diff options
Diffstat (limited to 'docs/content/tutorial/step_07.ngdoc')
| -rw-r--r-- | docs/content/tutorial/step_07.ngdoc | 210 | 
1 files changed, 210 insertions, 0 deletions
| diff --git a/docs/content/tutorial/step_07.ngdoc b/docs/content/tutorial/step_07.ngdoc new file mode 100644 index 00000000..0aebb9fe --- /dev/null +++ b/docs/content/tutorial/step_07.ngdoc @@ -0,0 +1,210 @@ +@ngdoc overview +@name Tutorial: 7 - Routing & Multiple Views +@description + +<ul doc:tutorial-nav="7"></ul> + + +In this step, you will learn how to create a layout template and how to build an app that has +multiple views by adding routing. + + +<doc:tutorial-instructions step="7"></doc:tutorial-instructions> + + +Note that you are redirected to `app/index.html#/phones` and the same phone list appears in the +browser. When you click on a phone link the stub of a phone detail page is displayed. + + +The most important changes are listed below. You can see the full diff on {@link +https://github.com/angular/angular-phonecat/compare/step-6...step-7 +GitHub}: + + +## Multiple Views, Routing and Layout Template + +Our app is slowly growing and becoming more complex. Before step 7, the app provided our users with +a single view (the list of all phones), and all of the template code was located in the +`index.html` file. The next step in building the app is to add a view that will show detailed +information about each of the devices in our list. + +To add the detailed view, we could expand the `index.html` file to contain template code for both +views, but that would get messy very quickly. Instead, we are going to turn the `index.html` +template into what we call a "layout template". This is a template that is common for all views in +our application. Other "partial templates" are then included into this layout template depending on +the current "route" — the view that is currently displayed to the user. + +Application routes in angular are declared via the {@link api/angular.module.ng.$route $route} +service. This service makes it easy to wire together controllers, view templates, and the current +URL location in the browser. Using this feature we can implement {@link +http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize the browser's +history (back and forward navigation) and bookmarks. + + +## Controllers + +__`app/js/controller.js`:__ +<pre> +function PhoneCatCtrl($route) { +  var self = this; + +  $route.when('/phones', +      {template: 'partials/phone-list.html',   controller: PhoneListCtrl}); +  $route.when('/phones/:phoneId', +      {template: 'partials/phone-detail.html', controller: PhoneDetailCtrl}); +  $route.otherwise({redirectTo: '/phones'}); + +  $route.onChange(function() { +    self.params = $route.current.params; +  }); + +  $route.parent(this); +} + +//PhoneCatCtrl.$inject = ['$route']; +... +</pre> + +We created a new controller called `PhoneCatCtrl`. We declared its dependency on the `$route` +service and used this service to declare that our application consists of two different views: + +* The phone list view will be shown when the URL hash fragment is `/phones`. To construct this +view, angular will use the `phone-list.html` template and the `PhoneListCtrl` controller. + +* The phone details view will be shown when the URL hash fragment matches '/phone/:phoneId', where +`:phoneId` is a variable part of the URL. To construct the phone details view, angular will use the +`phone-detail.html` template and the `PhoneDetailCtrl` controller. + +We reused the `PhoneListCtrl` controller that we constructed in previous steps and we added a new, +empty `PhoneDetailCtrl` controller to the `app/js/controllers.js` file for the phone details view. + +The statement `$route.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when +the browser address doesn't match either of our routes. + +Thanks to the `$route.parent(this);` statement and `ng:controller="PhoneCatCtrl"` declaration in +the `index.html` template, the `PhoneCatCtrl` controller has a special role in our app. It is the +"root" controller and the parent controller for the other two sub-controllers (`PhoneListCtrl` and +`PhoneDetailCtrl`). The sub-controllers inherit the model properties and behavior from the root +controller. + +Note the use of the `:phoneId` parameter in the second route declaration. The `$route` service uses +the route declaration — `'/phones/:phoneId'` — as a template that is matched against the current +URL. All variables defined with the `:` notation are extracted into the `$route.current.params` map. + +The `params` alias created in the {@link api/angular.module.ng.$route `$route.onChange`} callback +allows us to use the `phoneId` property of this map in the `phone-details.html` template. + + +## Template + +The `$route` service is usually used in conjunction with the {@link api/angular.widget.ng:view +ng:view} widget. The role of the `ng:view` widget is to include the view template for the current +route into the layout template, which makes it a perfect fit for our `index.html` template. + +__`app/index.html`:__ +<pre> +<html ng:app> +... +<body ng:controller="PhoneCatCtrl"> + +  <ng:view></ng:view> + +  <script src="lib/angular/angular.js"></script> +  <script src="js/controllers.js"></script> +</body> +</html> +</pre> + +Note that we removed most of the code in the `index.html` template and replaced it with a single +line containing the `ng:view` tag. The code that we removed was placed into the `phone-list.html` +template: + +__`app/partials/phone-list.html`:__ +<pre> +<ul class="predicates"> +  <li> +    Search: <input type="text" ng:model="query"/> +  </li> +  <li> +    Sort by: +    <select ng:model="orderProp"> +      <option value="name">Alphabetical</option> +      <option value="age">Newest</option> +    </select> +  </li> +</ul> + +<ul class="phones"> +  <li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)"> +    <a href="#/phones/{{phone.id}}">{{phone.name}}</a> +    <a href="#/phones/{{phone.id}}" class="thumb"><img ng:src="{{phone.imageUrl}}"></a> +    <p>{{phone.snippet}}</p> +  </li> +</ul> +</pre> + +<img src="img/tutorial/tutorial_07_final.png"> + +We also added a placeholder template for the phone details view: + +__`app/partials/phone-detail.html`:__ +<pre> +TBD: detail view for {{params.phoneId}} +</pre> + +Note how we are using `params` model defined in the `PhoneCatCtrl` controller. + + +## Test + +To automatically verify that everything is wired properly, we wrote end-to-end tests that navigate +to various URLs and verify that the correct view was rendered. + +<pre> +... +  it('should redirect index.html to index.html#/phones', function() { +   browser().navigateTo('../../app/index.html'); +   expect(browser().location().hash()).toBe('/phones'); +  }); +... + + describe('Phone detail view', function() { + +   beforeEach(function() { +      browser().navigateTo('../../app/index.html#/phones/nexus-s'); +   }); + + +   it('should display placeholder page with phoneId', function() { +      expect(binding('params.phoneId')).toBe('nexus-s'); +   }); + }); +</pre> + + +You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you +can see them running on {@link +http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html +angular's server}. + + +# Experiments + +* Try to add an `{{orderProp}}` binding to `index.html`, and you'll see that nothing happens even +when you are in the phone list view. This is because the `orderProp` model is visible only in the +scope managed by `PhoneListCtrl`, which is associated with the `<ng:view>` element. If you add the +same binding into the `phone-list.html` template, the binding will work as expected. + +* In `PhoneCatCtrl`, create a new model called "`hero`" with `this.hero = 'Zoro'`. In +`PhoneListCtrl` let's shadow it with `this.hero = 'Batman'`, and in `PhoneDetailCtrl` we'll use +`this.hero = "Captain Proton"`. Then add the `<p>hero = {{hero}}</p>` to all three of our templates +(`index.html`, `phone-list.html`, and `phone-detail.html`). Open the app and you'll see scope +inheritance and model property shadowing do some wonders. + +# Summary + +With the routing set up and the phone list view implemented, we're ready to go to {@link step_08 +step 8} to implement the phone details view. + + +<ul doc:tutorial-nav="7"></ul> | 
