In this step you will add a feature that allows the user to control the display order of the phone list. Dynamic sorting can be implemented by adding a new model property, integrating it with an iterator, and then having the data bound to complete the rest.
Please reset your working directory:
Git checkout-f step-4
You should find that in addition to the search box, your app has a more down menu, which allows you to control the order in which your phone is arranged.
The most important differences between steps 3 and 4 are listed below. You can see the whole difference on GitHub.
Template
App/index.html
Search: <input ng-model= "Query" >Sort by:<select ng-model= "Orderprop" > <option value= " Name ">Alphabetical</option> <option value=" age ">newest</option></select><ul class= "Phones" > <li ng-repeat= "Phone in phones | filter:query | orderby:orderprop" > {{Phone.name }} <p>{{phone.snippet}}</p> </li></ul>
We made the following changes in index.html :
- First, we add a tag called
orderProp
<select>
, so that our users can choose the two sort methods we provide.
- Then, after the
filter
filter, add an order by filter to process the data into the iterator. The orderBy
filter takes an array as input, copies a copy, and then re-sorts the copy and then outputs it to the iterator.
Angularjs select
orderProp
creates a two-way binding between the element and the model. orderProp
It is then used as orderBy
input to the filter.
As we talked about data binding and iterators in step 3, whenever the data model changes (such as when the user chooses a different order in the drop-down menu), the ANGULARJS data binding causes the view to update automatically. No clumsy DOM operation!
Controller
App/js/controllers.js:
function Phonelistctrl ($scope) { = [ {"name": "Nexus S", "snippet": "Fast just got Faster with Nexus S. " , " Age ": 0}, {" name ":" Motorola xoom™with wi-Fi "," snippet ":" The next, next Generation Tablet. " , " Age ": 1}, {" name ":" MOTOROLA xoom™ ", " snippet ":" The next, next Generation tablet. " , " Age ": 2} ]; = ' age ';}
- We have modified the
phones
model-the array of phones-to add an attribute to each cell phone record age
. We age
sort the phones according to the attributes.
We added a line to the controller code to let orderProp
the default value be age
. If we do not set the default value, the model will remain uninitialized until our users select a sequence in the drop-down menu.
Now we should talk about bidirectional data binding. Notice that when the app is loaded in the browser, "newest" is selected in the drop-down menu. This is because we set the ' age ' in the controller orderProp
. So binding works in the direction from our model to the user interface-the binding of data from model to view. Now when you select "Alphabetically" in the drop-down menu, the data model is updated at the same time, and the cell list array is reordered. This time data binding has a role in another direction-the binding of data from view to model.
Test
The changes we make can be validated by a unit test or an end-to-end test. Let's take a look at the unit tests first:
Test/unit/controllersspec.js:
Describe (' Phonecat controllers ',function() {Describe (' Phonelistctrl ',function(){ varscope, CTRL; Beforeeach (function() {scope={}, CTRL=NewPhonelistctrl (scope); }); It (' should create ' phones ' model with 3 phones ',function() {expect (scope.phones.length). ToBe (3); }); It (' should set the default value of Orderprop model ',function() {expect (Scope.orderprop). ToBe (' Age '); }); });});
Unit tests now verify that the default values are set correctly.
We use the Jasmine interface to PhoneListCtrl
extract the controller into a beforeEach
block that is describe
shared by all the tests in all the parent blocks.
Run these unit tests, as before, execute the ./scripts/test.sh
script, you should see the following output ( Note: to open http://localhost:9876 in the browser and enter strict mode, the test will not run!) ):
Chrome: RunnerReset...Total 2Tests(Passed: 2; Fails: 0; Errors: 0) (3.00Ms) chrome 19.0. 1084.36 mac Os: run 2 tests ( passed: 2; fails: 0; errors 0) (3.00 Ms)
Now let's shift our attention to end-to-end testing.
Test/e2e/scenarios.js:
... it (' Should is possible to control phone order via the drop-down select box ', function() { //Let's narrow the dataset to make the test assertions shorterInput (' query '). Enter (' Tablet '); Expect (Repeater ('. Phones li ', ' Phone List '). Column (' Phone.name ')). Toequal (["Motorola xoom\u2122 with Wi-Fi", "MOTOROLA xoom\u2122"]); Select (' Orderprop '). Option (' Alphabetical ').); Expect (Repeater ('. Phones li ', ' Phone List '). Column (' Phone.name ')). Toequal (["MOTOROLA xoom\u2122", "Motorola xoom\u2122 with Wi-Fi"]); });...
The end-to-end test verifies that the sorting mechanism of the option box is correct.
You can now refresh your browser and run the end-to-end test again, or you can run it on the ANGULARJS server.
Practice
- In the
PhoneListCtrl
controller, delete the SET orderProp
statement, and you will see that ANGULARJS will temporarily add a blank option in the drop-down menu, and the sort order is the default sort (that is, unsorted).
index.html
Add a ' {{Orderprop}} binding to the template to display its value in real time.
Summarize
Now you've provided search functionality for your app and tested it completely. Step 5 We will learn ANGULARJS services and how Angularjs uses dependency injection.