The aim of this section is to discuss two services AngularJS provides for integrating with a server, namely $http
and $resource
. We’ll look at $http
first and$resource
second. $resource
is essentially a RESTful extension of $http
.
Previously we introduced a feature to our blog admin application that calculated the percentage of used categories. We originally used this feature to look at how we can create our own injectable components. We’ll now use it again to discuss$http
.
$http
The requirements for our blog admin application have changed, and we now need to fetch the categories from a server.
The simplest way to achieve this is to use $http
directly in articleCtrl
.
The contents of articleCtrl
became quite lengthy in the previous section, so the following two snippets are intended to be illustrative.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
angular.module('tutsocean').controller('articleCtrl', function($scope, $http, calculateCategoryPercentage) { $scope.articles = [ { title: "HTML Tutorial", categories: ['tutorial', 'hardware'] }, { title: "CSS Tutorial", categories: ['tutorial', 'graphics'] }, { title: "jQuery Tutorial", categories: ['tutorial'] } ]; $scope.categoryPercentage = 0; $http.get('/categories').then(function(response) { $scope.categoryPercentage = calculateCategoryPercentage($scope.articles, response.data); }); }); |
In the above snippet, we issue an HTTP request to the URL ‘/categories’ and, if it is successful, we pass the response data to calculateCategoryPercentage
. There are two key things to note here.
First, there will be a delay while the server responds. During this delay, the $scope
property is not set and therefore a percentage is not displayed in the browser. We can lessen the impact of this by setting an initial value.
Second, we have returned calculateCategoryPercentage
to its simple value service version. But rather than hard-coding the available categories,calculateCategoryPercentage
is passed as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
angular.module('tutsocean') .value('calculateCategoryPercentage', function(articles, availableCategories) { var uniqueCategories = []; articles.forEach(function(article) { article.categories.forEach(function(category) { if (uniqueCategories.indexOf(category) == -1) { uniqueCategories.push(category); } }); }); return Math.floor(100 * (uniqueCategories.length / availableCategories.length)); }); |
$httpBackend
For the purposes of a tutorial, it is desirable to avoid introducing any tangential complexity. In our case, that would be a server to respond to the URL ‘/categories’.
AngularJS has a very useful additional module for backend-less development, namely $httpBackend
. This is perfect for tutorials, but I have also used it in a team of four AngularJS developers building an application against a partially built server. We didn’t want the road map of server features to impact us, so for a period of time, we developed backend-less.
Download angular-mocks.js and add another script reference in index.html
in the following order:
1 2 3 4 5 |
<script src="angular.js"></script> <script src="angular-mocks.js"></script> <script src="app.js"></script> <script src="controllers.js"></script> <script src="services.js"></script> |
There are two variants of $httpBackend
, one for unit testing and one for backend-less development. We need to tell our application to use the backend-less variant; this is achieved by adding a dependency to ngMockE2E
to our udemyAdmin
module. We then to configure how $httpBackend
should respond to URL and HTTP verb combinations. Currently we only need one combination, HTTP GET and ‘/categories’.
Edit app.js
as follows:
1 2 3 |
angular.module('tutsocean', ['ngMockE2E']).run(function($httpBackend) { $httpBackend.whenGET('/categories').respond(['tutorial', 'hardware', 'graphics']); }); |
In the above snippet, the run
method of our ‘udemyAdmin’ module is used for one-off configuration code that needs to execute as our application starts up.