I am using AngularJs 1.5 RC build.
I have a view wherein I am using ng-repeat to iterate over a collection , like so
<tr ng-repeat="user in users">
<td>{{user.JobID}}</td>
<td>{{getManager(user.userID)}}</td>
<td>{{user.StatusDesc}}</td>
<td>{{user.StartedAt}}</td>
</tr>
The idea here is to use the getManager function to get the name of the manager for each and every user in the users collection.
As an aside , I have to use this approach since the API is not returning me all the information.
This is how the getManager function looks like now.
$scope.getManager = function($id) {
return "John Doe";
}
The entire controller looks as follows
var app = angular.module('userapp', ['ui.bootstrap']);
app.controller('MainController', ['$scope','$http', function($scope, $http) {
$scope.getUsers = function() {
$http.get("http://localhost/getUsers").
success(function(data, status, headers, config) {
$scope.users = data.resource;
}).
error(function(data, status, headers, config) {
// log error
console.error("An error as encountered. Error follows:");
console.error(data);
});
}
$scope.getManager= function($id) {
return "John Doe";
}
}]);
So in my page view, I am getting "John Doe" as a manager for all my users.
Problem
The problem begins whenever I try to get the real manager for a user. So if i replace my dummy getManager with the following function
$scope.getManager = function($id) {
$http.get("http://localhost/user/manager/"+$id).
success(function(data, status, headers, config) {
return (data.resource[0].ManagerName);
}).
error(function(data, status, headers, config) {
// log error
console.error("An error as encountered. Error follows:");
console.error(data);
});
}
AngularJs starts complaining and fails with the following
https://docs.angularjs.org/error/$rootScope/infdig?p0=10&p1=%5B%5D
Can you please let me know what might be happening here.
Please note , I am an Angular noob, hence your patience will be well appreciated.
Thanks
You should call ajax in that way inside {{}} interpolation. It will get called on each digest cycle and will throw $rootScope/infdig error.
So I'd suggest you to call the getManager method as soon as you retrieve a data from server. Then after getting data from a server you need to call getManager method just by passing UserId(look I change getManager implementation to return managerName by returning data). After getting managerName you need to bind that manager name to user object & use {{user.ManagerName}} on the HTML.
Markup
<tr ng-repeat="user in users">
<td>{{user.JobID}}</td>
<td>{{user.managerName}}</td>
<td>{{user.StatusDesc}}</td>
<td>{{user.StartedAt}}</td>
</tr>
Code
$scope.getUsers = function() {
$http.get("http://localhost/getUsers")
.success(function(data, status, headers, config) {
$scope.users = data.resource;
angular.forEach($scope.users, function(user){
(function(u){
$scope.getManager(u.UserID).then(function(name){
u.ManagerName = data;
})
})(user);
})
})
};
$scope.getManager = function($id) {
return $http.get("http://localhost/user/manager/"+$id).
then(function(response) {
var data = response.data;
return (data.resource[0].ManagerName);
},function(error) {
console.error("An error as encountered. Error follows:");
});
};
Side Note
Don't use .success & .error function on $http calls as they are
deprecated.
This is a really bad practice. If you have N users, you will send N queries to fetch every data. You should return this data in http://localhost/getUsers response.
You can try:
$scope.getManager = function($id) {
return $http.get("http://localhost/user/manager/"+$id)
...
}
Related
My $http functions can return the following errors:
POST http://foobar.dev/foobar 500 (Internal Server Error)
POST http://foobar.dev/foobar 401 (Unauthorized)
Isn't there a way I can catch all status codes?
$http.post('/foobar', form)
.success(function(data, status, headers, config) {
console.info(data);
})
.error(function(data, status, headers, config) {
console.error(data);
if(status === 401) {
$scope.setTemplate('show-login');
}
if(status === 500) {
$scope.setTemplate('server-error');
}
}
);
Where $scope.setTemplate() is a function inside the Controller that sets a view.
But then I have to do this for each error() function and there are a lot functions like this which also not making it DRY code :P
What I want is to catch the error and do an action based on the status code returned in the error.
FYI: I'm not using Angulars $routeProvider().
You can use the Angular $http interceptor for this like #Dalorzo explained:
var myApp = angular.module("myApp", [], ['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$rootScope', '$q', function($rootScope, $q) {
return {
'responseError': function(response) {
var status = response.status;
// Skip for response with code 422 (as asked in the comment)
if (status != 422) {
var routes = {'401': 'show-login', '500': 'server-error'};
$rootScope.$broadcast("ajaxError", {template: routes[status]});
}
return $q.reject(response);
}
};
}]);
});
Then receive it in your controller:
$scope.$on("ajaxError", function(e, data) {
$scope.setTemplate(data.template);
});
Now, you don't have to put in your each error function.
How about something like this instead:
var routes = {'401':'show-login', '500': 'server-error'};
$scope.setTemplate(routes[status]);
Where routes is a dictionary with your error codes and desired routing.
This is exactly what $http interceptors are for. See the interceptors section here: $http
Basically, you create common functionality for all $http requests, in which you can handle different statuses. For example:
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2){
return {
response: function(response){
// do something for particular error codes
if(response.status === 500){
// do what you want here
}
return response;
}
};
});
// add the interceptor to the stack
$httpProvider.interceptors.push('myHttpInterceptor');
What I would say initially is to create a decorator for the $http service or create a service that would serve as a wrapper for the $http service.
Here is my controller and service:
var app = angular.module('myApp', ['ui.bootstrap']);
app.service("BrandService", ['$http', function($http){
this.reloadlist = function(){
var list;
$http.get('/admin.brands/getJSONDataOfSearch').
success(function(data, status, headers, config) {
list = data;
}).
error(function(data, status, headers, config) {
});
return list;
};
}]);
app.controller('BrandsCtrl', ['$scope','$http','$controller','BrandService', function($scope, $http, $controller, BrandService) {
$scope.brands = BrandService.reloadlist();
angular.extend(this, $controller("BrandCtrl", {$scope: $scope}));
}]);
I searched for this issue and tried answers of questions but I couldn't get solution. I am new at angular so can you explain with details; why I couldn't get the data from service to controller this way ?
The return used for data is for the callback of your function.
You must use the promise returned by $http like this.
In your service return the promise :
return $http.get('/admin.brands/getJSONDataOfSearch').
success(function(data, status, headers, config) {
return data;
}).
error(function(data, status, headers, config) {
});
Use then() on the promise in your controller :
BrandService.reloadlist()
.then(function (data){
$scope.brands = data;
});
It's not angular, it's the Javascript. The function you put in this.reloadlist does not return any value. It has no return at all, so the value returned will be undefined. The success handler does return something, but it will be run long after reloadlist finished working.
Besides what #fdreger already pointed out (missing return value), $http.get(...) is an async method. The return value is a promise not the actual value.
In order to access the value you need to return it from reloadlist like this:
this.reloadList = function() {
return $http.get('/admin.brands/getJSONDataOfSearch');
// you need to handle the promise in here. You could add a error handling here later by catching stuff...
}
and in the controller you can add it to the $scope like this:
BrandService
.reloadlist()
.then(function(res) {
$scope.brands = res.data;
});
The callback passed to then() is called as soon as the HTTP request has successfully completed, this makes the call asynchronous.
Besides the angular documentation for promises the article on MDN is a good read too.
I'm an angular noob and am really frustrated with a particular problem.
I have a $resource returning data from the server, which contains key/value pairs i.e. detail.name, detail.email etc.
I can access this information on the view using {{detail.name}} notation, but I cannot access it in the code, which is driving me nuts, as I need this data to do stuff with.
How can I access it in the backend?
here's the code generating the data:
mydata = Appointment.get({id: $stateParams.id}, function(data){
geocoder.geocode(data);
$scope.detail = data;
});
on the view I have the following:
<address class="text-left">
{{detail.address_1}}</br>
{{detail.city}}</br>
{{detail.postcode}}</br>
</address>
</hr>
<p> {{detail.lat}}</p>
<p> {{detail.lng}}</p>
<p> {{center}}</p>
this is all ok.
however, if I add console.log($scope.detail.lat) in the $resource callback i get undefined.
Here is the resource definition:
angular.module('MyApp')
.factory('Appointment', function($resource){
return $resource('/api/admin/:id', { id: "#_id" }, {
query: {method:'GET', isArray:true},
update: { method:'PUT' }
});
})
and the geocoder factory if anyone is interested:
angular.module('MyApp')
.factory('geocoder', ['$http','$state', function($http, $state){
var geocoder ={};
geocoder.geocode = function (formData){
var myformData = {};
var address = formData.address_1+', '+formData.city+', '+formData.postcode;
var key = 'AIzaSyACVwB4i_6ujTrdjTMI-_tnsDrf6yOfssw';
$http.get('https://maps.googleapis.com/maps/api/geocode/json?address='+address+'&key='+key).
success(function(results, status, headers, config) {
var results = results.results[0];
formData.lat = results.geometry.location.lat;
formData.lng = results.geometry.location.lng;
myformData = formData;
return myformData;
// this callback will be called asynchronously
// when the response is available
}).
error(function(results, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
return geocoder;
}])
Can anyone help?
You could do utilize the promise return from the $resource object & then utilize that promise in controller.
Factory
angular.module('MyApp')
.factory('Appointment', function($resource){
return $resource('/api/admin/:id', { id: "#_id" }, {
query: {method:'GET', isArray:true},
update: { method:'PUT' }
});
})
Controller
mydata = Appointment.get({id: $stateParams.id}).$promise;
mydata.then(function(data){
geocoder.geocode(data);
$scope.detail = data;
});
I just started with learning Angular and now i'm busy with an web application that shows some records i fetched from a JSON. The JSON looks like:
"results": [
{
"easy": false,
"id": 1,
"title": "title",
}
]
i am parsing that on this way (seems correct to me)
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.thing = data.results;
});
});
So now that i am in this JSON file i need to get the ID (in this case its 1) and with that ID i need to do a new request api.com/game/{id} to get more detailed information about the result from the first file.
What is the best way to do that?
$http.get('api.com/game/' + $scope.thing.id, function(...){ });
Point to note, you do not have to manually parse JSON with angular. It will do that for you. So data.results already has the object representing your response.
i think it is good idea if you do like this:
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.thing = data.results;
$scope.id=data.results[0].id;
gameInfo();
});
});
var gameInfo=function(){
$http.get('api.com/game/'+$scope.id).
success(function(data, status, headers, config) {
$scope.newThing = data;
});
}
Also take a look at ngResource which is a module that gives you more fine-grained control over HTTP requests. It does parameter replacement among other things (custom interceptors, etc.)
https://docs.angularjs.org/api/ngResource/service/$resource
I have an AngularJS controller that makes an HTTP get request to an API. The API can either return a res.json(true) or a res.json(false) value based on some condition.
However, the controller seems to be ignoring this and I'm just curious to see how someone else would implement this:
function MyCtrl($scope, $http) {
$http.get('/api/call').
success(function(data, status, headers, config) {
console.log(data); // --> this prints out false
if (data) { // --> this evaluates and I'd expect this to fail, however
console.log("true"); --> this also shown
}
});
Should I modify my response from the api that it returns something else other than res.json(false)?
Should I modify the code above to say something like if (data === false)?
res.json(true) // not JSON
res.json({ status: true }) // JSON