diff --git a/docs/content/tutorial/index.ngdoc b/docs/content/tutorial/index.ngdoc
index f96c0a2ad5e0..19e2d4741bb1 100644
--- a/docs/content/tutorial/index.ngdoc
+++ b/docs/content/tutorial/index.ngdoc
@@ -29,9 +29,10 @@ When you finish the tutorial you will be able to:
* Use data binding to wire up your data model to your views.
* Create and run unit tests, with Karma.
* Create and run end to end tests, with Protractor.
-* Move application logic out of the template and into Controllers.
+* Move application logic out of the template and into components and controllers.
* Get data from a server using Angular services.
* Apply animations to your application, using ngAnimate.
+* Organize your application code for larger projects.
* Identify resources for learning more about AngularJS.
The tutorial guides you through the entire process of building a simple application, including
diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc
index 624bbc322e6e..ec1d5122de88 100644
--- a/docs/content/tutorial/step_02.ngdoc
+++ b/docs/content/tutorial/step_02.ngdoc
@@ -7,12 +7,12 @@
Now it's time to make the web page dynamic — with AngularJS. We'll also add a test that verifies the
-code for the controller we are going to add.
+code for the component we are going to add.
There are many ways to structure the code for an application. For Angular apps, we encourage the use of
[the Model-View-Controller (MVC) design pattern](http://en.wikipedia.org/wiki/Model–View–Controller)
to decouple the code and to separate concerns. With that in mind, let's use a little Angular and
-JavaScript to add model, view, and controller components to our app.
+JavaScript to add models, views, and controllers to our app.
- The list of three phones is now generated dynamically from data
@@ -25,67 +25,69 @@ In Angular, the __view__ is a projection of the model through the HTML __templat
whenever the model changes, Angular refreshes the appropriate binding points, which updates the
view.
-The view component is constructed by Angular from this template:
+The view is constructed by Angular from this template.
-__`app/index.html`:__
+__`app/partials/phone-list.html`:__
```html
-
-
- ...
-
-
-
-
-
-
-
- {{phone.name}}
-
{{phone.snippet}}
-
-
-
-
-
+
+
+ {{phone.name}}
+
{{phone.snippet}}
+
+
```
-We replaced the hard-coded phone list with the {@link ng.directive:ngRepeat ngRepeat directive}
+Instead of a hard-coded phone list we've used the {@link ng.directive:ngRepeat ngRepeat directive}
and two {@link guide/expression Angular expressions}:
-* The `ng-repeat="phone in phones"` attribute in the `
` tag is an Angular repeater directive.
+* The `ng-repeat="phone in $ctrl.phones"` attribute in the `
` tag is an Angular repeater directive.
The repeater tells Angular to create a `
` element for each phone in the list using the `
`
tag as the template.
* The expressions wrapped in curly braces (`{{phone.name}}` and `{{phone.snippet}}`) will be replaced
-by the value of the expressions.
+by the value of the expressions. The expressions denote bindings that refer to our application model,
+which is set up in our controller.
-We have added a new directive, called `ng-controller`, which attaches a `PhoneListCtrl`
-__controller__ to the <body> tag. At this point:
+In `index.html` we no longer have the hard-coded phone list. Instead we are using a ``
+component element:
-* The expressions in curly braces (`{{phone.name}}` and `{{phone.snippet}}`) denote
-bindings, which are referring to our application model, which is set up in our `PhoneListCtrl`
-controller.
+__`app/index.html`:__
+
+```html
+
+
+ ...
+
+
+
+
+
+
+
+```
Note: We have specified an {@link angular.Module Angular Module} to load using `ng-app="phonecatApp"`,
-where `phonecatApp` is the name of our module. This module will contain the `PhoneListCtrl`.
+where `phonecatApp` is the name of our module. This module will contain the phone list component.
-
-
-## Model and Controller
+## Component, Model, and Controller
The data __model__ (a simple array of phones in object literal notation) is now instantiated within
-the `PhoneListCtrl` __controller__. The __controller__ is simply a constructor function that takes a
-`$scope` parameter:
+the `PhoneListCtrl` __controller__. The __controller__ is simply a constructor function. It is used
+by the `phoneList` component:
-__`app/js/controllers.js`:__
+__`app/js/components.js`:__
```js
var phonecatApp = angular.module('phonecatApp', []);
-phonecatApp.controller('PhoneListCtrl', function ($scope) {
- $scope.phones = [
+phonecatApp.component('phoneList', {
+ controller: 'PhoneListCtrl',
+ templateUrl: 'partials/phone-list.html'
+}).controller('PhoneListCtrl', function() {
+ this.phones = [
{'name': 'Nexus S',
'snippet': 'Fast just got faster with Nexus S.'},
{'name': 'Motorola XOOM™ with Wi-Fi',
@@ -97,40 +99,42 @@ phonecatApp.controller('PhoneListCtrl', function ($scope) {
```
-Here we declared a controller called `PhoneListCtrl` and registered it in an AngularJS
-module, `phonecatApp`. Notice that our `ng-app` directive (on the `` tag) now specifies the `phonecatApp`
-module name as the module to load when bootstrapping the Angular application.
+Here we declared a component called `phoneList` and a controller called `PhoneListCtrl`
+and registered both in an AngularJS module, `phonecatApp`. Notice that our `ng-app` directive
+(on the `` tag) now specifies the same `phonecatApp` module name as the module to load
+when bootstrapping the Angular application.
Although the controller is not yet doing very much, it plays a crucial role. By providing context
for our data model, the controller allows us to establish data-binding between
-the model and the view. We connected the dots between the presentation, data, and logic components
+the model and the view. We connected the dots between the presentation, data, and logic
as follows:
-* The {@link ng.directive:ngController ngController} directive, located on the `` tag,
-references the name of our controller, `PhoneListCtrl` (located in the JavaScript file
-`controllers.js`).
+* The `` element, located on the `` tag, creates a
+ `phoneList` component (located in the JavaScript file `components.js`).
-* The `PhoneListCtrl` controller attaches the phone data to the `$scope` that was injected into our
-controller function. This *scope* is a prototypical descendant of the *root scope* that was created
-when the application was defined. This controller scope is available to all bindings located within
-the `` tag.
+* The `phoneList` component creates an internal view from the `phone-list.html` template
+ and creates an instance of the controller `PhoneListCtrl`.
+
+* The `PhoneListCtrl` controller attaches the phone data to an attribute on itself. This controller
+ is available through the `$ctrl` alias to all bindings located within `phone-list.html` component
+ template.
### Scope
-The concept of a scope in Angular is crucial. A scope can be seen as the glue which allows the
-template, model and controller to work together. Angular uses scopes, along with the information
-contained in the template, data model, and controller, to keep models and views separate, but in
-sync. Any changes made to the model are reflected in the view; any changes that occur in the view
-are reflected in the model.
+Behind the scenes, Angular creates a **scope** for the component and uses it to bridge the component's controller and template together.
+
+Angular uses scopes, along with the information contained in the template, data model, and controller,
+to keep models and views separate, but in sync. Any changes made to the model are reflected in the view;
+any changes that occur in the view are reflected in the model.
To learn more about Angular scopes, see the {@link ng.$rootScope.Scope angular scope documentation}.
+
## Tests
The "Angular way" of separating controller from the view, makes it easy to test code as it is being
-developed. If our controller is available on the global namespace then we could simply instantiate it
-with a mock `scope` object:
+developed. If our controller is available on the global namespace then we could simply instantiate it:
__`test/e2e/scenarios.js`:__
@@ -138,16 +142,15 @@ __`test/e2e/scenarios.js`:__
describe('PhoneListCtrl', function(){
it('should create "phones" model with 3 phones', function() {
- var scope = {},
- ctrl = new PhoneListCtrl(scope);
+ var ctrl = new PhoneListCtrl();
- expect(scope.phones.length).toBe(3);
+ expect(ctrl.phones.length).toBe(3);
});
});
```
-The test instantiates `PhoneListCtrl` and verifies that the phones array property on the scope
+The test instantiates `PhoneListCtrl` and verifies that the phones array property on it
contains three records. This example demonstrates how easy it is to create a unit test for code in
Angular. Since testing is such a critical part of software development, we make it easy to create
tests in Angular so that developers are encouraged to write them.
@@ -169,10 +172,9 @@ describe('PhoneListCtrl', function(){
beforeEach(module('phonecatApp'));
it('should create "phones" model with 3 phones', inject(function($controller) {
- var scope = {},
- ctrl = $controller('PhoneListCtrl', {$scope:scope});
+ var ctrl = $controller('PhoneListCtrl');
- expect(scope.phones.length).toBe(3);
+ expect(ctrl.phones.length).toBe(3);
}));
});
@@ -181,14 +183,14 @@ describe('PhoneListCtrl', function(){
* Before each test we tell Angular to load the `phonecatApp` module.
* We ask Angular to `inject` the `$controller` service into our test function
* We use `$controller` to create an instance of the `PhoneListCtrl`
-* With this instance, we verify that the phones array property on the scope contains three records.
+* With this instance, we verify that the phones array property on it contains three records.
### Writing and Running Tests
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
-this tutorial in Jasmine v1.3. You can learn about Jasmine on the [Jasmine home page][jasmine] and
+this tutorial in Jasmine v2.4. You can learn about Jasmine on the [Jasmine home page][jasmine] and
at the [Jasmine docs][jasmine-docs].
The angular-seed project is pre-configured to run unit tests using [Karma][karma] but you will need
@@ -230,25 +232,25 @@ browser is limited, which results in your karma tests running extremely slow.
# Experiments
-* Add another binding to `index.html`. For example:
+* Add another binding to `phone-list.html`. For example:
```html
-
Total number of phones: {{phones.length}}
+
Total number of phones: {{ctrl.phones.length}}
```
* Create a new model property in the controller and bind to it from the template. For example:
- $scope.name = "World";
+ this.name = "World";
- Then add a new binding to `index.html`:
+ Then add a new binding to `phone-list.html`:
-
Hello, {{name}}!
+
Hello, {{ctrl.name}}!
Refresh your browser and verify that it says "Hello, World!".
* Update the unit test for the controller in `./test/unit/controllersSpec.js` to reflect the previous change. For example by adding:
- expect(scope.name).toBe('World');
+ expect(ctrl.name).toBe('World');
* Create a repeater in `index.html` that constructs a simple table:
@@ -266,12 +268,12 @@ browser is limited, which results in your karma tests running extremely slow.
Extra points: try and make an 8x8 table using an additional `ng-repeat`.
-* Make the unit test fail by changing `expect(scope.phones.length).toBe(3)` to instead use `toBe(4)`.
+* Make the unit test fail by changing `expect(ctrl.phones.length).toBe(3)` to instead use `toBe(4)`.
# Summary
-You now have a dynamic app that features separate model, view, and controller components, and you
+You now have a dynamic app that features separate models, views, and controllers, and you
are testing as you go. Now, let's go to {@link step_03 step 3} to learn how to add full text search
to the app.
@@ -279,5 +281,5 @@ to the app.
[jasmine]: http://jasmine.github.io/
-[jasmine-docs]: http://jasmine.github.io/1.3/introduction.html
+[jasmine-docs]: http://jasmine.github.io/2.4/introduction.html
[karma]: http://karma-runner.github.io/
diff --git a/docs/content/tutorial/step_03.ngdoc b/docs/content/tutorial/step_03.ngdoc
index 4025b520db2e..5e071142e5bd 100644
--- a/docs/content/tutorial/step_03.ngdoc
+++ b/docs/content/tutorial/step_03.ngdoc
@@ -17,14 +17,14 @@ user types into the search box.
-## Controller
+## Component and Controller
-We made no changes to the controller.
+We made no changes to the component or controller.
## Template
-__`app/index.html`:__
+__`app/partials/phone-list.html`:__
```html
@@ -32,14 +32,14 @@ __`app/index.html`:__
- Search:
+ Search:
-
+
{{phone.name}}
{{phone.snippet}}
@@ -60,15 +60,15 @@ list. This new code demonstrates the following:
* 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 code, the data that a user types into the input box (named __`query`__) is immediately
-available as a filter input in the list repeater (`phone in phones | filter:`__`query`__). When
+ In this code, the data that a user types into the input box (named __`$ctrl.query`__) is immediately
+available as a filter input in the list repeater (`phone in $ctrl.phones | filter:`__`$ctrl.query`__). When
changes to the data model cause the repeater's input to change, the repeater efficiently updates
the DOM to reflect the current state of the model.
* Use of the `filter` filter: The {@link ng.filter:filter filter} function uses the
-`query` value to create a new array that contains only those records that match the `query`.
+`$ctrl.query` value to create a new array that contains only those records that match the query.
`ngRepeat` automatically updates the view in response to the changing number of phones returned
by the `filter` filter. The process is completely transparent to the developer.
@@ -76,7 +76,7 @@ by the `filter` filter. The process is completely transparent to the developer.
## Test
In Step 2, we learned how to write and run unit tests. Unit tests are perfect for testing
-controllers and other components of our application written in JavaScript, but they can't easily
+controllers and other parts of our application written in JavaScript, but they can't easily
test DOM manipulation or the wiring of our application. For these, an end-to-end test is a much
better choice.
@@ -97,8 +97,8 @@ describe('PhoneCat App', function() {
it('should filter the phone list as a user types into the search box', function() {
- var phoneList = element.all(by.repeater('phone in phones'));
- var query = element(by.model('query'));
+ var phoneList = element.all(by.repeater('phone in $ctrl.phones'));
+ var query = element(by.model('$ctrl.query'));
expect(phoneList.count()).toBe(3);
@@ -139,79 +139,12 @@ To rerun the test suite, execute `npm run protractor` again.
# Experiments
### Display Current Query
-Display the current value of the `query` model by adding a `{{query}}` binding into the
-`index.html` template, and see how it changes when you type in the input box.
-
-### Display Query in Title
-Let's see how we can get the current value of the `query` model to appear in the HTML page title.
-
-* Add an end-to-end test into the `describe` block, `test/e2e/scenarios.js` should look like this:
-
- ```js
- describe('PhoneCat App', function() {
-
- describe('Phone list view', function() {
-
- beforeEach(function() {
- browser.get('app/index.html');
- });
-
- var phoneList = element.all(by.repeater('phone in phones'));
- var query = element(by.model('query'));
-
- it('should filter the phone list as a user types into the search box', function() {
- expect(phoneList.count()).toBe(3);
-
- query.sendKeys('nexus');
- expect(phoneList.count()).toBe(1);
-
- query.clear();
- query.sendKeys('motorola');
- expect(phoneList.count()).toBe(2);
- });
-
- it('should display the current filter value in the title bar', function() {
- query.clear();
- expect(browser.getTitle()).toMatch(/Google Phone Gallery:\s*$/);
-
- query.sendKeys('nexus');
- expect(browser.getTitle()).toMatch(/Google Phone Gallery: nexus$/);
- });
- });
- });
- ```
-
- Run protractor (`npm run protractor`) to see this test fail.
-
-
-* You might think you could just add the `{{query}}` to the title tag element as follows:
-
- Google Phone Gallery: {{query}}
-
- However, when you reload the page, you won't see the expected result. This is because the "query"
- model lives in the scope, defined by the `ng-controller="PhoneListCtrl"` directive, on the body
- element:
-
-
-
- If you want to bind to the query model from the `` element, you must __move__ the
- `ngController` declaration to the HTML element because it is the common parent of both the body
- and title elements:
-
-
-
- Be sure to __remove__ the `ng-controller` declaration from the body element.
-
-* Re-run `npm run protractor` to see the test now pass.
-
-* While using double curlies works fine within the title element, you might have noticed that
-for a split second they are actually displayed to the user while the page is loading. A better
-solution would be to use the {@link ng.directive:ngBind ngBind} or
-{@link ng.directive:ngBindTemplate ngBindTemplate} directives, which are invisible to the user
-while the page is loading:
-
- Google Phone Gallery
+Display the current value of the `query` model by adding a `{{$ctrl.query}}` binding into the
+`phone-list.html` template, and see how it changes when you type in the input box.
+You might also try to add the `{{$ctrl.query}}` to the `index.html` template. However,
+when you reload the page, you won't see the expected result. This is because the "query"
+model lives in the scope defined by the `` component.
# Summary
@@ -220,4 +153,3 @@ to {@link step_04 step 4} to learn how to add sorting capability to the phone ap
-
diff --git a/docs/content/tutorial/step_04.ngdoc b/docs/content/tutorial/step_04.ngdoc
index 2a041030f2ad..9b2f9a7555b4 100644
--- a/docs/content/tutorial/step_04.ngdoc
+++ b/docs/content/tutorial/step_04.ngdoc
@@ -19,28 +19,28 @@ the repeater, and letting the data binding magic do the rest of the work.
## Template
-__`app/index.html`:__
+__`app/partials/phone-list.html`:__
```html
- Search:
+ Search:
Sort by:
-