Inside an AngularJS controller I do a $http.post() request and update $scope with new data which works fine.
But in case of an error, I want to change the template of the same controller to another one. I haven't figured out how to change the template of a controller.
Here is some pseudo code inside the controller:
// this is the controller
var self = this
$http
.post('/something', $scope.something)
.success(function(data) {
$scope.result = data
})
.error(function(err) {
$scope.error = err
var statusCode = err.statusCode
// for example on a 403, I want the template 'errors/403.html' to
// be rendered
self.template = $templateCache.get('errors/' + statusCode + '.html')
})
Any ideas how this is possible? I do not want to put '/errors/403' to the routing because it is not idempotent.
Thanks for any suggestions. I am a bit desperate here ...
try like
$location.path('/login');
first of all you should setup the route provider and use then use $location service to change the URL.
configure route provider :
var app = angular.module("myApp", ["ngRoute"]);
app.config(function ($routeProvider) {
$routeProvider.when("/error", { controller: "", templateUrl: "/app/error.html" });
// setup some more routes here as above
$routeProvider.otherwise({ redirectTo: "/login" });
And in JS file -
var self = this
$http
.post('/something', $scope.something)
.success(function(data) {
$scope.result = data
})
.error(function(err) {
$scope.error = err
var statusCode = err.statusCode
// for example on a 403, I want the template 'errors/403.html' to
// be rendered
$location.path("/error");
})
Don't forget to add the angular-route.js file.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body data-ng-app="myApp">
<div data-ng-view=""></div>
<script src="Scripts/angular-route.js"></script>
</body>
</html>
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives'], function ($routeProvider, $locationProvider, $httpProvider) {
var interceptor = ['$rootScope', '$q', function (scope, $q) {
function success(response) {
return response;
}
function error(response) {
var status = response.status;
if (status == 401) {
window.location = "./index.html";
return;
}
// otherwise
return $q.reject(response);
}
return function (promise) {
return promise.then(success, error);
}
}];
$httpProvider.responseInterceptors.push(interceptor);
Related
Trying to retrieve using angular the json found at: "https://api.github.com/users/angular", more precisely the id property from that json.
Any thoughts on why this fails (in debug mode I get a
'response is not defined'
):
<html ng-app="myViewer">
<head>
<script data-require="angular.js#*" data-semver="1.2.25" src="https://code.angularjs.org/1.2.25/angular.js"></script>
</head>
<body ng-controller="MyController">
{{ result.id }}
{{ err }}
</body>
<script type="text/javascript">
(function() {
var app = angular.module("myViewer", []);
var MyController = function($scope, $http)
{
$http.get("https://api.github.com/users/angular")
.then(function1, onerr);
var function1 = function(response)
{
$scope.result = response.data;
}
var onerr = function(reason)
{
$scope.err = "nightmare";
}
}
app.controller("MyController", ["$scope", "$http", MyController]);
}());
</script>
</html>
I expect the result to be the id that you can see by copying that link in your browser.
Here is a working fiddler https://jsfiddle.net/paka2/8roj37q9/1/
angular.module("myViewer", []).controller("myCtrl", function($scope,$http){
this.result = {};
this.err ;
$http.get("https://api.github.com/users/angular")
.then(function1, onerr) ;
function function1 (response)
{
$scope.result = response.data;
}
function onerr (reason)
{
$scope.err = "nightmare";
}
});
Hope it helps!!
Works if I correct the order:
var function1 = function(response)
{
$scope.result = response.data;
}
var onerr = function(reason)
{
$scope.err = "nightmare";
}
$http.get("https://api.github.com/users/angular")
.then(function1, onerr);
function1 should be defined before i call it with then.
I think your promise is wrong.
$http.get('https://api.github.com/users/angular').then(function(response){
$scope.result = response.data;
})
See same HTTP call working below:
https://plnkr.co/edit/8JqZ5NukHnHWGPxZ0GRr
try this i think you have incorrectly defined the controller as mycontroller and it should be SecondController instead.
app.controller("MyController", ["$scope", "$http", SecondController ]);
Try with following
var function1 = function(response) { $scope.result = response; }
I am implementing logic through ui-router, Factory and Directive but getting error: JavaScript runtime error: [$injector:modulerr] in Angular Js.
Ui-Routing was working fine.
Index.html file:
<html><head><title>Employee Management System</title>
<link href="Content/bootstrap.css" rel="stylesheet" />
<script src="Scripts/jquery-1.9.1.min.js"></script>
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/angular-ui-router.min.js"></script>
<script src="Scripts/bootstrap.min.js"></script>
<script src="Scripts/app/EmpRecord.js"></script>
<script src="Scripts/app/GetDataService.js"></script>
<script src="Scripts/app/EmpController.js"></script>
<script src="Scripts/app/EmpApp.js"></script></head>
<body ng-app="EmpApp">
<div class="page-header">Employee Management System
</div><div ng-include="'pageContents/menu.html'"></div>
<ui-view></ui-view></body></html>
EmpApp.js
var app = angular.module("EmpApp", ['ui.router']);
app.factory('EmpFact', ['$http', EmpFact])
.controller('EmpController', ['$scope', 'EmpFact',EmpController])
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
templateUrl: '/home.html'
})
.state('Add', {
templateUrl: '/AddEmployee.html'
})
.state('List', {
templateUrl: 'ListEmp.html',
controller: 'EmpController'
}
)
})
.directive('emp-Record', EmpRecord);
ListEmp.html:
<div><div><h3>List of Employees</h3></div>
<div EmpRecord ng-repeat="e in Employees"></div></div>
EmpController
<div><div><h3>List of Employees</h3></div>
<div EmpRecord ng-repeat="e in Employees"></div></div>
GetDataService.js
var EmpFact = function ($http) {
var records = {}
$http.get('http://localhost/EmployeeApi/api/Emp')
.then(function (response) {
records= response.data;
});
return {
GetData: function () {
alert(records);
return records;
}
}
}
All Errors are gone Now but data is not coming.
In short:
Controller:
var EmpController= function ($scope,EmpFact) {
$scope.Employees = EmpFact.GetData();
console.log($scope.Employees);
};
Service:
var EmpFact = function ($http) {
var records = {}
$http.get('http://localhost/EmployeeApi/api/Emp')
.then(function (response) {
records= response.data;
});
return {
GetData: function () {
alert(records);
return records;
}}}
Àpp.js
app.factory('EmpFact', ['$http', EmpFact])
.controller('EmpController', ['$scope','EmpFact', EmpController])
.directive('empRecord', function () {
return {
template: "<tr><td>{{e.empid}}</td><td>{{e.empName}}</td><td>{{e.empEmail}}</td><td>{{e.empSalary}}</td>"
}});
HTML:
<div>
<div><h3>List of Employees</h3></div>
<div emp-Record ng-repeat="e in Employees"></div>
</div>
Ok, so as I suggested in the comment, because the error implies that you haven't injected the EmpFact factory into EmpController, changing
.controller('EmpController', ['$scope', EmpController])
Into:
.controller('EmpController', ['$scope', 'EmpFact', EmpController])
And also injecting it to the controller function:
var EmpController = function ($scope, EmpFact) { ... };
Made the error disappeared, but now you say that "data is not coming".
I suggest another change in your factory, instead of your current code, try this:
var EmpFact = function ($http) {
return {
GetData: function () {
// return a promise which resolve with the actual data returned from the server
return $http.get('http://localhost/EmployeeApi/api/Emp').then(
function (response) {
// return the actual results, instead of the whole response from the server
return response.data;
}
);
}
}
};
Now, in your controller, you should be able to get the data like this:
var EmpController = function ($scope, EmpFact) {
// Call the "GetData" from the factory, which return a promise with the actual results returned from the server
EmpFact.GetData().then(
function(data) {
// in the resolve callback function, save the results data in
// any $scope property (I used "$scope.Employees" so it will be
// available in the view via {{ Employees | json }})
$scope.Employees = data;
}
);
};
By returning a promise you are guaranteed to be able to handle the results returned from an asynchronous request (AJAX). You should be able to use the results in the view like this:
<div emp-Record ng-repeat="e in Employees"></div>
(Note that the above HTML snippet is taken from the comments below this answer)
Edit:
Looking at your directive, it doesn't look like a correct way to construct a table. Change emp-Record to emp-record and wrap it in a <table> tag to make it a valid HTML:
<table>
<tr emp-record ng-repeat="e in Employees"></tr>
</table>
And in your directive's template make sure you close the row tag (Add </tr>):
.directive('empRecord', function () {
return {
template: "<tr><td>{{e.empid}}</td><td>{{e.empName}}</td><td>{{e.empEmail}}</td><td>{{e.empSalary}}</td></tr>"
}
});
Thanks Alon for your help as I am new to Angular, converting my ASP.NET MVC code to HTML5/Angular only.
Finally I am able to resolve it.
Data Service/Factory:
var EmpFact = function ($http) {
return {
GetData: function () {
return $http.get('http://localhost/EmployeeApi/api/Emp');
}
}
}
Controller:
var EmpController = function ($scope, EmpFact) {
//EmpFact.GetData() is a promise.
EmpFact.GetData().then(
function (result) {
$scope.Employees= result.data;
}
);
}
I wanna use multiple ( in this case, 2 ) $http.gets in my service !
As you know the simple form of using $http.get is this :
app.factory('MyService', function ($http, $q) {
return {
getData: function() {
return $http.get('myfile.json')
.then(function(response) {
return response.data;
});
}
};
});
Now I wanna use 2 files ( 2 $http.gets ) and compare them to each other ( with some for loops and etc that I can ... ) !
What can I do now ? :(
use $q.all.
Add $q to controller's dependencies, exemple
$scope.req1 = $http.get('myfile.json');
$scope.req2 = $http.get('myfile2.json');
$q.all([$scope.req1, $scope.req2]).then(function(data) {
// data is array of your files
if ( JSON.stringify(data[0]) === JSON.stringify(data[1])){
console.log('is equal');
}
});
It is an extension of Hajji Tarik's solution. I was able to derive from your comments that you were still not clear with what to code in where. So I have developed a sample application which will assist you for the same.
//--app.module.js--//
angular.module('notesApp', []);
//--app.service.js--//
angular.module('notesApp')
.factory('notesFactory', ['$http',
function($http) {
var notesService = {};
notesService.getData = function(url, method) {
return $http({
url: url,
method: method
});
}
return notesService;
}
]);
//--app.controller.js--//
angular.module('notesApp')
.controller('MainController', ['$scope', '$http', '$log', '$q', 'notesFactory',
function($scope, $http, $log, $q, notesFactory) {
$scope.data = {};
var data1 = notesFactory.getData('http://localhost:3000/api/notes/1', 'GET');
var data2 = notesFactory.getData('http://localhost:3000/api/notes/2', 'GET');
var combinedData = $q.all({
firstResponse: data1,
secondResponse: data2
});
combinedData.then(function(response) {
$log.log(response.firstResponse.data);
$log.log(response.secondResponse.data);
//Write your comparison code here for comparing json results.
}, function(error) {
$scope.data = error;
});
}
]);
<html ng-app='notesApp'>
<head>
<title>
Notes Application
</title>
</head>
<body>
<div ng-controller='MainController'>
</div>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js'></script>
<script src='app.module.js'></script>
<script src='app.controller.js'></script>
<script src='app.service.js'></script>
</body>
</html>
I have created a simple app to store an event to my database. It is working fine but with a wordaround.
I use the following method:
controllers.controller('CalendarAddController', function($scope, $routeParams, Event) {
$scope.addEvent = function() {
$scope.ev=new Event();
$scope.ev.title = $scope.event.title;
$scope.ev.$save().then(function(res) { console.log("success");})
.catch(function(req) { console.log("error saving obj"); })
.finally(function() { console.log("always called") });
}
});
After submitting my form, the function addEvent is called.
If I print the value of $scope.event, it has the right values.
However, when I call .$save() on it, I get the error "TypeError: $scope.event.$save is not a function."
But when I create a new object and assign the values to it, it works fine.
Why isn't it working directly? Always creating a dummy object does not seem to be best practice I suppose.
The service I created
services.factory( 'Resource', [ '$resource', function( $resource ) {
return function( url, params, methods ) {
var defaults = {
update: { method: 'put', isArray: false },
create: { method: 'post' }
};
methods = angular.extend( defaults, methods );
var resource = $resource( url, params, methods );
resource.prototype.$save = function() {
if ( !this.id ) {
return this.$create();
}
else {
return this.$update();
}
};
return resource;
};
}]);
services.factory( 'Event', [ 'Resource', function( $resource ) {
return $resource( '/api/calendar/:id' );
}]);
Update: basic example
Using this example everything works front-end but in my rest API the data is not passed.
<!DOCTYPE html>
<html lang="en-US">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-route.min.js"></script>
<script type="text/javascript">
var app = angular.module('app', ['ngRoute','ngResource'])
.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'pages/home.html',
controller : 'mainController'
})
});
app.factory('Event', function($resource) {
return $resource('/test/api/:id');
});
app.controller('mainController', ['$scope', '$routeParams', 'Event',
function($scope, $routeParams, Event) {
function handleSuccess(data) {
alert("success");
}
function handleError(data) {
alert("error");
}
var event = new Event();
event.title = "a title";
Event.save(event, handleSuccess, handleError);
}]);
</script>
<body>
<div ng-app="app">
<div ng-view></div>
</div>
</body>
</html>
For the back-end I created a very basic script which writes the request to a file:
It always says "array()" so no data is passed.
<?php
$myFile = "testFile.txt";
$fh = fopen($myFile, 'w') or die("can't open file");
$stringData = print_r($_REQUEST,true);
fwrite($fh, $stringData);
fclose($fh);
?>
Where do you initialize $scope.event or is it automatically created by angular? If this is an plain JavaScript object you can't call .$save, but you can use the Event service itself - no need to create a new instance:
Event.create($scope.event)
I am building a service in angular and injecting the service in controller. I am trying to fetch data from json file and am using $http. however the data is not getting returned and i get undefined.
I am updating my code as per suggestion by #Phil
Service.js
;(function(app) {
app.factory('authService', ['$log', '$http','$location', function($log, $http,$location) {
var url = 'js/user.json';
var authService= {};
var userExist=null;
authService.authenticate = function(userid) {
var userobj = $http.get(url).success(function (data) {
userExist = data
console.log(data);
return userExist;
$log.info("Loaded users");
})
.error(function (error) {
$log.info(error);
$log.info("No user exists");
return error;
})
return userobj;
}
return authService;
}]);
})(angular.module('userApp'));
Controller.js
;(function(app) {
app.controller('Controller', ['$scope', '$log','$location','authService', function($scope,$log,$location,authService) {
$scope.data={};
$scope.getUsers = function()
{
userid = "123";
$scope.data = authService.authenticate(userid);
console.log($scope.data);
return $scope.data ;
}
}])
}(angular.module('userApp')));
index.html
<div class="main" ng-controller="Controller">
<input type="button" name="btngetusers" ng-click="getUsers()"></input>
</div>
<script src ="js/app.js"> </script>
<script src ="js/controller/Controller.js"> </script>
<script src ="js/services/Service.js"> </script>
user.json
i have placed the json file under the js directory.
[
{
"UserId": "1",
"FName": "Hice",
"LastName": "Harry"
},
{
"UserId": "2",
"FName": "Andrew",
"LastName": "Ads"
}
]
The data is getting returned as undefined. what am i missing here?
UPDATED CODE
I am updating my code as per suggestion by #skubsi
Service.js
;(function(app) {
app.factory('authService', ['$log', '$http','$location', function($log, $http,$location) {
var url = 'js/user.json';
var authService = {};
var userExist=null;
authService.authenticate = function(userid,success,error) {
$http.get(url).success(function(data){
success(data);
})
.error(error);
};
return authService;
}]);
})(angular.module('userApp'));
Controller.js
;(function(app) {
app.controller('MainController', ['$scope', '$log','$location','authService', function($scope,$log,$location,authService) {
var self = this;
this.data = null;
this.getUsers = function(){
function success(response){
self.data = response;
}
function error(){
console.log("error");
}
authService.authenticate(1,success,error);
}
}])
}(angular.module('userApp')));
index.html
<div class="main" ng-controller="MainController as main">
{{main.data}}
<input type="button" name="btngetusers" value ="Get User" ng-click="main.getUsers()"></input>
</div>
<script src ="js/app.js"> </script>
<script src ="js/controller/MainController.js"> </script>
<script src ="js/services/authenticate.js"> </script>
First things first: your JSON is invalid, you can verify this yourself by entering the JSON you supplied in JSONLint.
Parse error on line 2:
[ { UserId: 123,
--------------^
Expecting 'STRING', '}'
Secondly you pass a unknown service into your controller:
authenService
Then you should realize a promise is code that will run asynchronously, meaning that:
userid = "123";
$scope.data = authService.authenticate(userid);
console.log($scope.data);
return $scope.data ;
will not run synchronously. console.log($scope.data); Will be executed long before your authenticate method will be done. So you need to find a way to make your controller handle accordingly whilst keeping concerns separated. (and not falling into a deferred-anti-pattern).
You could for example add additional parameters to your authenticate function, which will enable the function to call back the original caller.
authService.authenticate = function(userid, success, error) { //success and error are functions
$http.get(url).success(function(data) {
//separation of concerns:
//execute logic.. set flags, filter w/e belongs to your authentication process.
success(data);
})
.error(error); //no processing required
};
So that in your controller all that is left to do is calling the authService and providing it a way to set your data:
this.getUsers = function() {
//This will enable to set the response to your controllers data model.
function success(response) {
self.data = response;
window.alert(response);
}
function error() {
window.alert('shite happened');
}
authService.authenticate(1, success, error);
};
Note that I have used the controllerAs syntax instead of $scope. To prove this mechanism works I created a plunker for you to investigate.
Your authenticationService.authenticate method doesn't return anything.
Specifically, the service name is authService and you're calling authenticationService.authenticate.