It’s time to give these web pages some dynamic features - use AngularJS! We have added a test here for the controller that will be added later.
There are many types of code structures for an application. For AngularJS applications, we encourage the use of the Model-View-Controller (MVC) pattern to decouple code and separate concerns. With this in mind, we use AngularJS to add some models, views, and controllers to our application.
Please reset the working directory:
Our app now has a list of three phones.
The most important differences between step 1 and step 2 are listed below. You can go to GitHub to see the complete differences.
Views and Templates
In AngularJS, a view is a mapping of a model rendered through an HTML template. This means that whenever the model changes, AngularJS will update the join point in real time and update the view accordingly.
For example, view components are built by AngularJS using the following template:
We just replaced the statically encoded phone list, because here we use the ngRepeat directive and two AngularJS expressions wrapped in curly braces - {{phone.name}} and {{phone.snippet}} ——can achieve the same effect.
1. The ng-repeat="phone in phones" statement in the
2. As we learned in step 0, the curly braces surrounding phone.name and phone.snippet identify data binding. Different from constant calculation, the expression here is actually a data model reference of our application, which we have set in the PhoneListCtrl controller.
Models and Controllers
The data model is initialized in the PhoneListCtrl controller (this is just a function containing an array, and the object stored in the array is the mobile phone data list):
app/js/controller.js:
Although the controller does not seem to play a controlling role, it plays a vital role here. Controllers allow us to establish data bindings between models and views by giving them the context of our data model. This is how we connect the presentation layer, data and logical components:
1.PhoneListCtrl - The name of the controller method (in the JS file controllers.js) matches the value of the ngController directive in the
tag.2. The phone’s data is now associated with the scope ($scope) injected into our controller function. When the application starts, a root scope is created, and the controller scope is a typical successor of the root scope. The scope of this controller is valid for all data bindings inside the
tag.The scope theory of AngularJS is very important: a scope can be regarded as a gluer for templates, models and controllers to work together. AngularJS uses scopes, along with information in templates, data models and controllers. These can help separate the model and view, but the two are really in sync! Any changes to the model are immediately reflected in the view; any changes to the view are immediately reflected in the model.
For a more in-depth understanding of AngularJS scope, please refer to the AngularJS Scope Document.
Test
The "AngularJS way" makes code testing during development very simple. Let’s take a look at the following newly added unit test for the controller:
test/unit/controllersSpec.js:
describe('PhoneListCtrl', function(){
it('should create "phones" model with 3 phones', function() {
var scope = {},
ctrl = new PhoneListCtrl(scope);
expect(scope.phones.length).toBe(3);
});
});
});
This test verifies that there are three records in our mobile phone array (no need to figure out this test script yet). This example shows how easy it is to create a unit test for AngularJS code. Because testing is an essential part of software development, we make it easy to build tests in AngularJS to encourage developers to write more of them.
When writing tests, AngularJS developers tend to use the syntax in the Jasmine Behavior-Driven Development (BBD) framework. Although AngularJS does not force you to use Jasmine, all of our tests in the tutorial are written using Jasmine. You can get relevant knowledge on Jasmine's official homepage or Jasmine Wiki.
AngularJS based projects are pre-configured to use the JsTestDriver to run unit tests.
You can run the test like this:
1. On a separate terminal, enter the angular-phonecat directory and run ./scripts/test-server.sh to start the test (please enter .scriptstest-server.bat on the Windows command line to run the script, followed by The script command runs in a similar way);
2. Open a new browser window and go to http://localhost:9876;
3. Select "Capture this browser in strict mode".
At this time, you can put aside your window and forget about it. JsTestDriver will run the test by itself and output the results in your terminal.
4. Run ./scripts/test.sh to test.
You should see results similar to the following:
Practice
Add another data binding for index.html. For example:
Total number of phones: {{phones.length}}
Create a simple table with an iterator:
row number |
---|
{{i}} |
row number |
---|
{{i 1}} |
Summary
You now have a dynamic application with separate models, views, and controllers that you can test at any time. Now, you can proceed to step 3 to add full-text search functionality to your application.