So far, we've used a hard coded three-cell phone record dataset. Now we use Angularjs a built-in service $http to get a larger set of mobile record data. We will use the Angularjs Dependency injection (Dependency injection (DI)) feature to provide this ANGULARJS service for the Phonelistctrl controller.
Please reset the working directory:
Git checkout-f step-5
To refresh your browser, you should now be able to see a list of 20 phones.
The most important differences between steps 4 and 5 are listed below. You can see the whole difference in the GitHub.
Data
The App/phones/phones.json file in your project is a dataset that stores a larger list of mobile phones in JSON format.
Here is a sample of this file:
[
{
' age ': '
id ': ' motorola-defy-with-motoblur ',
' name ': ' Motorola defy\u2122 with motoblur\u2122 ",
" snippet ":" Are you Ready for the everything life throws your? "
...
},
...
]
Controller
We use the ANGULARJS service $http in the controller to launch an HTTP request to your Web server to get the data from the App/phones/phones.json file. $http is just one of Angularjs's many built-in services that can handle common operations for some Web applications. Angularjs can inject these services into any place you need them.
Services are managed through the Angularjs dependency Injection di subsystem. Depending on the injection service, you can build your Web application well (such as separating the presentation layer, the data, and the control components) and loosely coupled (a part does not need to solve the dependencies between parts, all of which are handled by the DI subsystem).
App/js/controllers.js
function Phonelistctrl ($scope, $http) {
$http. Get (' Phones/phones.json '). Success (function (data) {
$ Scope.phones = data;
});
$scope. Orderprop = ' age ';
}
The $http initiates an HTTP GET request to the Web server and asks for Phone/phones.json (note that the URL is relative to our index.html file). The server responds with the data in the JSON file. (This response may be generated dynamically from back-end servers in real time.) But for browsers, they all look the same. For the sake of simplicity, we simply used a JSON file in the tutorial. )
The $http service returns with Success [Object Answer][ng. $q]. When the asynchronous response arrives, this object answering function is used to process the data of the server response, and the data is assigned to the phones data model of the scope. Note that the ANGULARJS will automatically detect this JSON response and it has been parsed for us!
In order to use the ANGULARJS service, you only need to declare the name of the service in the Controller's constructor as a parameter, just like this:
function Phonelistctrl ($scope, $http) {...}
When the controller is constructed, the ANGULARJS dependency injector injects these services into your controller. Of course, the dependency injector also handles any transitive dependencies that may exist for the required service (a service usually relies on other services).
Note that parameter names are important because the injector uses them to find the appropriate dependencies.
' $ ' prefix naming convention
You can create your own service, actually we will learn it in step 11. As a naming convention, ANGULARJS built-in services, scoping methods, and some other Angularjs APIs use a ' $ ' prefix in front of the name. Do not use the ' $ ' prefix to name your own service and model, or you may have a name conflict.
About JS Compression
Because Angularjs infers the dependent service name through the parameter name of the controller constructor. So if you want to compress the Phonelistctrl controller's JS code, all of its parameters will also be compressed, then rely on the injection system can not correctly identify the service.
To overcome the problem of compression, just assign a $inject attribute to an array of service identifiers in the controller function as if the last line was commented out:
Phonelistctrl $inject = [' $scope ', ' $http '];
Another method can also be used to specify a list of dependencies and to avoid compression problems--constructing a controller using JavaScript arrays: Putting the service to be injected into a string array (representing the name of the dependency), the last element of the array is the Controller's method function:
var Phonelistctrl = [' $scope ', ' $http ', function ($scope, $http) {*/* constructor body */}];
The two methods mentioned above can work perfectly with any function that ANGULARJS can inject, which depends entirely on the programming style of your project and suggests an array approach.
Test
Test/unit/controllerspec.js:
Since we are now starting to use dependency injection, and our controllers also contain many dependent services, it is a little more complicated to construct tests for our controllers. We need to use the new operation and provide the constructor with some pseudo implementations including $http. However, the approach we recommend (and, more simply, OH) is to create a controller in a test environment, using the same methods and Angularjs as the product code does in the following scenario:
Describe (' phonecat controllers ', function () {
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});
});
Note: Because we loaded jasmine and angular-mock.js in the test environment, we have two helper methods, module and inject, to help us get and configure the injector.
In the following way, we create a controller in a test environment:
We use the inject method to inject $rootscope, $controller and $httpbackend service instances into Jasmine Beforeeach functions. These instances come from an injector, but the injector is recreated within each test. This ensures that each test starts at a well-known starting point, and that each test is independent of the other tests.
Call $rootscope. $new () to create a new scope for our controller.
The Phonelistctrl function and the scope you just created are passed as arguments to the injected $controller function.
Since our current code uses the $http service in the controller to get the phone list data before creating the Phonelistctrl, we need to tell the test suite to wait for a request from the controller. We can do this:
Inject the request service $httpbackend into our Beforeeach function. This is a pseudo version of this service, which helps to handle all XHR and JSONP requests in the product environment. The pseudo version of the service allows you to write tests without having to think about the native API and the global state, which can be a nightmare for testing.
Use the $httpbackend.expectget method to tell the $httpbackend service to wait for an HTTP request and tell it how to respond to it. Notice that the response is not emitted until we call the $httpbackend.flush method.
Right now
It (' should create ' phones ' model with 2 phones fetched from xhr ', function () {
expect (scope.phones). tobeundefined (); c2/> $httpBackend. Flush ();
Expect (Scope.phones). toequal ([{name: ' Nexus S '},
{name: ' Motorola DROID '}];
});
In the browser, we call $httpbackend.flush () to empty the (flush) request queue. This will allow the $http service to return promise (see here for promise) to be interpreted as a canonical answer.
We set up some assertions to verify that the mobile data model is already in scope.
Finally, we verify that the default values for Orderprop are set correctly:
It (' should set the default value of Orderprop model ', function () {
expect (Scope.orderprop). Tobe (' age ');
});
;
Practice
Add a {{phones | json}} binding at the end of Index.html to watch the list of mobile phones in JSON format.
In the Phonelistctrl controller, the HTTP response is preprocessed so that only the top five of the phone list is displayed. The following code is used inside the $http callback function:
$scope. Phones = Data.splice (0, 5);
Summarize
Now you should feel how easy it is to use ANGULARJS services (thanks to the dependency injection mechanism of the ANGULARJS service), go to step 6, and you'll add thumbnails and links to your phone.
Thank you for your support for this site, follow-up continue to update related articles!