Friday, 16 August 2013

Using Angular.js Factories to Get Remote Data

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:

{
  "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.

17 comments:

  1. 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?

    ReplyDelete
  2. I 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
  3. […] 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.  […]

    ReplyDelete
  4. Been 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?

    ReplyDelete
  5. but how will you handle errors?

    ReplyDelete
  6. Thank 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!

    ReplyDelete
  7. You'd have to do the promise shit I guess.. https://github.com/kriskowal/q#handling-errors

    Sometimes I just want to be able to do `q.prenuptial(cb)`

    Anyways, great article, thanks!

    ReplyDelete
  8. 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!

    The 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.

    ReplyDelete
  9. 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.

    http://sravi-kiran.blogspot.com/2013/03/MovingAjaxCallsToACustomServiceInAngularJS.html

    ReplyDelete
  10. David,

    I 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.

    ReplyDelete
  11. thanks...................

    ReplyDelete
  12. Hi 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/

    Next thing i wanted was to do a ajax request and load the multuple html section

    ReplyDelete
    Replies
    1. Solved
      http://stackoverflow.com/questions/22368267/single-controller-for-multiple-html-section-and-data-from-ajax-request-angularjs

      Delete

 
© doobries domain
Designed by BlogThietKe Cooperated with Duy Pham
Posts RSSComments RSS
Back to top