aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/tutorial/step_07.ngdoc
diff options
context:
space:
mode:
authorIgor Minar2012-03-30 14:02:26 -0700
committerIgor Minar2012-04-04 15:59:18 -0700
commit6336b6e89e3a80aec3c4367ab4c2737fd365c030 (patch)
tree31aa86a0555b541d1f6cc107845278ae80ddbff9 /docs/content/tutorial/step_07.ngdoc
parentfdf17d729fa7651e88dc5f27c40b8de875a34a55 (diff)
downloadangular.js-6336b6e89e3a80aec3c4367ab4c2737fd365c030.tar.bz2
chore(docs): restore old tutorial ngdoc files
Diffstat (limited to 'docs/content/tutorial/step_07.ngdoc')
-rw-r--r--docs/content/tutorial/step_07.ngdoc210
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>