From ea6b87c24ba70d2554c0f9a3e80b245dc3780234 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 29 Apr 2011 11:04:18 -0700 Subject: renamed tutorial so that it would sort properly --- docs/tutorial.ngdoc | 2 +- docs/tutorial.step_0.ngdoc | 77 ------------------- docs/tutorial.step_00.ngdoc | 78 +++++++++++++++++++ docs/tutorial.step_01.ngdoc | 88 +++++++++++++++++++++ docs/tutorial.step_02.ngdoc | 137 +++++++++++++++++++++++++++++++++ docs/tutorial.step_03.ngdoc | 108 ++++++++++++++++++++++++++ docs/tutorial.step_04.ngdoc | 161 +++++++++++++++++++++++++++++++++++++++ docs/tutorial.step_05.ngdoc | 147 +++++++++++++++++++++++++++++++++++ docs/tutorial.step_06.ngdoc | 113 +++++++++++++++++++++++++++ docs/tutorial.step_07.ngdoc | 181 ++++++++++++++++++++++++++++++++++++++++++++ docs/tutorial.step_08.ngdoc | 148 ++++++++++++++++++++++++++++++++++++ docs/tutorial.step_09.ngdoc | 108 ++++++++++++++++++++++++++ docs/tutorial.step_1.ngdoc | 88 --------------------- docs/tutorial.step_10.ngdoc | 4 +- docs/tutorial.step_2.ngdoc | 137 --------------------------------- docs/tutorial.step_3.ngdoc | 108 -------------------------- docs/tutorial.step_4.ngdoc | 161 --------------------------------------- docs/tutorial.step_5.ngdoc | 147 ----------------------------------- docs/tutorial.step_6.ngdoc | 113 --------------------------- docs/tutorial.step_7.ngdoc | 181 -------------------------------------------- docs/tutorial.step_8.ngdoc | 148 ------------------------------------ docs/tutorial.step_9.ngdoc | 108 -------------------------- 22 files changed, 1272 insertions(+), 1271 deletions(-) delete mode 100755 docs/tutorial.step_0.ngdoc create mode 100755 docs/tutorial.step_00.ngdoc create mode 100755 docs/tutorial.step_01.ngdoc create mode 100755 docs/tutorial.step_02.ngdoc create mode 100755 docs/tutorial.step_03.ngdoc create mode 100755 docs/tutorial.step_04.ngdoc create mode 100755 docs/tutorial.step_05.ngdoc create mode 100755 docs/tutorial.step_06.ngdoc create mode 100755 docs/tutorial.step_07.ngdoc create mode 100755 docs/tutorial.step_08.ngdoc create mode 100755 docs/tutorial.step_09.ngdoc delete mode 100755 docs/tutorial.step_1.ngdoc delete mode 100755 docs/tutorial.step_2.ngdoc delete mode 100755 docs/tutorial.step_3.ngdoc delete mode 100755 docs/tutorial.step_4.ngdoc delete mode 100755 docs/tutorial.step_5.ngdoc delete mode 100755 docs/tutorial.step_6.ngdoc delete mode 100755 docs/tutorial.step_7.ngdoc delete mode 100755 docs/tutorial.step_8.ngdoc delete mode 100755 docs/tutorial.step_9.ngdoc (limited to 'docs') diff --git a/docs/tutorial.ngdoc b/docs/tutorial.ngdoc index a8a51b45..b430b248 100644 --- a/docs/tutorial.ngdoc +++ b/docs/tutorial.ngdoc @@ -3,7 +3,7 @@ @name Tutorial @description -A great way to get introduced to angular is to work through the {@link tutorial.step_0 angular +A great way to get introduced to angular is to work through the {@link tutorial.step_00 angular tutorial}, which walks you through the construction of an angular web app. The app you will build in the tutorial is loosely based on the {@link http://www.google.com/phone/ Google phone gallery app}. The {@link http://angular.github.com/angular-phonecat/step-11/app/ end result of our effort} diff --git a/docs/tutorial.step_0.ngdoc b/docs/tutorial.step_0.ngdoc deleted file mode 100755 index 6d11d3b0..00000000 --- a/docs/tutorial.step_0.ngdoc +++ /dev/null @@ -1,77 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 0 -@description - - - - - - - - - -
{@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-0/app Example}{@link tutorial Tutorial Home}Code Diff{@link tutorial.step_1 Next}
- -The following sample code is our starting point. It is a static HTML page that displays next to -nothing, but it has everything we need to proceed. You can think of this bit of code as our -prototype template, consisting of basic HTML tags with a pair of angular specific attributes. - -__`app/index.html`:__ -
-
-
-
-  
-  my angular app
-  
-
-
-
-  Nothing here yet!
-
-  
-
-
-
- -## Discussion: - -Although our app doesn't appear to do anything dynamic, note the following: - -* __... `xmlns:ng="http://angularjs.org"` ...__ This `xmlns` declaration for the `ng` namespace -must be specified if you use XHTML, or if you are targeting IE older than 9 (regardless of whether -you are using XHTML or HTML). - -* __` - - This will download the angular script from the angular server instead of from a local file. - -* To try this code out in your browser, you need to navigate to the step-0 page (you are currently -on Step 0 of the tutorial). If your http server is running, navigate to `app/index.html`. -Remember, this is a relative URL (see the Relative URL section in {@link tutorial Tutorial}). The -browser will display the same thing as you would see if you go to -http://angular.github.com/angular-phonecat/step-0/app (accessible from Example link at the bottom -of the page). - -Now we can move on and add some content to our developing web app. - - - - - - - - - -
{@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-0/app Example}{@link tutorial Tutorial Home}Code Diff{@link tutorial.step_1 Next}
diff --git a/docs/tutorial.step_00.ngdoc b/docs/tutorial.step_00.ngdoc new file mode 100755 index 00000000..dbe38285 --- /dev/null +++ b/docs/tutorial.step_00.ngdoc @@ -0,0 +1,78 @@ + +@workInProgress +@ngdoc overview +@name Tutorial: Step 0 +@description + + + + + + + + + +
{@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-0/app Example}{@link tutorial Tutorial Home}Code Diff{@link tutorial.step_01 Next}
+ +The following sample code is our starting point. It is a static HTML page that displays next to +nothing, but it has everything we need to proceed. You can think of this bit of code as our +prototype template, consisting of basic HTML tags with a pair of angular specific attributes. + +__`app/index.html`:__ +
+
+
+
+  
+  my angular app
+  
+
+
+
+  Nothing here yet!
+
+  
+
+
+
+ +## Discussion: + +Although our app doesn't appear to do anything dynamic, note the following: + +* __... `xmlns:ng="http://angularjs.org"` ...__ This `xmlns` declaration for the `ng` namespace +must be specified if you use XHTML, or if you are targeting IE older than 9 (regardless of whether +you are using XHTML or HTML). + +* __` + + This will download the angular script from the angular server instead of from a local file. + +* To try this code out in your browser, you need to navigate to the step-0 page (you are currently +on Step 0 of the tutorial). If your http server is running, navigate to `app/index.html`. +Remember, this is a relative URL (see the Relative URL section in {@link tutorial Tutorial}). The +browser will display the same thing as you would see if you go to +http://angular.github.com/angular-phonecat/step-0/app (accessible from Example link at the bottom +of the page). + +Now we can move on and add some content to our developing web app. + + + + + + + + + +
{@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-0/app Example}{@link tutorial Tutorial Home}Code Diff{@link tutorial.step_01 Next}
diff --git a/docs/tutorial.step_01.ngdoc b/docs/tutorial.step_01.ngdoc new file mode 100755 index 00000000..d96eaeb3 --- /dev/null +++ b/docs/tutorial.step_01.ngdoc @@ -0,0 +1,88 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 1 +@description + + + + + + + + +
{@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-1/app Example}{@link tutorial Tutorial Home} +{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}{@link tutorial.step_00 Next}
+ +Now that we have the basic ingredients in place, let's add some basic information about two cell +phones to our app. + +Note: We will usually include only the new code that we added for each step. In this and +subsequent examples, we will leave out code from the previous step that hasn't changed, for +example: + + ... + + ... + +Let's add the following code to `index.html`: + +__`app/index.html`:__ +
+
+...
+  Google Phone Gallery
+...
+
+...
+  
+...
+
+ +## Discussion: + +* It's a static web page! We displayed info about two phones! Yay. + +* For those of you playing along at home on your own web servers, did you switch to Step 1 and +refresh your browsers? + + * __{@link tutorial Using Git:}__ + + From your `angular-phonecat` directory, run this command: + + git checkout step-1 + + * __{@link tutorial Using Snapshots:}__ + + From `[install directory]/sandbox`, run this command: + + ./goto_step.sh 1 + +* Now would be a good time to open up `app/index.html` in your browser and see the current state +of our "application". It's not very exciting, but that's ok. + +When you're ready, let's move on and start using some angular features to turn this static page +into a dynamic web app. + + + + + + + + + +
{@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-1/app Example}{@link tutorial Tutorial Home} +{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}{@link tutorial.step_00 Next}
diff --git a/docs/tutorial.step_02.ngdoc b/docs/tutorial.step_02.ngdoc new file mode 100755 index 00000000..62becdba --- /dev/null +++ b/docs/tutorial.step_02.ngdoc @@ -0,0 +1,137 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 2 +@description + + + + + + + + +
{@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-2/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code +Diff}{@link tutorial.step_00 Next}
+ +In the last step, we remembered what a basic, static web page looks like, and now we want to get +dynamic. There are many ways to do this, but an important feature of angular is the incorporation +of the principles behind {@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design +pattern} into client-side web apps. With that in mind, let's use a little angular and a little +JavaScript to add Model, View, and Controller components to our app, and change the static page +into one that is dynamically generated. + +Our __View__ component is constructed by angular from this template: + +__`app/index.html`:__ +
+...
+
+
+  
+
+  
+  
+
+...
+
+ +Our data __Model__ (a short list of phones in object literal notation) is instantiated within our +__Controller__ function (`PhoneListCtrl`): + +__`app/js/controllers.js`:__ +
+/* App Controllers */
+
+function PhoneListCtrl() {
+  this.phones = [{"name": "Nexus S",
+                  "snippet": "Fast just got faster with Nexus S."},
+                 {"name": "Motorola XOOM™ with Wi-Fi",
+                  "snippet": "The Next, Next Generation tablet."},
+                 {"name": "MOTOROLA XOOM™",
+                  "snippet": "The Next, Next Generation tablet."}];
+}
+
+ +The "Angular way" urges us to test as we develop: + +__`test/unit/controllersSpec.js`:__ +
+/* jasmine specs for controllers go here */
+describe('PhoneCat controllers', function() {
+
+  describe('PhoneListCtrl', function(){
+
+    it('should create "phones" model with 3 phones', function() {
+      var ctrl = new PhoneListCtrl();
+      expect(ctrl.phones.length).toBe(3);
+    });
+  });
+});
+
+ +## Discussion: + +So what were our changes from Step 1? + +* __View template:__ We replaced the hard-coded phone list with the {@link +angular.widget.@ng:repeat ng:repeat widget} and two {@link guide.expression angular expressions} +enclosed in curly braces: `{{phone.name}}` and `{{phone.snippet}}`: + + * The `ng:repeat="phone in phones"` statement in the `
  • ` tag is an angular repeater. It + tells angular to create a `
  • ` element for each phone in the phones list, using the first + `
  • ` tag as the template. + + * The curly braces around `phone.name` and `phone.snippet` are an example of {@link + angular.markup angular markup}. The curly braces are shorthand for the angular directive + {@link angular.directive.ng:bind ng:bind}. They indicate to angular that these are template + binding points. Binding points are locations in the template where angular creates + data-binding between the View and the Model. In angular, the View is a projection of the Model + through the HTML template. This means that whenever the model changes, angular refreshes the + appropriate binding points, which updates the view. + +* __Controller:__ At this point, it doesn't appear as if our controller is doing very much +controlling, but it is playing a crucial role: providing context for our data model so we can +establish data-binding between the model and the view. Note in the following how we connected the +dots between our presentation, data, and logic components: + + * The name of our controller function (in the JavaScript file `controllers.js`) matches the + {@link angular.directive.ng:controller ng:controller} directive in the `` tag + (`PhoneListCtrl`). + * We instantiated our data within the scope of our controller function, and our template + binding points are located within the block bounded by the ` + + {@link tutorial.step_00 Previous} + {@link http://angular.github.com/angular-phonecat/step-2/app Example} + {@link tutorial Tutorial Home} +{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code +Diff} + {@link tutorial.step_00 Next} + + diff --git a/docs/tutorial.step_03.ngdoc b/docs/tutorial.step_03.ngdoc new file mode 100755 index 00000000..4fcccf4e --- /dev/null +++ b/docs/tutorial.step_03.ngdoc @@ -0,0 +1,108 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 3 +@description + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-3/app Example}{@link tutorial Tutorial Home}{@link + https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code + Diff}{@link tutorial.step_00 Next}
    + +We did a lot of work in laying the foundation of our app in the last step, so now we'll do +something simple, and add full text search. We will also write an end-to-end test, because a good +end-to-end test is a good friend. It stays with your app, keeps an eye on it, and quickly detects +regressions. + +__`app/index.html`:__ +
    +...
    +   Fulltext Search: 
    +
    +  
    +...
    +
    +__`test/e2e/scenarios.js`:__ +
    +/* jasmine-like end2end tests go here */
    +describe('PhoneCat App', function() {
    +
    +  describe('Phone list view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html');
    +    });
    +
    +
    +    it('should filter the phone list as user types into the search box', function() {
    +      expect(repeater('.phones li').count()).toBe(3);
    +
    +      input('query').enter('nexus');
    +      expect(repeater('.phones li').count()).toBe(1);
    +
    +      input('query').enter('motorola');
    +      expect(repeater('.phones li').count()).toBe(2);
    +    });
    +  });
    +});
    +
    + +## Discussion: + +We continued using the same controller that we set up in Step 2, but we added the following +features to our app: + +* __Search Box:__ A standard HTML `` tag combined with angular's {@link +angular.Array.filter $filter} utility (added to the repeater) lets a user type in search criteria +and immediately see the effects of their search on the phone list. This new code demonstrates the +following: + + * Two way Data-binding. This is one of the core features in angular. When the page loads, + angular binds the name of the input box to a variable of the same name in the data model and + keeps the two in sync. + +In this example, the data that you type into the input box (named __`query`__) is immediately +available as a filter input in the list repeater (`phone in phones.$filter(`__`query`__`)`). +Whenever the data model changes and this change causes the input to the repeater to change, the +repeater will efficiently update the DOM to reflect the current state of the model. + + * Use of `$filter` in a template. The `$filter` function is one of several built-in {@link + angular.Array angular functions} that augment JavaScript arrays during their evaluation as + angular expressions. In {@link guide.expression angular expressions}, these array utilities are + available as array methods. (They are prefixed with a $ to avoid naming collisions.) + + * `ng:repeat` automatically shrinks and grows the number of phones in the View, via DOM + manipulation that is completely transparent to the developer. If you've written any DOM + manipulation code, this should make you happy. + +* __CSS:__ We added in some minimal CSS to the file we set up in Step 0: `./css/app.css`. + +* __Testing:__ To run the end to end test, open http://localhost:8000/test/e2e/runner.html in +your browser. This end-to-end test shows the following: + + * Proof that the search box and the repeater are correctly wired together. + + * How easy it is to write end-to-end tests. This is just a simple test, but the point here is + to show how easy it is to set up a functional, readable, end-to-end test. + + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-3/app Example}{@link tutorial Tutorial Home}{@link + https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code + Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_04.ngdoc b/docs/tutorial.step_04.ngdoc new file mode 100755 index 00000000..559055b6 --- /dev/null +++ b/docs/tutorial.step_04.ngdoc @@ -0,0 +1,161 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 4 +@description + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-4/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-3...step-4 Code +Diff}{@link tutorial.step_00 Next}
    + +In this step, we add a feature that lets our users choose which way to order the phone list. + +__`app/index.html`:__ +
    +...
    +  
    +
    +  
    +...
    +
    + +__`app/js/controller.js`:__ +
    +/* App Controllers */
    +
    +function PhoneListCtrl() {
    +  this.phones = [{"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}];
    +
    +  this.orderProp = 'age';
    +}
    +
    + +__`test/unit/controllerSpec.js`:__ +
    +/* jasmine specs for controllers go here */
    +describe('PhoneCat controllers', function() {
    +
    +  describe('PhoneListCtrl', function(){
    +    var scope, $browser, ctrl;
    +
    +    beforeEach(function() {
    +      ctrl = new PhoneListCtrl();
    +    });
    +
    +
    +    it('should create "phones" model with 3 phones', function() {
    +      expect(ctrl.phones.length).toBe(3);
    +    });
    +
    +
    +    it('should set the default value of orderProp model', function() {
    +      expect(ctrl.orderProp).toBe('age');
    +    });
    +  });
    +});
    +
    + +__`test/e2e/scenarios.js`:__ +
    +/* jasmine-like end2end tests go here */
    +describe('PhoneCat App', function() {
    +
    +  describe('Phone list view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html');
    +    });
    +
    +
    +    it('should filter the phone list as user types into the search box', function() {
    +      expect(repeater('.phones li').count()).toBe(3);
    +
    +      input('query').enter('nexus');
    +      expect(repeater('.phones li').count()).toBe(1);
    +
    +      input('query').enter('motorola');
    +      expect(repeater('.phones li').count()).toBe(2);
    +    });
    +
    +
    +    it('should be possible to control phone order via the drop down select box', function() {
    +      input('query').enter('tablet'); //let's narrow the dataset to make the test assertions
    +      shorter
    +
    +      expect(repeater('.phones li', 'Phone List').column('a')).
    +          toEqual(["Motorola XOOM\u2122 with Wi-Fi",
    +                   "MOTOROLA XOOM\u2122"]);
    +
    +      select('orderProp').option('alphabetical');
    +
    +      expect(repeater('.phones li', 'Phone List').column('a')).
    +          toEqual(["MOTOROLA XOOM\u2122",
    +                   "Motorola XOOM\u2122 with Wi-Fi"]);
    +    });
    +  });
    +});
    +
    + +## Discussion: + +To provide dynamic ordering, we employ another one of angular's "array type augmenters" and let +the data binding do the rest of the work for us: + +* First, we provide a ` +
  • +
  • + Sort by: + +
  • + + + +... + + +__`app/js/controller.js`__ (Unchanged): +
    +/* App Controllers */
    +
    +function PhoneListCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/phones.json', function(code, response) {
    +    self.phones = response;
    +  });
    +
    +  self.orderProp = 'age';
    +}
    +
    +//PhoneListCtrl.$inject = ['$xhr'];
    +
    + +__`app/phones/phones.json`__ (sample snippet): +
    + [
    +  {
    +   "age": 4, 
    +   ...
    +   "carrier": "T-Mobile", 
    +   "id": "motorola-defy-with-motoblur", 
    +   "imageUrl": "http://google.com/phone/image/small/640001", 
    +   "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", 
    +   "snippet": "Are you ready for everything life throws your way?"
    +  }, 
    +  …
    + ]
    +
    + +__`test/e2e/scenarios.js`__: +
    +...
    +    it('should render phone specific links', function() {
    +      input('query').enter('nexus');
    +      element('.phones li a').click();
    +      expect(browser().location().hash()).toBe('/phones/nexus-s');
    +    });
    +...
    +
    + +## Discussion: + +* Note that we're using {@link guide.expression angular expressions} enclosed in the now-familiar +{@link angular.markup double-curly brace markup} in the href attribute values. These represent +attribute bindings, and work the same way as the bindings we saw in previous steps. + +* Note also the use of the {@link angular.directive.ng:src ng:src} directive in the `` tag. +That directive prevents the browser from treating the angular `{{ exppression }}` markup +literally, as it would do if we tried to use markup in a regular `src` attribute. Use `ng:src` to +keep the browser from eagerly making an extra http request to an invalid location. + +* We expanded our end-to-end test to verify that the app is generating correct links to the phone +views we will implement in the upcoming steps. + + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-6/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-5...step-6 Code +Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_07.ngdoc b/docs/tutorial.step_07.ngdoc new file mode 100755 index 00000000..3c715a79 --- /dev/null +++ b/docs/tutorial.step_07.ngdoc @@ -0,0 +1,181 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 7 +@description + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code +Diff}{@link tutorial.step_00 Next}
    + +Our app is slowly growing and becoming more complex. Up until now, the app provided our users with +just one view (the list of all phones), and all of our template code was located in the +`index.html` file. The next step in building our app is the addition of 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. + +Similarly as with templates, angular also allows for controllers and scopes managed by these +controllers to be nested. We are going to create a "root" controller called `PhoneCatCtrl`, which +will contain the declaration of routes for the application. + +Application routes in angular are declared via the {@link angular.service.$route $route} service. +This services 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, and Back and Forward browser navigation. + +We'll use the $route service to declare that our application consists of two different views: one +view presents the phone listing, and the other view presents the details for a particular phone. +Each view will have the template stored in a separate file in the `app/partials/` directory. +Similarly each view will have a controller associated with it. These will be stored in the +existing `app/js/controllers.js` file. + +The `$route` service is usually used in conjunction with the {@link 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. + +For now we are going to get all the routing going, and move the phone listing template into a +separate file. We'll save the implementation of the phone details View for the next step. + +__`app/index.html`:__ +
    +...
    +
    +
    +  
    +
    +  
    +  
    +
    +
    +
    + +__`app/partials/phone-list.html`:__ +
    +
    +
    +
    +
    + +__`app/partials/phone-list.html`:__ +
    +TBD: detail view for {{params.phoneId}}
    +
    + +__`app/js/controller.js`:__ +
    +/* App Controllers */
    +
    +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'];
    +
    +
    +function PhoneListCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/phones.json', function(code, response) {
    +    self.phones = response;
    +  });
    +
    +  self.orderProp = 'age';
    +}
    +
    +//PhoneListCtrl.$inject = ['$xhr'];
    +
    +
    +function PhoneDetailCtrl() {}
    +
    + +## Discussion: + +* __The View.__ Our View template in `index.html` has been reduced down to this: +``. As described above, it is now a "layout template". We added the following +two new View templates: + + * `app/partials/phone-list.html` for the phone list. The phone-list view was formerly our + main view. We simply moved the code from `index.html` to here. + + * `app/partials/phone-detail.html` for the phone details (just a placeholder template for now). + +* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two +sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`). These inherit the model properties and +behavior from the root controller. + + * __`$route.`__ The root controller's job now is to set up the `$route` configuration: + + * When the fragment part of the URL in the browser ends in "/phones", `$route` service + grabs the `phone-list.html` template, compiles it, and links it with a new scope that is + controlled by our `PhoneListCtrl` controller. + + * When the URL ends in "/phones/:phoneId", `$route` compiles and links the + `phone-detail.html` template as it did with `phone-list.html`. But note the use of the + `:phoneId` parameter declaration in the `path` argument of `$route.when()`: `$route` + services provides all the values for variables defined in this way as + `$route.current.params` map. In our route, `$route.current.params.phoneId` always holds + the current contents of the `:phoneId` portion of the URL. We will use the `phoneId` + parameter when we fetch the phone details in Step 8. + + * Any other URL fragment gets redirected to `/phones`. + + * __Controller/Scope inheritance.__ In the function passed into `$route`'s `onChange()` + method, we copied url parameters extracted from the current route to the `params` property in + the root scope. This property is inherited by child scopes created for our view controllers + and accessible by these controllers. + + * __Tests.__ To automatically verify that everything is wired properly, we write end to end + tests that navigate to various URLs and verify that the correct view was rendered. + + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code +Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_08.ngdoc b/docs/tutorial.step_08.ngdoc new file mode 100755 index 00000000..bd220f5a --- /dev/null +++ b/docs/tutorial.step_08.ngdoc @@ -0,0 +1,148 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 8 +@description + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code +Diff}{@link tutorial.step_00 Next}
    + +In this step, we implement the Phone Details View template. Once again we will use {@link +angular.services.$xhr $xhr} to fetch our data, and we'll flesh out the `phone-details.html` View +template. + +__`app/partials/phone-details.html`:__ +
    +
    +
    +

    {{phone.name}}

    + +

    {{phone.description}}

    + + + + +
    + +__`app/js/controller.js`:__ +
    +function PhoneCatCtrl($route) (same as Step 7)
    +
    +function PhoneListCtrl($xhr) (same as Step 7)
    +
    +function PhoneDetailCtrl($xhr) {
    +  var self = this;
    +
    +  $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
    +    self.phone = response;
    +  });
    +}
    +
    +//PhoneDetailCtrl.$inject = ['$xhr'];
    +
    + +__`app/phones/nexus-s.json`:__ (sample snippet) +
    +{
    +  "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope,
    +  Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", 
    +  "android": {
    +      "os": "Android 2.3", 
    +      "ui": "Android"
    +  }, 
    +  ...
    +  "images": [
    +      "img/phones/nexus-s.0.jpg", 
    +      "img/phones/nexus-s.1.jpg", 
    +      "img/phones/nexus-s.2.jpg", 
    +      "img/phones/nexus-s.3.jpg"
    +  ], 
    +  "storage": {
    +      "flash": "16384MB", 
    +      "ram": "512MB"
    +  }
    +}
    +
    + +__`test/unit/controllerSpec.js`:__ +
    +...
    +    it('should fetch phone detail', function(){
    +      scope.params = {phoneId:'xyz'};
    +      $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
    +      ctrl = scope.$new(PhoneDetailCtrl);
    +
    +      expect(ctrl.phone).toBeUndefined();
    +      $browser.xhr.flush();
    +
    +      expect(ctrl.phone).toEqual({name:'phone xyz'});
    +    });
    +...
    +
    + +__`test/e2e/scenarios.js`:__ +
    +...
    +  describe('Phone detail view', function() {
    +
    +    beforeEach(function() {
    +      browser().navigateTo('../../app/index.html#/phones/nexus-s');
    +    });
    +
    +
    +    it('should display nexus-s page', function() {
    +      expect(binding('phone.name')).toBe('Nexus S');
    +    });
    +  });
    +...
    +
    + +## Discussion: + +* Phone Details View Template. There is nothing fancy or new here, just note where we use the +angular `{{ expression }}` markup and directives to project phone data from our model into the +view. + +* Note how we used the `$route` `params` object from the scope managed by the root controller +(`PhoneCatCtrl`), to construct the path for the phone details xhr request. The rest of this step +is simply applying the previously learned concepts and angular APIs to create a large template +that displays a lot of data about a phone. + +* Tests. We updated the existing end to end test and wrote a new unit test that is similar in +spirit to the one we wrote for the `PhoneListCtrl` controller. + + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code +Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_09.ngdoc b/docs/tutorial.step_09.ngdoc new file mode 100755 index 00000000..9d952514 --- /dev/null +++ b/docs/tutorial.step_09.ngdoc @@ -0,0 +1,108 @@ +@workInProgress +@ngdoc overview +@name Tutorial: Step 9 +@description + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code +Diff}{@link tutorial.step_00 Next}
    + +In this step, we have determined that the built-in angular display filters ({@link +angular.filter.number number}, {@link angular.filter.currency currency}, {@link +angular.filter.date date}, etc.) don't handle what we want to do, so we get to create our own +custom {@link angular.filter filter}. + +In the previous step, the details page displayed either "true" or "false" to indicate whether +certain phone features were present or not. Our custom "checkmark" filter replaces those text +strings with glyphs: ✓ for "true", and ✘ for "false". + +Our filter code lives in `app/js/filters.js`: + +__`app/index.html`:__ +
    +...
    + 
    + 
    + 
    +...
    +
    + +In the phone details template, we employ our filter for angular expressions whose values are +"true" or "false"; `{{ [phone_feature] | checkmark }}`: + +__`app/partials/phone-detail.html`:__ +
    +
    +

    {{phone.name}}

    +

    {{phone.description}}

    +... + +
    + +__`app/js/filters.js`:__ (New) +
    +angular.filter('checkmark', function(input) {
    +  return input ? '\u2713' : '\u2718';
    +});
    +
    + +__`test/unit/filtersSpec.js`:__ (New) +
    +describe('checkmark filter', function() {
    +
    +  it('should convert boolean values to unicode checkmark or cross', function() {
    +    expect(angular.filter.checkmark(true)).toBe('\u2713');
    +    expect(angular.filter.checkmark(false)).toBe('\u2718');
    +  });
    +})
    +
    + +## Discussion: + +* This example shows how easy it is to roll your own filters for displaying data. As explained in +the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you +simply register your custom filter function on to the `angular.filter` function. + +* In this example, our filter name is "checkmark"; our input is either "true" or "false", and we +return one of two unicode characters we have chosen to represent true or false (`\u2713` and +`\u2718`). + +* We created a new unit test to verify that our custom filter converts boolean values to unicode +characters. + + + + + + + + + +
    {@link tutorial.step_00 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo +}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code +Diff}{@link tutorial.step_00 Next}
    diff --git a/docs/tutorial.step_1.ngdoc b/docs/tutorial.step_1.ngdoc deleted file mode 100755 index 7b4613b7..00000000 --- a/docs/tutorial.step_1.ngdoc +++ /dev/null @@ -1,88 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 1 -@description - - - - - - - - -
    {@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-1/app Example}{@link tutorial Tutorial Home} -{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}{@link tutorial.step_2 Next}
    - -Now that we have the basic ingredients in place, let's add some basic information about two cell -phones to our app. - -Note: We will usually include only the new code that we added for each step. In this and -subsequent examples, we will leave out code from the previous step that hasn't changed, for -example: - - ... - - ... - -Let's add the following code to `index.html`: - -__`app/index.html`:__ -
    -
    -...
    -  Google Phone Gallery
    -...
    -
    -...
    -  
    -...
    -
    - -## Discussion: - -* It's a static web page! We displayed info about two phones! Yay. - -* For those of you playing along at home on your own web servers, did you switch to Step 1 and -refresh your browsers? - - * __{@link tutorial Using Git:}__ - - From your `angular-phonecat` directory, run this command: - - git checkout step-1 - - * __{@link tutorial Using Snapshots:}__ - - From `[install directory]/sandbox`, run this command: - - ./goto_step.sh 1 - -* Now would be a good time to open up `app/index.html` in your browser and see the current state -of our "application". It's not very exciting, but that's ok. - -When you're ready, let's move on and start using some angular features to turn this static page -into a dynamic web app. - - - - - - - - - -
    {@link tutorial Previous}{@link http://angular.github.com/angular-phonecat/step-1/app Example}{@link tutorial Tutorial Home} -{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}{@link tutorial.step_2 Next}
    diff --git a/docs/tutorial.step_10.ngdoc b/docs/tutorial.step_10.ngdoc index 2abe3344..130b4023 100644 --- a/docs/tutorial.step_10.ngdoc +++ b/docs/tutorial.step_10.ngdoc @@ -4,7 +4,7 @@ @description - + @@ -99,7 +99,7 @@ the `setImage` controller method.
    {@link tutorial.step_9 Previous}{@link tutorial.step_09 Previous} {@link http://angular.github.com/angular-phonecat/step-10/app Live Demo } {@link tutorial Tutorial Home}
    - + diff --git a/docs/tutorial.step_2.ngdoc b/docs/tutorial.step_2.ngdoc deleted file mode 100755 index 90a50e0e..00000000 --- a/docs/tutorial.step_2.ngdoc +++ /dev/null @@ -1,137 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 2 -@description -
    {@link tutorial.step_9 Previous}{@link tutorial.step_09 Previous} {@link http://angular.github.com/angular-phonecat/step-10/app Live Demo } {@link tutorial Tutorial Home}
    - - - - - - - -
    {@link tutorial.step_1 Previous}{@link http://angular.github.com/angular-phonecat/step-2/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code -Diff}{@link tutorial.step_3 Next}
    - -In the last step, we remembered what a basic, static web page looks like, and now we want to get -dynamic. There are many ways to do this, but an important feature of angular is the incorporation -of the principles behind {@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design -pattern} into client-side web apps. With that in mind, let's use a little angular and a little -JavaScript to add Model, View, and Controller components to our app, and change the static page -into one that is dynamically generated. - -Our __View__ component is constructed by angular from this template: - -__`app/index.html`:__ -
    -...
    -
    -
    -  
    -
    -  
    -  
    -
    -...
    -
    - -Our data __Model__ (a short list of phones in object literal notation) is instantiated within our -__Controller__ function (`PhoneListCtrl`): - -__`app/js/controllers.js`:__ -
    -/* App Controllers */
    -
    -function PhoneListCtrl() {
    -  this.phones = [{"name": "Nexus S",
    -                  "snippet": "Fast just got faster with Nexus S."},
    -                 {"name": "Motorola XOOM™ with Wi-Fi",
    -                  "snippet": "The Next, Next Generation tablet."},
    -                 {"name": "MOTOROLA XOOM™",
    -                  "snippet": "The Next, Next Generation tablet."}];
    -}
    -
    - -The "Angular way" urges us to test as we develop: - -__`test/unit/controllersSpec.js`:__ -
    -/* jasmine specs for controllers go here */
    -describe('PhoneCat controllers', function() {
    -
    -  describe('PhoneListCtrl', function(){
    -
    -    it('should create "phones" model with 3 phones', function() {
    -      var ctrl = new PhoneListCtrl();
    -      expect(ctrl.phones.length).toBe(3);
    -    });
    -  });
    -});
    -
    - -## Discussion: - -So what were our changes from Step 1? - -* __View template:__ We replaced the hard-coded phone list with the {@link -angular.widget.@ng:repeat ng:repeat widget} and two {@link guide.expression angular expressions} -enclosed in curly braces: `{{phone.name}}` and `{{phone.snippet}}`: - - * The `ng:repeat="phone in phones"` statement in the `
  • ` tag is an angular repeater. It - tells angular to create a `
  • ` element for each phone in the phones list, using the first - `
  • ` tag as the template. - - * The curly braces around `phone.name` and `phone.snippet` are an example of {@link - angular.markup angular markup}. The curly braces are shorthand for the angular directive - {@link angular.directive.ng:bind ng:bind}. They indicate to angular that these are template - binding points. Binding points are locations in the template where angular creates - data-binding between the View and the Model. In angular, the View is a projection of the Model - through the HTML template. This means that whenever the model changes, angular refreshes the - appropriate binding points, which updates the view. - -* __Controller:__ At this point, it doesn't appear as if our controller is doing very much -controlling, but it is playing a crucial role: providing context for our data model so we can -establish data-binding between the model and the view. Note in the following how we connected the -dots between our presentation, data, and logic components: - - * The name of our controller function (in the JavaScript file `controllers.js`) matches the - {@link angular.directive.ng:controller ng:controller} directive in the `` tag - (`PhoneListCtrl`). - * We instantiated our data within the scope of our controller function, and our template - binding points are located within the block bounded by the ` - - {@link tutorial.step_1 Previous} - {@link http://angular.github.com/angular-phonecat/step-2/app Example} - {@link tutorial Tutorial Home} -{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code -Diff} - {@link tutorial.step_3 Next} - - diff --git a/docs/tutorial.step_3.ngdoc b/docs/tutorial.step_3.ngdoc deleted file mode 100755 index b3d3efc2..00000000 --- a/docs/tutorial.step_3.ngdoc +++ /dev/null @@ -1,108 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 3 -@description - - - - - - - - -
    {@link tutorial.step_2 Previous}{@link http://angular.github.com/angular-phonecat/step-3/app Example}{@link tutorial Tutorial Home}{@link - https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code - Diff}{@link tutorial.step_4 Next}
    - -We did a lot of work in laying the foundation of our app in the last step, so now we'll do -something simple, and add full text search. We will also write an end-to-end test, because a good -end-to-end test is a good friend. It stays with your app, keeps an eye on it, and quickly detects -regressions. - -__`app/index.html`:__ -
    -...
    -   Fulltext Search: 
    -
    -  
    -...
    -
    -__`test/e2e/scenarios.js`:__ -
    -/* jasmine-like end2end tests go here */
    -describe('PhoneCat App', function() {
    -
    -  describe('Phone list view', function() {
    -
    -    beforeEach(function() {
    -      browser().navigateTo('../../app/index.html');
    -    });
    -
    -
    -    it('should filter the phone list as user types into the search box', function() {
    -      expect(repeater('.phones li').count()).toBe(3);
    -
    -      input('query').enter('nexus');
    -      expect(repeater('.phones li').count()).toBe(1);
    -
    -      input('query').enter('motorola');
    -      expect(repeater('.phones li').count()).toBe(2);
    -    });
    -  });
    -});
    -
    - -## Discussion: - -We continued using the same controller that we set up in Step 2, but we added the following -features to our app: - -* __Search Box:__ A standard HTML `` tag combined with angular's {@link -angular.Array.filter $filter} utility (added to the repeater) lets a user type in search criteria -and immediately see the effects of their search on the phone list. This new code demonstrates the -following: - - * Two way Data-binding. This is one of the core features in angular. When the page loads, - angular binds the name of the input box to a variable of the same name in the data model and - keeps the two in sync. - -In this example, the data that you type into the input box (named __`query`__) is immediately -available as a filter input in the list repeater (`phone in phones.$filter(`__`query`__`)`). -Whenever the data model changes and this change causes the input to the repeater to change, the -repeater will efficiently update the DOM to reflect the current state of the model. - - * Use of `$filter` in a template. The `$filter` function is one of several built-in {@link - angular.Array angular functions} that augment JavaScript arrays during their evaluation as - angular expressions. In {@link guide.expression angular expressions}, these array utilities are - available as array methods. (They are prefixed with a $ to avoid naming collisions.) - - * `ng:repeat` automatically shrinks and grows the number of phones in the View, via DOM - manipulation that is completely transparent to the developer. If you've written any DOM - manipulation code, this should make you happy. - -* __CSS:__ We added in some minimal CSS to the file we set up in Step 0: `./css/app.css`. - -* __Testing:__ To run the end to end test, open http://localhost:8000/test/e2e/runner.html in -your browser. This end-to-end test shows the following: - - * Proof that the search box and the repeater are correctly wired together. - - * How easy it is to write end-to-end tests. This is just a simple test, but the point here is - to show how easy it is to set up a functional, readable, end-to-end test. - - - - - - - - - -
    {@link tutorial.step_2 Previous}{@link http://angular.github.com/angular-phonecat/step-3/app Example}{@link tutorial Tutorial Home}{@link - https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code - Diff}{@link tutorial.step_4 Next}
    diff --git a/docs/tutorial.step_4.ngdoc b/docs/tutorial.step_4.ngdoc deleted file mode 100755 index de98eb34..00000000 --- a/docs/tutorial.step_4.ngdoc +++ /dev/null @@ -1,161 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 4 -@description - - - - - - - - -
    {@link tutorial.step_3 Previous}{@link http://angular.github.com/angular-phonecat/step-4/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-3...step-4 Code -Diff}{@link tutorial.step_5 Next}
    - -In this step, we add a feature that lets our users choose which way to order the phone list. - -__`app/index.html`:__ -
    -...
    -  
    -
    -  
    -...
    -
    - -__`app/js/controller.js`:__ -
    -/* App Controllers */
    -
    -function PhoneListCtrl() {
    -  this.phones = [{"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}];
    -
    -  this.orderProp = 'age';
    -}
    -
    - -__`test/unit/controllerSpec.js`:__ -
    -/* jasmine specs for controllers go here */
    -describe('PhoneCat controllers', function() {
    -
    -  describe('PhoneListCtrl', function(){
    -    var scope, $browser, ctrl;
    -
    -    beforeEach(function() {
    -      ctrl = new PhoneListCtrl();
    -    });
    -
    -
    -    it('should create "phones" model with 3 phones', function() {
    -      expect(ctrl.phones.length).toBe(3);
    -    });
    -
    -
    -    it('should set the default value of orderProp model', function() {
    -      expect(ctrl.orderProp).toBe('age');
    -    });
    -  });
    -});
    -
    - -__`test/e2e/scenarios.js`:__ -
    -/* jasmine-like end2end tests go here */
    -describe('PhoneCat App', function() {
    -
    -  describe('Phone list view', function() {
    -
    -    beforeEach(function() {
    -      browser().navigateTo('../../app/index.html');
    -    });
    -
    -
    -    it('should filter the phone list as user types into the search box', function() {
    -      expect(repeater('.phones li').count()).toBe(3);
    -
    -      input('query').enter('nexus');
    -      expect(repeater('.phones li').count()).toBe(1);
    -
    -      input('query').enter('motorola');
    -      expect(repeater('.phones li').count()).toBe(2);
    -    });
    -
    -
    -    it('should be possible to control phone order via the drop down select box', function() {
    -      input('query').enter('tablet'); //let's narrow the dataset to make the test assertions
    -      shorter
    -
    -      expect(repeater('.phones li', 'Phone List').column('a')).
    -          toEqual(["Motorola XOOM\u2122 with Wi-Fi",
    -                   "MOTOROLA XOOM\u2122"]);
    -
    -      select('orderProp').option('alphabetical');
    -
    -      expect(repeater('.phones li', 'Phone List').column('a')).
    -          toEqual(["MOTOROLA XOOM\u2122",
    -                   "Motorola XOOM\u2122 with Wi-Fi"]);
    -    });
    -  });
    -});
    -
    - -## Discussion: - -To provide dynamic ordering, we employ another one of angular's "array type augmenters" and let -the data binding do the rest of the work for us: - -* First, we provide a ` -
  • -
  • - Sort by: - -
  • - - - -... - - -__`app/js/controller.js`__ (Unchanged): -
    -/* App Controllers */
    -
    -function PhoneListCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/phones.json', function(code, response) {
    -    self.phones = response;
    -  });
    -
    -  self.orderProp = 'age';
    -}
    -
    -//PhoneListCtrl.$inject = ['$xhr'];
    -
    - -__`app/phones/phones.json`__ (sample snippet): -
    - [
    -  {
    -   "age": 4, 
    -   ...
    -   "carrier": "T-Mobile", 
    -   "id": "motorola-defy-with-motoblur", 
    -   "imageUrl": "http://google.com/phone/image/small/640001", 
    -   "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", 
    -   "snippet": "Are you ready for everything life throws your way?"
    -  }, 
    -  …
    - ]
    -
    - -__`test/e2e/scenarios.js`__: -
    -...
    -    it('should render phone specific links', function() {
    -      input('query').enter('nexus');
    -      element('.phones li a').click();
    -      expect(browser().location().hash()).toBe('/phones/nexus-s');
    -    });
    -...
    -
    - -## Discussion: - -* Note that we're using {@link guide.expression angular expressions} enclosed in the now-familiar -{@link angular.markup double-curly brace markup} in the href attribute values. These represent -attribute bindings, and work the same way as the bindings we saw in previous steps. - -* Note also the use of the {@link angular.directive.ng:src ng:src} directive in the `` tag. -That directive prevents the browser from treating the angular `{{ exppression }}` markup -literally, as it would do if we tried to use markup in a regular `src` attribute. Use `ng:src` to -keep the browser from eagerly making an extra http request to an invalid location. - -* We expanded our end-to-end test to verify that the app is generating correct links to the phone -views we will implement in the upcoming steps. - - - - - - - - - -
    {@link tutorial.step_5 Previous}{@link http://angular.github.com/angular-phonecat/step-6/app Example}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-5...step-6 Code -Diff}{@link tutorial.step_7 Next}
    diff --git a/docs/tutorial.step_7.ngdoc b/docs/tutorial.step_7.ngdoc deleted file mode 100755 index aa4209a2..00000000 --- a/docs/tutorial.step_7.ngdoc +++ /dev/null @@ -1,181 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 7 -@description - - - - - - - - -
    {@link tutorial.step_6 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code -Diff}{@link tutorial.step_8 Next}
    - -Our app is slowly growing and becoming more complex. Up until now, the app provided our users with -just one view (the list of all phones), and all of our template code was located in the -`index.html` file. The next step in building our app is the addition of 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. - -Similarly as with templates, angular also allows for controllers and scopes managed by these -controllers to be nested. We are going to create a "root" controller called `PhoneCatCtrl`, which -will contain the declaration of routes for the application. - -Application routes in angular are declared via the {@link angular.service.$route $route} service. -This services 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, and Back and Forward browser navigation. - -We'll use the $route service to declare that our application consists of two different views: one -view presents the phone listing, and the other view presents the details for a particular phone. -Each view will have the template stored in a separate file in the `app/partials/` directory. -Similarly each view will have a controller associated with it. These will be stored in the -existing `app/js/controllers.js` file. - -The `$route` service is usually used in conjunction with the {@link 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. - -For now we are going to get all the routing going, and move the phone listing template into a -separate file. We'll save the implementation of the phone details View for the next step. - -__`app/index.html`:__ -
    -...
    -
    -
    -  
    -
    -  
    -  
    -
    -
    -
    - -__`app/partials/phone-list.html`:__ -
    -
    -
    -
    -
    - -__`app/partials/phone-list.html`:__ -
    -TBD: detail view for {{params.phoneId}}
    -
    - -__`app/js/controller.js`:__ -
    -/* App Controllers */
    -
    -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'];
    -
    -
    -function PhoneListCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/phones.json', function(code, response) {
    -    self.phones = response;
    -  });
    -
    -  self.orderProp = 'age';
    -}
    -
    -//PhoneListCtrl.$inject = ['$xhr'];
    -
    -
    -function PhoneDetailCtrl() {}
    -
    - -## Discussion: - -* __The View.__ Our View template in `index.html` has been reduced down to this: -``. As described above, it is now a "layout template". We added the following -two new View templates: - - * `app/partials/phone-list.html` for the phone list. The phone-list view was formerly our - main view. We simply moved the code from `index.html` to here. - - * `app/partials/phone-detail.html` for the phone details (just a placeholder template for now). - -* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two -sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`). These inherit the model properties and -behavior from the root controller. - - * __`$route.`__ The root controller's job now is to set up the `$route` configuration: - - * When the fragment part of the URL in the browser ends in "/phones", `$route` service - grabs the `phone-list.html` template, compiles it, and links it with a new scope that is - controlled by our `PhoneListCtrl` controller. - - * When the URL ends in "/phones/:phoneId", `$route` compiles and links the - `phone-detail.html` template as it did with `phone-list.html`. But note the use of the - `:phoneId` parameter declaration in the `path` argument of `$route.when()`: `$route` - services provides all the values for variables defined in this way as - `$route.current.params` map. In our route, `$route.current.params.phoneId` always holds - the current contents of the `:phoneId` portion of the URL. We will use the `phoneId` - parameter when we fetch the phone details in Step 8. - - * Any other URL fragment gets redirected to `/phones`. - - * __Controller/Scope inheritance.__ In the function passed into `$route`'s `onChange()` - method, we copied url parameters extracted from the current route to the `params` property in - the root scope. This property is inherited by child scopes created for our view controllers - and accessible by these controllers. - - * __Tests.__ To automatically verify that everything is wired properly, we write end to end - tests that navigate to various URLs and verify that the correct view was rendered. - - - - - - - - - -
    {@link tutorial.step_6 Previous}{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code -Diff}{@link tutorial.step_8 Next}
    diff --git a/docs/tutorial.step_8.ngdoc b/docs/tutorial.step_8.ngdoc deleted file mode 100755 index ad967085..00000000 --- a/docs/tutorial.step_8.ngdoc +++ /dev/null @@ -1,148 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 8 -@description - - - - - - - - -
    {@link tutorial.step_7 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code -Diff}{@link tutorial.step_9 Next}
    - -In this step, we implement the Phone Details View template. Once again we will use {@link -angular.services.$xhr $xhr} to fetch our data, and we'll flesh out the `phone-details.html` View -template. - -__`app/partials/phone-details.html`:__ -
    -
    -
    -

    {{phone.name}}

    - -

    {{phone.description}}

    - - - - -
    - -__`app/js/controller.js`:__ -
    -function PhoneCatCtrl($route) (same as Step 7)
    -
    -function PhoneListCtrl($xhr) (same as Step 7)
    -
    -function PhoneDetailCtrl($xhr) {
    -  var self = this;
    -
    -  $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
    -    self.phone = response;
    -  });
    -}
    -
    -//PhoneDetailCtrl.$inject = ['$xhr'];
    -
    - -__`app/phones/nexus-s.json`:__ (sample snippet) -
    -{
    -  "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope,
    -  Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", 
    -  "android": {
    -      "os": "Android 2.3", 
    -      "ui": "Android"
    -  }, 
    -  ...
    -  "images": [
    -      "img/phones/nexus-s.0.jpg", 
    -      "img/phones/nexus-s.1.jpg", 
    -      "img/phones/nexus-s.2.jpg", 
    -      "img/phones/nexus-s.3.jpg"
    -  ], 
    -  "storage": {
    -      "flash": "16384MB", 
    -      "ram": "512MB"
    -  }
    -}
    -
    - -__`test/unit/controllerSpec.js`:__ -
    -...
    -    it('should fetch phone detail', function(){
    -      scope.params = {phoneId:'xyz'};
    -      $browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
    -      ctrl = scope.$new(PhoneDetailCtrl);
    -
    -      expect(ctrl.phone).toBeUndefined();
    -      $browser.xhr.flush();
    -
    -      expect(ctrl.phone).toEqual({name:'phone xyz'});
    -    });
    -...
    -
    - -__`test/e2e/scenarios.js`:__ -
    -...
    -  describe('Phone detail view', function() {
    -
    -    beforeEach(function() {
    -      browser().navigateTo('../../app/index.html#/phones/nexus-s');
    -    });
    -
    -
    -    it('should display nexus-s page', function() {
    -      expect(binding('phone.name')).toBe('Nexus S');
    -    });
    -  });
    -...
    -
    - -## Discussion: - -* Phone Details View Template. There is nothing fancy or new here, just note where we use the -angular `{{ expression }}` markup and directives to project phone data from our model into the -view. - -* Note how we used the `$route` `params` object from the scope managed by the root controller -(`PhoneCatCtrl`), to construct the path for the phone details xhr request. The rest of this step -is simply applying the previously learned concepts and angular APIs to create a large template -that displays a lot of data about a phone. - -* Tests. We updated the existing end to end test and wrote a new unit test that is similar in -spirit to the one we wrote for the `PhoneListCtrl` controller. - - - - - - - - - -
    {@link tutorial.step_7 Previous}{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code -Diff}{@link tutorial.step_9 Next}
    diff --git a/docs/tutorial.step_9.ngdoc b/docs/tutorial.step_9.ngdoc deleted file mode 100755 index 36b60e30..00000000 --- a/docs/tutorial.step_9.ngdoc +++ /dev/null @@ -1,108 +0,0 @@ -@workInProgress -@ngdoc overview -@name Tutorial: Step 9 -@description - - - - - - - - -
    {@link tutorial.step_8 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code -Diff}{@link tutorial.step_10 Next}
    - -In this step, we have determined that the built-in angular display filters ({@link -angular.filter.number number}, {@link angular.filter.currency currency}, {@link -angular.filter.date date}, etc.) don't handle what we want to do, so we get to create our own -custom {@link angular.filter filter}. - -In the previous step, the details page displayed either "true" or "false" to indicate whether -certain phone features were present or not. Our custom "checkmark" filter replaces those text -strings with glyphs: ✓ for "true", and ✘ for "false". - -Our filter code lives in `app/js/filters.js`: - -__`app/index.html`:__ -
    -...
    - 
    - 
    - 
    -...
    -
    - -In the phone details template, we employ our filter for angular expressions whose values are -"true" or "false"; `{{ [phone_feature] | checkmark }}`: - -__`app/partials/phone-detail.html`:__ -
    -
    -

    {{phone.name}}

    -

    {{phone.description}}

    -... - -
    - -__`app/js/filters.js`:__ (New) -
    -angular.filter('checkmark', function(input) {
    -  return input ? '\u2713' : '\u2718';
    -});
    -
    - -__`test/unit/filtersSpec.js`:__ (New) -
    -describe('checkmark filter', function() {
    -
    -  it('should convert boolean values to unicode checkmark or cross', function() {
    -    expect(angular.filter.checkmark(true)).toBe('\u2713');
    -    expect(angular.filter.checkmark(false)).toBe('\u2718');
    -  });
    -})
    -
    - -## Discussion: - -* This example shows how easy it is to roll your own filters for displaying data. As explained in -the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you -simply register your custom filter function on to the `angular.filter` function. - -* In this example, our filter name is "checkmark"; our input is either "true" or "false", and we -return one of two unicode characters we have chosen to represent true or false (`\u2713` and -`\u2718`). - -* We created a new unit test to verify that our custom filter converts boolean values to unicode -characters. - - - - - - - - - -
    {@link tutorial.step_8 Previous}{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo -}{@link tutorial Tutorial Home}{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code -Diff}{@link tutorial.step_10 Next}
    -- cgit v1.2.3