In this step, we will improve the way our app gets the data.
Please reset the working directory:
Git checkout-f step-11
The last improvement to our application is to define a custom service that represents the restful client. With this client we can send XHR requests in a simpler way, without having to care about the lower-level $http services (APIs, HTTP methods, and URLs).
The most important differences between steps 9 and 10 are listed below. You can see the whole difference in the GitHub.
Template
Custom services are defined in app/js/services, so we need to introduce this file into the layout template. Also, we're going to load the Angularjs-resource.js file, which contains the Ngresource module and the $resource service, which we'll use in a minute:
App/index.html
...
<script src= "Js/services.js" ></script>
<script src= "Lib/angular/angular-resource.js" ></ Script> ...
Service
App/js/services.js
Angular.module (' phonecatservices ', [' Ngresource ']).
Factory (' Phone ', function ($resource) {return
$resource (' phones/:p Honeid.json ', {}, {
query: {method: ' Get '), Params:{phoneid: ' Phones '}, isarray:true}
});
We use the module API to register a custom service through a factory method. We have the name of the incoming service phone and factory function. Factory functions are similar to controller constructors, and they all declare dependent services through function arguments. The phone service declares that it relies on the $resource service.
$resource Service makes it possible to create a restful client with just a few lines of code. Our application uses this client to replace the underlying $http service.
App/js/app.js
...
Angular.module (' Phonecat ', [' phonecatfilters ', ' phonecatservices ']).
...
We need to add phonecatservices to the Phonecat array of dependencies.
Controller
By refactoring the underlying $http service and placing it in a new service phone, we can greatly simplify the sub controllers (Phonelistctrl and Phonedetailctrl). Angularjs $resource is more suitable for interacting with restful data sources than $http. And now it's easier to understand what the controller's code is doing.
App/js/controllers.js
...
function Phonelistctrl ($scope, Phone) {
$scope. Phones = Phone.query ();
$scope. Orderprop = ' age ';
}
Phonelistctrl $inject = [' $scope ', ' Phone '];
function Phonedetailctrl ($scope, $routeParams, phone) {
$scope. Phone = Phone.get ({phoneid: $routeParams. Phoneid}, function (phone) {
$scope. Mainimageurl = Phone.images[0];
});
$scope. setimage = function (IMAGEURL) {
$scope. mainimageurl = ImageUrl;
}
}
Phonedetailctrl $inject = [' $scope ', ' $routeParams ', ' Phone '];
Notice that in the Phonelistctrl we put:
$http. Get (' Phones/phones.json '). Success (function (data) {
$scope. phones = data;
});
Replaced by:
$scope. Phones = Phone.query ();
We use this simple statement to query all the phones.
Another very important note is that in the above code, the way to call the phone service is that we don't pass any callback functions. Although this seems to be the result of synchronous return, in fact it is not. What is returned synchronously is a "future"-an object that is populated with data when the XHR returns accordingly. Given the ANGULARJS data binding, we can use future and bind it to our template. Then, when the data arrives, our view is automatically updated.
Sometimes, relying solely on future objects and data binding is not enough to meet our needs, so in these cases we need to add a callback function to handle the server's response. The Phonedetailctrl controller is an explanation by setting the Mainimageurl in a callback function.
Test
Modify our unit tests to verify that our new service initiates HTTP requests and processes them as expected. The test also checks to see if our controller works properly with the service.
$resource Service enhances the response to objects by adding methods to update and delete resources. If we are going to use the toequal, our test will fail because the test value does not exactly equate to the response. To solve this problem, we need to use a recently defined toequaldatajasmine matching device. When the Toequaldata match compares two objects, it takes into account only the attributes of the object and ignores all the methods.
Test/unit/controllersspec.js:
describe('PhoneCat controllers', function() {
beforeEach(function(){
this.addMatchers({
toEqualData: function(expected) {
return angular.equals(this.actual, expected);
}
});
});
beforeEach(module('phonecatServices'));
describe('PhoneListCtrl', function(){
var scope, ctrl, $httpBackend;
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('phones/phones.json').
respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
scope = $rootScope.$new();
ctrl = $controller(PhoneListCtrl, {$scope: scope});
}));
it('should create "phones" model with 2 phones fetched from xhr', function() {
expect(scope.phones).toEqual([]);
$httpBackend.flush();
expect(scope.phones).toEqualData(
[{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
});
it('should set the default value of orderProp model', function() {
expect(scope.orderProp).toBe('age');
});
});
describe('PhoneDetailCtrl', function(){
var scope, $httpBackend, ctrl,
xyzPhoneData = function() {
return {
name: 'phone xyz',
images: ['image/url1.png', 'image/url2.png']
}
};
beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData());
$routeParams.phoneId = 'xyz';
scope = $rootScope.$new();
ctrl = $controller(PhoneDetailCtrl, {$scope: scope});
}));
it('should fetch phone detail', function() {
expect(scope.phone).toEqualData({});
$httpBackend.flush();
expect(scope.phone).toEqualData(xyzPhoneData());
});
});
});
Summarize
Completed! You have created a Web application in a relatively short period of time. In the end we will mention what we should do next.
The above is Angularjs res and custom service information collation, follow-up continue to supplement the relevant information, hope to help you learn angularjs!