In this post, I’d like to show the differences between using an Angular.js factory to get local JSON data vs remote data via an AJAX call.
For this example, I’m assuming that we have a JSON dataset that describes different types of fruit, for example:
At it’s simplest, an Angular.js view to iterate over this data could look like the following HTML:
In the HTML view, we can see that an Angular.js controller called fruitsController is being used within a module called fruitsApp. We’re then using ng-repeat to iterate through a collection of fruit and add them into a simple HTML list.
If we wanted to get data locally rather than via HTTP, we could declare a controller and factory as follows:
To make a HTTP call via an Angular.js factory, we need to pass the $http object into the factory and then make a call to the remote HTTP request using the $http.get() method.
In this example, you can see that the controller makes a request to the factory which then calls an asynchronous function ($http.get) to get the data. When this asynchronous function completes successfully, it calls back to an anonymous function in the controller and populates the view model.
For this example, I’m assuming that we have a JSON dataset that describes different types of fruit, for example:
{
"fruits": [
{
"id": "1",
"name": "Apple"
},
{
"id": "2",
"name": "Orange"
}
]
}
At it’s simplest, an Angular.js view to iterate over this data could look like the following HTML:
<!doctype html>
<html lang="en" ng-app="fruitsApp">
<head>
<title>Angular Sample App</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="fruitsController">
<ul>
<li ng-repeat="fruit in fruits"></li>
</ul>
</div>
</body>
</html>
A Hardcoded Angular.js Controller and Factory
In the HTML view, we can see that an Angular.js controller called fruitsController is being used within a module called fruitsApp. We’re then using ng-repeat to iterate through a collection of fruit and add them into a simple HTML list.
If we wanted to get data locally rather than via HTTP, we could declare a controller and factory as follows:
var fruitsApp = angular.module('fruitsApp', [])
fruitsApp.factory('fruitsFactory', function() {
return {
getFruits: function() {
return [{"id": "1","name": "Apple"}, {"id": "2","name": "Orange"}];
},
};
});
fruitsApp.controller('fruitsController', function($scope, fruitsFactory) {
$scope.fruits = fruitsFactory.getFruits();
});
This is a very simple controller and factory. The fruitsController returns a view model which is populated from the fruitsFactory, which simply has a hardcoded static list of fruit.A Dynamic Angular.js Controller and Factory Using AJAX
The above exampe will work for getting data, but isn’t of much use for dynamically generated content. For dynamic content, we need to make an HTTP request to get our data, for example via a REST call.To make a HTTP call via an Angular.js factory, we need to pass the $http object into the factory and then make a call to the remote HTTP request using the $http.get() method.
var fruitsApp = angular.module('fruitsApp', [])
fruitsApp.factory('fruitsFactory', function($http) {
return {
getFruitsAsync: function(callback) {
$http.get('fruits.json').success(callback);
}
};
});
fruitsApp.controller('fruitsController', function($scope, fruitsFactory) {
fruitsFactory.getFruitsAsync(function(results) {
console.log('fruitsController async returned value');
$scope.fruits = results.fruits;
});
});
In this example, you can see that the controller makes a request to the factory which then calls an asynchronous function ($http.get) to get the data. When this asynchronous function completes successfully, it calls back to an anonymous function in the controller and populates the view model.
I notice getFruitsAsync takes a callback parameter. Would a "more Angular" way of doing it be to just return the result of the http.get call, which is a promise object, so the calling function can handle the callback, along with any error conditions?
ReplyDeleteI agree. If you are just binding the result to the $scope object, angular is smart enough to understand a promise and defer the promise then bind the data when it appears. So, instead of doing a callback, you can literally just return the promise itself and set it to the $scope, like this: $scope.fruits = fruitsFactory.getFruitsAsync() and then in the factory return $http.get('fruits.json');
ReplyDelete[…] In this post, I’d like to show the differences between using an Angular.js factory to get local JSON data vs remote data via an AJAX call. To make a HTTP call via an Angular.js factory, we need to pass the $http object into the factory and then make a call to the remote HTTP request using the $http.get() method. In this example, you can see that the controller makes a request to the factory which then calls an asynchronous function ($http.get) to get the data. When this asynchronous function completes successfully, it calls back to an anonymous function in the controller and populates the view model. […]
ReplyDeleteBeen looking for an article like this for awhile now. Glad I found it. I assume that this is the proper way to handle Reqeusts via AJAX. I know you are not suppose to use the controller for DOM manipulation and things of that nature but I suppose that making these Requests are okay to handle in the controllers via a Factory, Correct or No?
ReplyDeletebut how will you handle errors?
ReplyDeleteThank you so much for this post! I have been looking for a simple example like this for hours. All of the examples I've seen except this one don't work. So, thanks!
ReplyDeleteYou'd have to do the promise shit I guess.. https://github.com/kriskowal/q#handling-errors
ReplyDeleteSometimes I just want to be able to do `q.prenuptial(cb)`
Anyways, great article, thanks!
Thank you thank you thank you. I spent all day reading stackoverflow posts and trying to learn up on factories and services and yada yada yada. All I wanted was one useful example of how to make a factory around the $http service that I already had in my controller and help it all make sense!
ReplyDeleteThe key here, is that when defining your controller you changed the second argument which was $http (when there was no factory and the $http was used directly in the controllwer) into your factory instance fruitsFactory.
In terms of handling errors - have a look at this article - it's a working example of getting an error message from the factory into the controller.
ReplyDeletehttp://sravi-kiran.blogspot.com/2013/03/MovingAjaxCallsToACustomServiceInAngularJS.html
David,
ReplyDeleteI seriously just started looking into angular, I haven't even finished the phones tutorial. But looking into angular two days ago and finding this post today was perfect timing. So thanks.
hi............
ReplyDeletethanks...................
ReplyDeletethanks.....
ReplyDeletethanks
ReplyDelete.............
ReplyDeleteHi Thanks for the sample, i was trying to use one controller for multiple html section and was working successfully , here is the demo http://jsfiddle.net/tomalex0/z6fEf/4/
ReplyDeleteNext thing i wanted was to do a ajax request and load the multuple html section
Solved
Deletehttp://stackoverflow.com/questions/22368267/single-controller-for-multiple-html-section-and-data-from-ajax-request-angularjs