mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-20 04:11:51 +00:00
docs - stripping extra new lines
This commit is contained in:
parent
d428c9910e
commit
b842642b57
75 changed files with 3 additions and 1723 deletions
|
|
@ -3,11 +3,9 @@
|
||||||
@name angular.service
|
@name angular.service
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
The services API provides objects for carrying out common web app tasks. Service objects are
|
The services API provides objects for carrying out common web app tasks. Service objects are
|
||||||
managed by angular's {@link guide/dev_guide.di dependency injection system}.
|
managed by angular's {@link guide/dev_guide.di dependency injection system}.
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.service.$browser $browser } - Provides an instance of a browser object
|
* {@link angular.service.$browser $browser } - Provides an instance of a browser object
|
||||||
* {@link angular.service.$cookieStore $cookieStore } - Provides key / value storage backed by
|
* {@link angular.service.$cookieStore $cookieStore } - Provides key / value storage backed by
|
||||||
session cookies
|
session cookies
|
||||||
|
|
@ -27,6 +25,5 @@ server-side data sources
|
||||||
* {@link angular.service.$window $window } - References the browsers `window` object
|
* {@link angular.service.$window $window } - References the browsers `window` object
|
||||||
* {@link angular.service.$xhr $xhr} - Generates an XHR request.
|
* {@link angular.service.$xhr $xhr} - Generates an XHR request.
|
||||||
|
|
||||||
|
|
||||||
For information on how angular services work and how to write your own services, see {@link
|
For information on how angular services work and how to write your own services, see {@link
|
||||||
guide/dev_guide.services Angular Services} in the angular Developer Guide.
|
guide/dev_guide.services Angular Services} in the angular Developer Guide.
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,8 @@
|
||||||
@name API Reference
|
@name API Reference
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
## Angular Compiler API
|
## Angular Compiler API
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.widget Widgets} - Angular custom DOM element
|
* {@link angular.widget Widgets} - Angular custom DOM element
|
||||||
* {@link angular.directive Directives} - Angular DOM element attributes
|
* {@link angular.directive Directives} - Angular DOM element attributes
|
||||||
* {@link angular.markup Markup} and {@link angular.attrMarkup Attribute Markup}
|
* {@link angular.markup Markup} and {@link angular.attrMarkup Attribute Markup}
|
||||||
|
|
@ -14,47 +12,33 @@
|
||||||
* {@link angular.validator Validators} - Angular input validators
|
* {@link angular.validator Validators} - Angular input validators
|
||||||
* {@link angular.compile angular.compile()} - Template compiler
|
* {@link angular.compile angular.compile()} - Template compiler
|
||||||
|
|
||||||
|
|
||||||
## Angular Scope API
|
## Angular Scope API
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.scope Scope Object} - Angular scope object
|
* {@link angular.scope Scope Object} - Angular scope object
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Angular Services & Dependency Injection API
|
## Angular Services & Dependency Injection API
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.service Angular Services}
|
* {@link angular.service Angular Services}
|
||||||
* {@link angular.injector angular.injector() }
|
* {@link angular.injector angular.injector() }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Angular Testing API
|
## Angular Testing API
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.mock Testing Mocks API} - Mock objects for testing
|
* {@link angular.mock Testing Mocks API} - Mock objects for testing
|
||||||
* {@link
|
* {@link
|
||||||
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en_US
|
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en_US
|
||||||
Angular Scenario Runner} - Automated scenario testing documentation
|
Angular Scenario Runner} - Automated scenario testing documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Angular Utility Functions
|
## Angular Utility Functions
|
||||||
|
|
||||||
|
|
||||||
### HTML & DOM Manipulation
|
### HTML & DOM Manipulation
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.element angular.element()}
|
* {@link angular.element angular.element()}
|
||||||
|
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.bind angular.bind() }
|
* {@link angular.bind angular.bind() }
|
||||||
* {@link angular.extend angular.extend() }
|
* {@link angular.extend angular.extend() }
|
||||||
* {@link angular.forEach angular.forEach() }
|
* {@link angular.forEach angular.forEach() }
|
||||||
|
|
@ -62,11 +46,8 @@ Angular Scenario Runner} - Automated scenario testing documentation
|
||||||
* {@link angular.noop angular.noop() }
|
* {@link angular.noop angular.noop() }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Type Identification
|
## Type Identification
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.isArray angular.isArray() }
|
* {@link angular.isArray angular.isArray() }
|
||||||
* {@link angular.isDate angular.isDate() }
|
* {@link angular.isDate angular.isDate() }
|
||||||
* {@link angular.isDefined angular.isDefined() }
|
* {@link angular.isDefined angular.isDefined() }
|
||||||
|
|
@ -76,25 +57,18 @@ Angular Scenario Runner} - Automated scenario testing documentation
|
||||||
* {@link angular.isString angular.isString() }
|
* {@link angular.isString angular.isString() }
|
||||||
* {@link angular.isUndefined angular.isUndefined() }
|
* {@link angular.isUndefined angular.isUndefined() }
|
||||||
|
|
||||||
|
|
||||||
## Strings
|
## Strings
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.lowercase angular.lowercase() }
|
* {@link angular.lowercase angular.lowercase() }
|
||||||
* {@link angular.uppercase angular.uppercase() }
|
* {@link angular.uppercase angular.uppercase() }
|
||||||
|
|
||||||
|
|
||||||
### JSON
|
### JSON
|
||||||
|
|
||||||
|
|
||||||
* {@link angular.fromJson angular.fromJson() }
|
* {@link angular.fromJson angular.fromJson() }
|
||||||
* {@link angular.toJson angular.toJson() }
|
* {@link angular.toJson angular.toJson() }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Utility methods for JavaScript types
|
## Utility methods for JavaScript types
|
||||||
* {@link angular.Object Object API} - Utility functions for JavaScript objects
|
* {@link angular.Object Object API} - Utility functions for JavaScript objects
|
||||||
* {@link angular.Array Array API} - Utility functions for JavaScript arrays
|
* {@link angular.Array Array API} - Utility functions for JavaScript arrays
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
@name Cookbook: Advanced Form
|
@name Cookbook: Advanced Form
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Here we extend the basic form example to include common features such as reverting, dirty state
|
Here we extend the basic form example to include common features such as reverting, dirty state
|
||||||
detection, and preventing invalid form submission.
|
detection, and preventing invalid form submission.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -31,13 +29,11 @@ detection, and preventing invalid form submission.
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UserForm.prototype = {
|
UserForm.prototype = {
|
||||||
cancel: function(){
|
cancel: function(){
|
||||||
this.form = angular.copy(this.master);
|
this.form = angular.copy(this.master);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
save: function(){
|
save: function(){
|
||||||
this.master = this.form;
|
this.master = this.form;
|
||||||
this.cancel();
|
this.cancel();
|
||||||
|
|
@ -46,11 +42,9 @@ detection, and preventing invalid form submission.
|
||||||
</script>
|
</script>
|
||||||
<div ng:controller="UserForm">
|
<div ng:controller="UserForm">
|
||||||
|
|
||||||
|
|
||||||
<label>Name:</label><br/>
|
<label>Name:</label><br/>
|
||||||
<input type="text" name="form.name" ng:required/> <br/><br/>
|
<input type="text" name="form.name" ng:required/> <br/><br/>
|
||||||
|
|
||||||
|
|
||||||
<label>Address:</label><br/>
|
<label>Address:</label><br/>
|
||||||
<input type="text" name="form.address.line1" size="33" ng:required/> <br/>
|
<input type="text" name="form.address.line1" size="33" ng:required/> <br/>
|
||||||
<input type="text" name="form.address.city" size="12" ng:required/>,
|
<input type="text" name="form.address.city" size="12" ng:required/>,
|
||||||
|
|
@ -58,7 +52,6 @@ detection, and preventing invalid form submission.
|
||||||
<input type="text" name="form.address.zip" size="5" ng:required
|
<input type="text" name="form.address.zip" size="5" ng:required
|
||||||
ng:validate="regexp:zip"/><br/><br/>
|
ng:validate="regexp:zip"/><br/><br/>
|
||||||
|
|
||||||
|
|
||||||
<label>Contacts:</label>
|
<label>Contacts:</label>
|
||||||
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
|
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
|
||||||
<div ng:repeat="contact in form.contacts">
|
<div ng:repeat="contact in form.contacts">
|
||||||
|
|
@ -75,7 +68,6 @@ ng:validate="regexp:zip"/><br/><br/>
|
||||||
<button ng:click="save()" ng:disabled="{{$invalidWidgets.visible() ||
|
<button ng:click="save()" ng:disabled="{{$invalidWidgets.visible() ||
|
||||||
master.$equals(form)}}">Save</button>
|
master.$equals(form)}}">Save</button>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
Debug View:
|
Debug View:
|
||||||
<pre>form={{form}}
|
<pre>form={{form}}
|
||||||
|
|
@ -104,11 +96,8 @@ master.$equals(form)}}">Save</button>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#Things to notice
|
#Things to notice
|
||||||
|
|
||||||
|
|
||||||
* Cancel & save buttons are only enabled if the form is dirty — there is something to cancel or
|
* Cancel & save buttons are only enabled if the form is dirty — there is something to cancel or
|
||||||
save.
|
save.
|
||||||
* Save button is only enabled if there are no validation errors on the form.
|
* Save button is only enabled if there are no validation errors on the form.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
@name Cookbook: Resources - Buzz
|
@name Cookbook: Resources - Buzz
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
External resources are URLs that provide JSON data, which are then rendered with the help of
|
External resources are URLs that provide JSON data, which are then rendered with the help of
|
||||||
templates. angular has a resource factory that can be used to give names to the URLs and then
|
templates. angular has a resource factory that can be used to give names to the URLs and then
|
||||||
attach behavior to them. For example you can use the
|
attach behavior to them. For example you can use the
|
||||||
|
|
@ -11,7 +10,6 @@ attach behavior to them. For example you can use the
|
||||||
API}
|
API}
|
||||||
to retrieve Buzz activity and comments.
|
to retrieve Buzz activity and comments.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,14 @@
|
||||||
@name Cookbook: Deep Linking
|
@name Cookbook: Deep Linking
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Deep linking allows you to encode the state of the application in the URL so that it can be
|
Deep linking allows you to encode the state of the application in the URL so that it can be
|
||||||
bookmarked and the application can be restored from the URL to the same state.
|
bookmarked and the application can be restored from the URL to the same state.
|
||||||
|
|
||||||
|
|
||||||
While <angular/> does not force you to deal with bookmarks in any particular way, it has services
|
While <angular/> does not force you to deal with bookmarks in any particular way, it has services
|
||||||
which make the common case described here very easy to implement.
|
which make the common case described here very easy to implement.
|
||||||
|
|
||||||
|
|
||||||
# Assumptions
|
# Assumptions
|
||||||
|
|
||||||
|
|
||||||
Your application consists of a single HTML page which bootstraps the application. We will refer
|
Your application consists of a single HTML page which bootstraps the application. We will refer
|
||||||
to this page as the chrome.
|
to this page as the chrome.
|
||||||
Your application is divided into several screens (or views) which the user can visit. For example,
|
Your application is divided into several screens (or views) which the user can visit. For example,
|
||||||
|
|
@ -25,30 +21,22 @@ screen will be constructed from an HTML snippet, which we will refer to as the p
|
||||||
have multiple partials, but a single partial is the most common construct. This example makes the
|
have multiple partials, but a single partial is the most common construct. This example makes the
|
||||||
partial boundary visible using a blue line.
|
partial boundary visible using a blue line.
|
||||||
|
|
||||||
|
|
||||||
You can make a routing table which shows which URL maps to which partial view template and which
|
You can make a routing table which shows which URL maps to which partial view template and which
|
||||||
controller.
|
controller.
|
||||||
|
|
||||||
|
|
||||||
# Example
|
# Example
|
||||||
|
|
||||||
|
|
||||||
In this example we have a simple app which consist of two screens:
|
In this example we have a simple app which consist of two screens:
|
||||||
|
|
||||||
|
|
||||||
* Welcome: url `#` Show the user contact information.
|
* Welcome: url `#` Show the user contact information.
|
||||||
* Settings: url `#/settings` Show an edit screen for user contact information.
|
* Settings: url `#/settings` Show an edit screen for user contact information.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The two partials are defined in the following URLs:
|
The two partials are defined in the following URLs:
|
||||||
|
|
||||||
|
|
||||||
* {@link ./examples/settings.html}
|
* {@link ./examples/settings.html}
|
||||||
* {@link ./examples/welcome.html}
|
* {@link ./examples/welcome.html}
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -59,7 +47,6 @@ The two partials are defined in the following URLs:
|
||||||
$route.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
|
$route.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
|
||||||
$route.parent(this);
|
$route.parent(this);
|
||||||
|
|
||||||
|
|
||||||
// initialize the model to something useful
|
// initialize the model to something useful
|
||||||
this.person = {
|
this.person = {
|
||||||
name:'anonymous',
|
name:'anonymous',
|
||||||
|
|
@ -67,7 +54,6 @@ The two partials are defined in the following URLs:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function WelcomeCntl($route){}
|
function WelcomeCntl($route){}
|
||||||
WelcomeCntl.prototype = {
|
WelcomeCntl.prototype = {
|
||||||
greet: function(){
|
greet: function(){
|
||||||
|
|
@ -75,7 +61,6 @@ The two partials are defined in the following URLs:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function SettingsCntl(){
|
function SettingsCntl(){
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +69,6 @@ The two partials are defined in the following URLs:
|
||||||
this.form = angular.copy(this.person);
|
this.form = angular.copy(this.person);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
save: function(){
|
save: function(){
|
||||||
angular.copy(this.form, this.person);
|
angular.copy(this.form, this.person);
|
||||||
window.location.hash = "#";
|
window.location.hash = "#";
|
||||||
|
|
@ -117,12 +101,8 @@ The two partials are defined in the following URLs:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Things to notice
|
# Things to notice
|
||||||
|
|
||||||
|
|
||||||
* Routes are defined in the `AppCntl` class. The initialization of the controller causes the
|
* Routes are defined in the `AppCntl` class. The initialization of the controller causes the
|
||||||
initialization of the {@link api/angular.service.$route $route} service with the proper URL
|
initialization of the {@link api/angular.service.$route $route} service with the proper URL
|
||||||
routes.
|
routes.
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,11 @@
|
||||||
@name Cookbook: Form
|
@name Cookbook: Form
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
A web application's main purpose is to present and gather data. For this reason angular strives
|
A web application's main purpose is to present and gather data. For this reason angular strives
|
||||||
to make both of these operations trivial. This example shows off how you can build a simple form to
|
to make both of these operations trivial. This example shows off how you can build a simple form to
|
||||||
allow a user to enter data.
|
allow a user to enter data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -26,11 +23,9 @@ allow a user to enter data.
|
||||||
</script>
|
</script>
|
||||||
<div ng:controller="FormController" class="example">
|
<div ng:controller="FormController" class="example">
|
||||||
|
|
||||||
|
|
||||||
<label>Name:</label><br/>
|
<label>Name:</label><br/>
|
||||||
<input type="text" name="user.name" ng:required/> <br/><br/>
|
<input type="text" name="user.name" ng:required/> <br/><br/>
|
||||||
|
|
||||||
|
|
||||||
<label>Address:</label><br/>
|
<label>Address:</label><br/>
|
||||||
<input type="text" name="user.address.line1" size="33" ng:required/> <br/>
|
<input type="text" name="user.address.line1" size="33" ng:required/> <br/>
|
||||||
<input type="text" name="user.address.city" size="12" ng:required/>,
|
<input type="text" name="user.address.city" size="12" ng:required/>,
|
||||||
|
|
@ -38,7 +33,6 @@ allow a user to enter data.
|
||||||
<input type="text" name="user.address.zip" size="5" ng:required
|
<input type="text" name="user.address.zip" size="5" ng:required
|
||||||
ng:validate="regexp:zip"/><br/><br/>
|
ng:validate="regexp:zip"/><br/><br/>
|
||||||
|
|
||||||
|
|
||||||
<label>Phone:</label>
|
<label>Phone:</label>
|
||||||
[ <a href="" ng:click="user.contacts.$add()">add</a> ]
|
[ <a href="" ng:click="user.contacts.$add()">add</a> ]
|
||||||
<div ng:repeat="contact in user.contacts">
|
<div ng:repeat="contact in user.contacts">
|
||||||
|
|
@ -56,7 +50,6 @@ ng:validate="regexp:zip"/><br/><br/>
|
||||||
<pre>user={{user}}</pre>
|
<pre>user={{user}}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</doc:source>
|
</doc:source>
|
||||||
<doc:scenario>
|
<doc:scenario>
|
||||||
it('should show debug', function(){
|
it('should show debug', function(){
|
||||||
|
|
@ -69,13 +62,11 @@ ng:validate="regexp:zip"/><br/><br/>
|
||||||
expect(binding('user')).toMatch(/you@example.org/);
|
expect(binding('user')).toMatch(/you@example.org/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should remove contact', function(){
|
it('should remove contact', function(){
|
||||||
using('.example').element('a:contains(X)').click();
|
using('.example').element('a:contains(X)').click();
|
||||||
expect(binding('user')).not().toMatch(/\(234\) 555\-1212/);
|
expect(binding('user')).not().toMatch(/\(234\) 555\-1212/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should validate zip', function(){
|
it('should validate zip', function(){
|
||||||
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
|
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
|
||||||
.not().toMatch(/ng-validation-error/);
|
.not().toMatch(/ng-validation-error/);
|
||||||
|
|
@ -84,7 +75,6 @@ ng:validate="regexp:zip"/><br/><br/>
|
||||||
.toMatch(/ng-validation-error/);
|
.toMatch(/ng-validation-error/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should validate state', function(){
|
it('should validate state', function(){
|
||||||
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
|
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
|
||||||
.not().toMatch(/ng-validation-error/);
|
.not().toMatch(/ng-validation-error/);
|
||||||
|
|
@ -96,11 +86,8 @@ ng:validate="regexp:zip"/><br/><br/>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Things to notice
|
# Things to notice
|
||||||
|
|
||||||
|
|
||||||
* The user data model is initialized {@link api/angular.directive.ng:controller controller} and is
|
* The user data model is initialized {@link api/angular.directive.ng:controller controller} and is
|
||||||
available in
|
available in
|
||||||
the {@link api/angular.scope scope} with the initial data.
|
the {@link api/angular.scope scope} with the initial data.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
@name Cookbook: Hello World
|
@name Cookbook: Hello World
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
Your name: <input type="text" name="name" value="World"/>
|
Your name: <input type="text" name="name" value="World"/>
|
||||||
|
|
@ -19,13 +18,10 @@
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
# Things to notice
|
# Things to notice
|
||||||
|
|
||||||
|
|
||||||
Take a look through the source and note:
|
Take a look through the source and note:
|
||||||
|
|
||||||
|
|
||||||
* The script tag that {@link guide/dev_guide.bootstrap bootstraps} the angular environment.
|
* The script tag that {@link guide/dev_guide.bootstrap bootstraps} the angular environment.
|
||||||
* The text {@link api/angular.widget.HTML input widget} which is bound to the greeting name text.
|
* The text {@link api/angular.widget.HTML input widget} which is bound to the greeting name text.
|
||||||
* No need for listener registration and event firing on change events.
|
* No need for listener registration and event firing on change events.
|
||||||
|
|
|
||||||
|
|
@ -3,68 +3,48 @@
|
||||||
@name Cookbook
|
@name Cookbook
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Welcome to the angular cookbook. Here we will show you typical uses of angular by example.
|
Welcome to the angular cookbook. Here we will show you typical uses of angular by example.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Hello World
|
# Hello World
|
||||||
|
|
||||||
|
|
||||||
{@link helloworld Hello World}: The simplest possible application that demonstrates the
|
{@link helloworld Hello World}: The simplest possible application that demonstrates the
|
||||||
classic Hello World!
|
classic Hello World!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Basic Form
|
# Basic Form
|
||||||
|
|
||||||
|
|
||||||
{@link form Basic Form}: Displaying forms to the user for editing is the bread and butter
|
{@link form Basic Form}: Displaying forms to the user for editing is the bread and butter
|
||||||
of web applications. Angular makes forms easy through bidirectional data binding.
|
of web applications. Angular makes forms easy through bidirectional data binding.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Advanced Form
|
# Advanced Form
|
||||||
|
|
||||||
|
|
||||||
{@link advancedform Advanced Form}: Taking the form example to the next level and
|
{@link advancedform Advanced Form}: Taking the form example to the next level and
|
||||||
providing advanced features such as dirty detection, form reverting and submit disabling if
|
providing advanced features such as dirty detection, form reverting and submit disabling if
|
||||||
validation errors exist.
|
validation errors exist.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Model View Controller
|
# Model View Controller
|
||||||
|
|
||||||
|
|
||||||
{@link mvc MVC}: Tic-Tac-Toe: Model View Controller (MVC) is a time-tested design pattern
|
{@link mvc MVC}: Tic-Tac-Toe: Model View Controller (MVC) is a time-tested design pattern
|
||||||
to separate the behavior (JavaScript controller) from the presentation (HTML view). This
|
to separate the behavior (JavaScript controller) from the presentation (HTML view). This
|
||||||
separation aids in maintainability and testability of your project.
|
separation aids in maintainability and testability of your project.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Multi-page App and Deep Linking
|
# Multi-page App and Deep Linking
|
||||||
|
|
||||||
|
|
||||||
{@link deeplinking Deep Linking}: An AJAX application never navigates away from the
|
{@link deeplinking Deep Linking}: An AJAX application never navigates away from the
|
||||||
first page it loads. Instead, it changes the DOM of its single page. Eliminating full-page reloads
|
first page it loads. Instead, it changes the DOM of its single page. Eliminating full-page reloads
|
||||||
is what makes AJAX apps responsive, but it creates a problem in that apps with a single URL
|
is what makes AJAX apps responsive, but it creates a problem in that apps with a single URL
|
||||||
prevent you from emailing links to a particular screen within your application.
|
prevent you from emailing links to a particular screen within your application.
|
||||||
|
|
||||||
|
|
||||||
Deep linking tries to solve this by changing the URL anchor without reloading a page, thus
|
Deep linking tries to solve this by changing the URL anchor without reloading a page, thus
|
||||||
allowing you to send links to specific screens in your app.
|
allowing you to send links to specific screens in your app.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Services
|
# Services
|
||||||
|
|
||||||
|
|
||||||
{@link api/angular.service Services}: Services are long lived objects in your applications that are
|
{@link api/angular.service Services}: Services are long lived objects in your applications that are
|
||||||
available across controllers. A collection of useful services are pre-bundled with angular but you
|
available across controllers. A collection of useful services are pre-bundled with angular but you
|
||||||
will likely add your own. Services are initialized using dependency injection, which resolves the
|
will likely add your own. Services are initialized using dependency injection, which resolves the
|
||||||
|
|
@ -72,11 +52,8 @@ order of initialization. This safeguards you from the perils of global state (a
|
||||||
implement long lived objects).
|
implement long lived objects).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# External Resources
|
# External Resources
|
||||||
|
|
||||||
|
|
||||||
{@link buzz Resources}: Web applications must be able to communicate with the external
|
{@link buzz Resources}: Web applications must be able to communicate with the external
|
||||||
services to get and update data. Resources are the abstractions of external URLs which are
|
services to get and update data. Resources are the abstractions of external URLs which are
|
||||||
specially tailored to angular data binding.
|
specially tailored to angular data binding.
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,15 @@
|
||||||
@name Cookbook: MVC
|
@name Cookbook: MVC
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
MVC allows for a clean an testable separation between the behavior (controller) and the view
|
MVC allows for a clean an testable separation between the behavior (controller) and the view
|
||||||
(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the
|
(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the
|
||||||
view. This makes it very easy for the controller and the view to share the model.
|
view. This makes it very easy for the controller and the view to share the model.
|
||||||
|
|
||||||
|
|
||||||
The model is simply the controller's this. This makes it very easy to test the controller in
|
The model is simply the controller's this. This makes it very easy to test the controller in
|
||||||
isolation since one can simply instantiate the controller and test without a view, because there is
|
isolation since one can simply instantiate the controller and test without a view, because there is
|
||||||
no connection between the controller and the view.
|
no connection between the controller and the view.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -83,7 +79,6 @@ no connection between the controller and the view.
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<h3>Tic-Tac-Toe</h3>
|
<h3>Tic-Tac-Toe</h3>
|
||||||
<div ng:controller="TicTacToeCntl">
|
<div ng:controller="TicTacToeCntl">
|
||||||
Next Player: {{nextMove}}
|
Next Player: {{nextMove}}
|
||||||
|
|
@ -109,7 +104,6 @@ no connection between the controller and the view.
|
||||||
expect(element('.winner').text()).toEqual('Player X has won!');
|
expect(element('.winner').text()).toEqual('Player X has won!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function piece(row, col) {
|
function piece(row, col) {
|
||||||
element('.board tr:nth-child('+row+') td:nth-child('+col+')').click();
|
element('.board tr:nth-child('+row+') td:nth-child('+col+')').click();
|
||||||
}
|
}
|
||||||
|
|
@ -117,11 +111,8 @@ no connection between the controller and the view.
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Things to notice
|
# Things to notice
|
||||||
|
|
||||||
|
|
||||||
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
||||||
* The controller is instantiated by <angular/> and injected into the view.
|
* The controller is instantiated by <angular/> and injected into the view.
|
||||||
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,23 @@
|
||||||
@name Developer Guide: Initializing Angular: Automatic Initiialization
|
@name Developer Guide: Initializing Angular: Automatic Initiialization
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular initializes automatically when you load the angular script into your page, specifying
|
Angular initializes automatically when you load the angular script into your page, specifying
|
||||||
angular's `ng:autobind` attribute with no arguments:
|
angular's `ng:autobind` attribute with no arguments:
|
||||||
|
|
||||||
|
|
||||||
<script src="angular.js" ng:autobind>
|
<script src="angular.js" ng:autobind>
|
||||||
|
|
||||||
|
|
||||||
From a high-level view, this is what happens during angular's automatic initialization process:
|
From a high-level view, this is what happens during angular's automatic initialization process:
|
||||||
|
|
||||||
|
|
||||||
1. The browser loads the page, and then runs the angular script.
|
1. The browser loads the page, and then runs the angular script.
|
||||||
|
|
||||||
|
|
||||||
The `ng:autobind` attribute tells angular to compile and manage the whole HTML document. The
|
The `ng:autobind` attribute tells angular to compile and manage the whole HTML document. The
|
||||||
compilation phase is initiated in the page's `onLoad()` handler. Angular doesn't begin processing
|
compilation phase is initiated in the page's `onLoad()` handler. Angular doesn't begin processing
|
||||||
the page until after the page load is complete.
|
the page until after the page load is complete.
|
||||||
|
|
||||||
|
|
||||||
2. Angular finds the root of the HTML document and creates the global variable `angular` in the
|
2. Angular finds the root of the HTML document and creates the global variable `angular` in the
|
||||||
global namespace. Everything that angular subsequently creates is bound to fields in this global
|
global namespace. Everything that angular subsequently creates is bound to fields in this global
|
||||||
object.
|
object.
|
||||||
|
|
||||||
|
|
||||||
3. Angular walks the DOM looking for angular widgets, directives, and markup (such as `ng:init` or
|
3. Angular walks the DOM looking for angular widgets, directives, and markup (such as `ng:init` or
|
||||||
`ng:repeat`). As angular encounters these, it creates child scopes as necessary and attaches them
|
`ng:repeat`). As angular encounters these, it creates child scopes as necessary and attaches them
|
||||||
to the DOM, registers listeners on those scopes, associates any controller functions with their
|
to the DOM, registers listeners on those scopes, associates any controller functions with their
|
||||||
|
|
@ -34,39 +27,29 @@ data and their part of the view, and ultimately constructs a runnable applicatio
|
||||||
app features two-way data-binding and a nice separation between data, presentation, and business
|
app features two-way data-binding and a nice separation between data, presentation, and business
|
||||||
logic.
|
logic.
|
||||||
|
|
||||||
|
|
||||||
4. For the duration of the application session (while the page is loaded), angular monitors the
|
4. For the duration of the application session (while the page is loaded), angular monitors the
|
||||||
state of the application, and updates the view and the data model whenever the state of either one
|
state of the application, and updates the view and the data model whenever the state of either one
|
||||||
changes.
|
changes.
|
||||||
|
|
||||||
|
|
||||||
For details on how the compiler works, see {@link dev_guide.compiler Angular HTML Compiler}.
|
For details on how the compiler works, see {@link dev_guide.compiler Angular HTML Compiler}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Initialization Options
|
## Initialization Options
|
||||||
|
|
||||||
|
|
||||||
The reason why `ng:autobind` exists is because angular should not assume that the entire HTML
|
The reason why `ng:autobind` exists is because angular should not assume that the entire HTML
|
||||||
document should be processed just because the `angular.js` script is included. In order to compile
|
document should be processed just because the `angular.js` script is included. In order to compile
|
||||||
only a part of the document, specify the ID of the element you want to use for angular's root
|
only a part of the document, specify the ID of the element you want to use for angular's root
|
||||||
element as the value of the `ng:autobind` attribute:
|
element as the value of the `ng:autobind` attribute:
|
||||||
|
|
||||||
|
|
||||||
ng:autobind="angularContent"
|
ng:autobind="angularContent"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Auto-bootstrap with `#autobind`
|
## Auto-bootstrap with `#autobind`
|
||||||
|
|
||||||
|
|
||||||
In some rare cases you can't define the `ng:` prefix before the script tag's attribute (for
|
In some rare cases you can't define the `ng:` prefix before the script tag's attribute (for
|
||||||
example, in some CMS systems). In those situations it is possible to auto-bootstrap angular by
|
example, in some CMS systems). In those situations it is possible to auto-bootstrap angular by
|
||||||
appending `#autobind` to the `<script src=...>` URL, like in this snippet:
|
appending `#autobind` to the `<script src=...>` URL, like in this snippet:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
|
@ -82,19 +65,15 @@ appending `#autobind` to the `<script src=...>` URL, like in this snippet:
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
As with `ng:autobind`, you can specify an element id that should be exclusively targeted for
|
As with `ng:autobind`, you can specify an element id that should be exclusively targeted for
|
||||||
compilation as the value of the `#autobind`, for example: `#autobind=angularContent`.
|
compilation as the value of the `#autobind`, for example: `#autobind=angularContent`.
|
||||||
|
|
||||||
|
|
||||||
## Filename Restrictions for Auto-bootstrap
|
## Filename Restrictions for Auto-bootstrap
|
||||||
|
|
||||||
|
|
||||||
In order for us to find the auto-bootstrap from a script attribute or URL fragment, the value of
|
In order for us to find the auto-bootstrap from a script attribute or URL fragment, the value of
|
||||||
the `script` `src` attribute that loads the angular script must match one of these naming
|
the `script` `src` attribute that loads the angular script must match one of these naming
|
||||||
conventions:
|
conventions:
|
||||||
|
|
||||||
|
|
||||||
- `angular.js`
|
- `angular.js`
|
||||||
- `angular-min.js`
|
- `angular-min.js`
|
||||||
- `angular-x.x.x.js`
|
- `angular-x.x.x.js`
|
||||||
|
|
@ -103,28 +82,20 @@ conventions:
|
||||||
- `angular-x.x.x-xxxxxxxx.min.js` (dev snapshot)
|
- `angular-x.x.x-xxxxxxxx.min.js` (dev snapshot)
|
||||||
- `angular-bootstrap.js` (used for development of angular)
|
- `angular-bootstrap.js` (used for development of angular)
|
||||||
|
|
||||||
|
|
||||||
Optionally, any of the filename formats above can be prepended with a relative or absolute URL that
|
Optionally, any of the filename formats above can be prepended with a relative or absolute URL that
|
||||||
ends with `/`.
|
ends with `/`.
|
||||||
|
|
||||||
|
|
||||||
## Global Angular Object
|
## Global Angular Object
|
||||||
|
|
||||||
|
|
||||||
The angular script creates a single global variable `angular` in the global namespace. All angular
|
The angular script creates a single global variable `angular` in the global namespace. All angular
|
||||||
APIs are bound to fields of this global object.
|
APIs are bound to fields of this global object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.bootstrap Initializing Angular}
|
* {@link dev_guide.bootstrap Initializing Angular}
|
||||||
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
|
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
{@link api/angular.compile Compiler API}
|
{@link api/angular.compile Compiler API}
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,14 @@
|
||||||
@name Developer Guide: Initializing Angular: Manual Initialization
|
@name Developer Guide: Initializing Angular: Manual Initialization
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Letting angular handle the initialization process (bootstrapping) is a handy way to start using
|
Letting angular handle the initialization process (bootstrapping) is a handy way to start using
|
||||||
angular, but advanced users who want more control over the initialization process can choose to use
|
angular, but advanced users who want more control over the initialization process can choose to use
|
||||||
the manual bootstrapping method instead.
|
the manual bootstrapping method instead.
|
||||||
|
|
||||||
|
|
||||||
The best way to get started with manual bootstrapping is to look at the what happens when you use
|
The best way to get started with manual bootstrapping is to look at the what happens when you use
|
||||||
{@link api/angular.directive.ng:autobind ng:autobind}, by showing each step of the process
|
{@link api/angular.directive.ng:autobind ng:autobind}, by showing each step of the process
|
||||||
explicitly.
|
explicitly.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
@ -32,27 +29,20 @@ Hello {{'World'}}!
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
This is the sequence that your code should follow if you bootstrap angular on your own:
|
This is the sequence that your code should follow if you bootstrap angular on your own:
|
||||||
|
|
||||||
|
|
||||||
1. After the page is loaded, find the root of the HTML template, which is typically the root of
|
1. After the page is loaded, find the root of the HTML template, which is typically the root of
|
||||||
the document.
|
the document.
|
||||||
2. Run angular's {@link dev_guide.compiler Angular HTML compiler}, which converts a template into
|
2. Run angular's {@link dev_guide.compiler Angular HTML compiler}, which converts a template into
|
||||||
an executable, bi-directionally bound application.
|
an executable, bi-directionally bound application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.bootstrap Initializing Angular}
|
* {@link dev_guide.bootstrap Initializing Angular}
|
||||||
* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization}
|
* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization}
|
||||||
* {@link dev_guide.compiler Angular HTML compiler}
|
* {@link dev_guide.compiler Angular HTML compiler}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
{@link api/angular.compile Compiler API}
|
{@link api/angular.compile Compiler API}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,16 @@
|
||||||
@name Developer Guide: Initializing Angular
|
@name Developer Guide: Initializing Angular
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Initializing angular consists of loading the `angular.js` script in your page, and specifying how
|
Initializing angular consists of loading the `angular.js` script in your page, and specifying how
|
||||||
angular should process and manage the page. To initialize angular you do the following:
|
angular should process and manage the page. To initialize angular you do the following:
|
||||||
|
|
||||||
|
|
||||||
* Specify the angular namespace in the `<html>` page
|
* Specify the angular namespace in the `<html>` page
|
||||||
* Choose which flavor of angular script to load (debug or production)
|
* Choose which flavor of angular script to load (debug or production)
|
||||||
* Specify whether or not angular should process and manage the page automatically (`ng:autobind`)
|
* Specify whether or not angular should process and manage the page automatically (`ng:autobind`)
|
||||||
|
|
||||||
|
|
||||||
The simplest way to initialize angular is to load the angular script and tell angular to compile
|
The simplest way to initialize angular is to load the angular script and tell angular to compile
|
||||||
and manage the whole page. You do this as follows:
|
and manage the whole page. You do this as follows:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
@ -30,57 +26,40 @@ and manage the whole page. You do this as follows:
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Specifying the Angular Namespace
|
## Specifying the Angular Namespace
|
||||||
|
|
||||||
|
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
||||||
|
|
||||||
You need to declare the angular namespace declaration in the following cases:
|
You need to declare the angular namespace declaration in the following cases:
|
||||||
|
|
||||||
|
|
||||||
* For all types of browser if you are using XHTML.
|
* For all types of browser if you are using XHTML.
|
||||||
* For Internet Explorer older than version 9 (because older versions of IE do not render widgets
|
* For Internet Explorer older than version 9 (because older versions of IE do not render widgets
|
||||||
properly for either HTML or XHTML).
|
properly for either HTML or XHTML).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Creating Your Own Namespaces
|
## Creating Your Own Namespaces
|
||||||
|
|
||||||
|
|
||||||
When you are ready to define your own {@link dev_guide.compiler.widgets widgets}, you must create
|
When you are ready to define your own {@link dev_guide.compiler.widgets widgets}, you must create
|
||||||
your own namespace in addition to specifying the angular namespace. You use your own namespace to
|
your own namespace in addition to specifying the angular namespace. You use your own namespace to
|
||||||
form the fully qualified name for widgets that you create.
|
form the fully qualified name for widgets that you create.
|
||||||
|
|
||||||
|
|
||||||
For example, you could map the alias `my` to your domain, and create a widget called `my:widget`.
|
For example, you could map the alias `my` to your domain, and create a widget called `my:widget`.
|
||||||
To create your own namespace, simply add another `xmlns` tag to your page, create an alias, and set
|
To create your own namespace, simply add another `xmlns` tag to your page, create an alias, and set
|
||||||
it to your unique domain:
|
it to your unique domain:
|
||||||
|
|
||||||
|
|
||||||
<html xmlns:ng="http://angularjs.org" xmlns:my="http://mydomain.com">
|
<html xmlns:ng="http://angularjs.org" xmlns:my="http://mydomain.com">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Loading the Angular Bootstrap Script
|
## Loading the Angular Bootstrap Script
|
||||||
|
|
||||||
|
|
||||||
The angular bootstrap script comes in two flavors; a debug script, and a production script:
|
The angular bootstrap script comes in two flavors; a debug script, and a production script:
|
||||||
|
|
||||||
|
|
||||||
* angular-[version].js - This is a human-readable file, suitable for development and debugging.
|
* angular-[version].js - This is a human-readable file, suitable for development and debugging.
|
||||||
* angular-[version].min.js - This is a compressed and obfuscated file, suitable for use in
|
* angular-[version].min.js - This is a compressed and obfuscated file, suitable for use in
|
||||||
production.
|
production.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization}
|
* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization}
|
||||||
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
|
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,10 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Directives: Creating Custom Angular Directives
|
@name Developer Guide: Angular HTML Compiler: Directives: Creating Custom Angular Directives
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
The following code snippet shows how to define a custom directive. You define a new directive by
|
The following code snippet shows how to define a custom directive. You define a new directive by
|
||||||
extending the {@link dev_guide.compiler Angular HTML compiler}. The code snippet below is a
|
extending the {@link dev_guide.compiler Angular HTML compiler}. The code snippet below is a
|
||||||
simplified definition of the built-in {@link api/angular.directive.ng:bind ng:bind} directive:
|
simplified definition of the built-in {@link api/angular.directive.ng:bind ng:bind} directive:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.directive('ng:bind', function(expression, compiledElement) {
|
angular.directive('ng:bind', function(expression, compiledElement) {
|
||||||
var compiler = this;
|
var compiler = this;
|
||||||
|
|
@ -21,29 +19,21 @@ angular.directive('ng:bind', function(expression, compiledElement) {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
# Additional Compiler Methods for Custom Directives
|
# Additional Compiler Methods for Custom Directives
|
||||||
|
|
||||||
|
|
||||||
The angular compiler exposes methods that you may need to use when writing your own widgets and
|
The angular compiler exposes methods that you may need to use when writing your own widgets and
|
||||||
directives. For example, the `descend()` method lets you control whether the compiler ignores or
|
directives. For example, the `descend()` method lets you control whether the compiler ignores or
|
||||||
processes child elements of the element it is compiling. For information on this and other
|
processes child elements of the element it is compiling. For information on this and other
|
||||||
compiler methods, see the {@link api/angular.compile Compiler API doc}.
|
compiler methods, see the {@link api/angular.compile Compiler API doc}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Docs
|
## Related Docs
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||||
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.directive Angular Directive API}.
|
* {@link api/angular.directive Angular Directive API}.
|
||||||
|
|
|
||||||
|
|
@ -3,39 +3,30 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Understanding Angular Directives
|
@name Developer Guide: Angular HTML Compiler: Understanding Angular Directives
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
An angular directive is a custom HTML attribute that angular knows how to process. You add them to
|
An angular directive is a custom HTML attribute that angular knows how to process. You add them to
|
||||||
a template element like any other attribute. Angular directives all have a `ng:` prefix. In the
|
a template element like any other attribute. Angular directives all have a `ng:` prefix. In the
|
||||||
following example, the angular directive (`ng:controller`) is a div tag:
|
following example, the angular directive (`ng:controller`) is a div tag:
|
||||||
|
|
||||||
|
|
||||||
<div ng:controller>
|
<div ng:controller>
|
||||||
|
|
||||||
|
|
||||||
You use angular directives to modify DOM element properties. The element you modify can be an
|
You use angular directives to modify DOM element properties. The element you modify can be an
|
||||||
existing HTML element type or a custom DOM element type that you created. You can use any number of
|
existing HTML element type or a custom DOM element type that you created. You can use any number of
|
||||||
directives per element.
|
directives per element.
|
||||||
|
|
||||||
|
|
||||||
You add angular directives to a standard HTML tag as in the following example, in which we have
|
You add angular directives to a standard HTML tag as in the following example, in which we have
|
||||||
added the {@link api/angular.directive.ng:click ng:click} directive to a button tag:
|
added the {@link api/angular.directive.ng:click ng:click} directive to a button tag:
|
||||||
|
|
||||||
|
|
||||||
<button name="button1" ng:click="foo()">Click This</button>
|
<button name="button1" ng:click="foo()">Click This</button>
|
||||||
|
|
||||||
|
|
||||||
In the example above, `name` is the standard HTML attribute, and `ng:click` is the angular
|
In the example above, `name` is the standard HTML attribute, and `ng:click` is the angular
|
||||||
directive. The `ng:click` directive lets you implement custom behavior in an associated controller
|
directive. The `ng:click` directive lets you implement custom behavior in an associated controller
|
||||||
function.
|
function.
|
||||||
|
|
||||||
|
|
||||||
In the next example, we add the {@link api/angular.directive.ng:bind ng:bind} directive to a
|
In the next example, we add the {@link api/angular.directive.ng:bind ng:bind} directive to a
|
||||||
`<span>` tag:
|
`<span>` tag:
|
||||||
|
|
||||||
|
|
||||||
<span ng:bind="1+2"></span>
|
<span ng:bind="1+2"></span>
|
||||||
|
|
||||||
|
|
||||||
The `ng:bind` directive tells angular to set up {@link dev_guide.templates.databinding data
|
The `ng:bind` directive tells angular to set up {@link dev_guide.templates.databinding data
|
||||||
binding} between the data model and the view for the specified expression. When the angular {@link
|
binding} between the data model and the view for the specified expression. When the angular {@link
|
||||||
dev_guide.compiler compiler} encounters an `ng:bind` directive in a template, it passes the
|
dev_guide.compiler compiler} encounters an `ng:bind` directive in a template, it passes the
|
||||||
|
|
@ -44,18 +35,13 @@ the expression in the model, the view is updated to display the span text with t
|
||||||
expression value.
|
expression value.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
* {@link dev_guide.compiler.directives.creating_directives Creating Angular Directives}
|
* {@link dev_guide.compiler.directives.creating_directives Creating Angular Directives}
|
||||||
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
||||||
|
|
||||||
|
|
||||||
## Related API:
|
## Related API:
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.directive Directive API}
|
* {@link api/angular.directive Directive API}
|
||||||
* {@link api/angular.widget Widget API}
|
* {@link api/angular.widget Widget API}
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,15 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Comparing Directives and Attribute Widgets
|
@name Developer Guide: Angular HTML Compiler: Comparing Directives and Attribute Widgets
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Although directives and {@link dev_guide.compiler.widgets attribute widgets} appear the same in a
|
Although directives and {@link dev_guide.compiler.widgets attribute widgets} appear the same in a
|
||||||
template (`ng:init` is a directive, `ng:repeat` is an attribute widget), there is a difference in
|
template (`ng:init` is a directive, `ng:repeat` is an attribute widget), there is a difference in
|
||||||
the order in which they are evaluated. The user of existing directives or widgets cannot determine
|
the order in which they are evaluated. The user of existing directives or widgets cannot determine
|
||||||
the order of evaluation. The evaluation order is the responsibility of the developer creating
|
the order of evaluation. The evaluation order is the responsibility of the developer creating
|
||||||
custom directives and widgets.
|
custom directives and widgets.
|
||||||
|
|
||||||
|
|
||||||
For example, consider this piece of HTML, which uses the `ng:repeat`, `ng:init`, and `ng:bind`
|
For example, consider this piece of HTML, which uses the `ng:repeat`, `ng:init`, and `ng:bind`
|
||||||
widget and directives:
|
widget and directives:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<ul ng:init="people=['mike', 'mary']">
|
<ul ng:init="people=['mike', 'mary']">
|
||||||
<li ng:repeat="person in people"
|
<li ng:repeat="person in people"
|
||||||
|
|
@ -24,36 +21,28 @@ widget and directives:
|
||||||
</ul>
|
</ul>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Notice that the order of execution matters here. Because we want to run the `ng:init="a=a+1` and
|
Notice that the order of execution matters here. Because we want to run the `ng:init="a=a+1` and
|
||||||
`ng:bind="person"` once for each `person in people`, we need to execute {@link
|
`ng:bind="person"` once for each `person in people`, we need to execute {@link
|
||||||
api/angular.widget.@ng:repeat ng:repeat} to make copies of the `<li>` element before we run the
|
api/angular.widget.@ng:repeat ng:repeat} to make copies of the `<li>` element before we run the
|
||||||
{@link api/angular.directive.ng:init ng:init}, and {@link api/angular.directive.ng:bind ng:bind}
|
{@link api/angular.directive.ng:init ng:init}, and {@link api/angular.directive.ng:bind ng:bind}
|
||||||
for each of the `<li>`copies.
|
for each of the `<li>`copies.
|
||||||
|
|
||||||
|
|
||||||
If you implemented `ng:repeat` as a directive, there would be no guarantee that the attributes
|
If you implemented `ng:repeat` as a directive, there would be no guarantee that the attributes
|
||||||
`ng:repeat`, `ng:init`, and `ng:bind` would be evaluated in the order they are declared, because
|
`ng:repeat`, `ng:init`, and `ng:bind` would be evaluated in the order they are declared, because
|
||||||
the order of element attributes in HTML is not significant to the browser.
|
the order of element attributes in HTML is not significant to the browser.
|
||||||
|
|
||||||
|
|
||||||
So, when creating a custom HTML attribute, you will have to consider whether a directive or a
|
So, when creating a custom HTML attribute, you will have to consider whether a directive or a
|
||||||
widget is more appropriate. When the order of execution doesn't matter, directives are the right
|
widget is more appropriate. When the order of execution doesn't matter, directives are the right
|
||||||
choice. In a situation where the order matters and one attribute should be processed with a higher
|
choice. In a situation where the order matters and one attribute should be processed with a higher
|
||||||
priority than others, use a widget for the attribute that must be processed first.
|
priority than others, use a widget for the attribute that must be processed first.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||||
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
||||||
|
|
||||||
|
|
||||||
## Related API:
|
## Related API:
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.directive Directive API}
|
* {@link api/angular.directive Directive API}
|
||||||
* {@link api/angular.widget Widget API}
|
* {@link api/angular.widget Widget API}
|
||||||
|
|
|
||||||
|
|
@ -65,17 +65,13 @@ return function(linkElement){
|
||||||
Note: For more about widgets, see {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
Note: For more about widgets, see {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
||||||
and the {@link api/angular.widget widget API reference page}.
|
and the {@link api/angular.widget widget API reference page}.
|
||||||
|
|
||||||
|
|
||||||
# Compilation process for `<my:greeter>`
|
# Compilation process for `<my:greeter>`
|
||||||
|
|
||||||
|
|
||||||
Here are the steps that the compiler takes in processing the page that contains the widget
|
Here are the steps that the compiler takes in processing the page that contains the widget
|
||||||
definition above:
|
definition above:
|
||||||
|
|
||||||
|
|
||||||
## Compile Phase
|
## Compile Phase
|
||||||
|
|
||||||
|
|
||||||
1. Recursively traverse the DOM depth-first.
|
1. Recursively traverse the DOM depth-first.
|
||||||
2. Find the angular.widget definition.
|
2. Find the angular.widget definition.
|
||||||
3. Find and execute the widget's compileElement function, which includes the following steps:
|
3. Find and execute the widget's compileElement function, which includes the following steps:
|
||||||
|
|
@ -86,10 +82,8 @@ template (i.e. any repeating elements)).
|
||||||
2. Extract the salutation and name HTML attributes as angular expressions.
|
2. Extract the salutation and name HTML attributes as angular expressions.
|
||||||
4. Return the aggregate link function, which includes just one link function in this example.
|
4. Return the aggregate link function, which includes just one link function in this example.
|
||||||
|
|
||||||
|
|
||||||
## Link Phase
|
## Link Phase
|
||||||
|
|
||||||
|
|
||||||
1. Execute the aggregate link function, which includes the following steps:
|
1. Execute the aggregate link function, which includes the following steps:
|
||||||
1. Create a <span> element set to the salutation class
|
1. Create a <span> element set to the salutation class
|
||||||
2. Create a <span> element set to the name class.
|
2. Create a <span> element set to the name class.
|
||||||
|
|
@ -99,17 +93,12 @@ compileElement, because that's the template.)
|
||||||
corresponding spans.
|
corresponding spans.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
||||||
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile angular.compile()}
|
* {@link api/angular.compile angular.compile()}
|
||||||
|
|
|
||||||
|
|
@ -3,59 +3,46 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Understanding Angular Markup
|
@name Developer Guide: Angular HTML Compiler: Understanding Angular Markup
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Markup in angular is a feature that you can use in templates to transform the content of DOM
|
Markup in angular is a feature that you can use in templates to transform the content of DOM
|
||||||
elements prior to the compile phase (in which elements are compiled and link functions are
|
elements prior to the compile phase (in which elements are compiled and link functions are
|
||||||
returned. See the {@link dev_guide.compiler compiler docs} for details on how the compiler
|
returned. See the {@link dev_guide.compiler compiler docs} for details on how the compiler
|
||||||
works.) The ability to make pre-compile changes to DOM elements lets you create shorthand for
|
works.) The ability to make pre-compile changes to DOM elements lets you create shorthand for
|
||||||
{@link api/angular.widget widget} and {@link api/angular.directive directive} declarations.
|
{@link api/angular.widget widget} and {@link api/angular.directive directive} declarations.
|
||||||
|
|
||||||
|
|
||||||
Angular provides one built-in markup feature: the double curly-braces used to declare binding
|
Angular provides one built-in markup feature: the double curly-braces used to declare binding
|
||||||
points (between the model and view) for angular expressions. You can also create your own custom
|
points (between the model and view) for angular expressions. You can also create your own custom
|
||||||
markup.
|
markup.
|
||||||
|
|
||||||
|
|
||||||
# Using Double Curly-brace Markup (`{{ }}`)
|
# Using Double Curly-brace Markup (`{{ }}`)
|
||||||
|
|
||||||
|
|
||||||
The double curly-brace (`{{ }}`) markup translates an enclosed expression into an {@link
|
The double curly-brace (`{{ }}`) markup translates an enclosed expression into an {@link
|
||||||
api/angular.directive.ng:bind ng:bind} directive:
|
api/angular.directive.ng:bind ng:bind} directive:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
{{expression}}
|
{{expression}}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
is transformed to:
|
is transformed to:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<span ng:bind="expression"></span>
|
<span ng:bind="expression"></span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Markup is useful for the simple reason that `{{1+2}}` is easier to write and understand than `<span
|
Markup is useful for the simple reason that `{{1+2}}` is easier to write and understand than `<span
|
||||||
ng:bind="1+2"></span>`. After markup shorthand is expanded into the DOM elements it represents, the
|
ng:bind="1+2"></span>`. After markup shorthand is expanded into the DOM elements it represents, the
|
||||||
expanded elements are then {@link dev_guide.compiler compiled} normally.
|
expanded elements are then {@link dev_guide.compiler compiled} normally.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Creating Custom Markup
|
# Creating Custom Markup
|
||||||
|
|
||||||
|
|
||||||
Let's say you want to define markup that transforms `---` into a horizontal rule (`<hr/>`):
|
Let's say you want to define markup that transforms `---` into a horizontal rule (`<hr/>`):
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
header
|
header
|
||||||
---
|
---
|
||||||
footer
|
footer
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
should translate to:
|
should translate to:
|
||||||
<pre>
|
<pre>
|
||||||
header
|
header
|
||||||
|
|
@ -63,10 +50,8 @@ header
|
||||||
footer
|
footer
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Here is how you could extend the angular compiler to create the "---" markup:
|
Here is how you could extend the angular compiler to create the "---" markup:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.markup('---', function(text, textNode, parentElement) {
|
angular.markup('---', function(text, textNode, parentElement) {
|
||||||
var compiler = this;
|
var compiler = this;
|
||||||
|
|
@ -83,20 +68,16 @@ angular.markup('---', function(text, textNode, parentElement) {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Unlike the way the compiler processes {@link api/angular.widget widgets} and {@link
|
Unlike the way the compiler processes {@link api/angular.widget widgets} and {@link
|
||||||
api/angular.directive directives} (matching the name of the handler function to a DOM element or
|
api/angular.directive directives} (matching the name of the handler function to a DOM element or
|
||||||
attribute name), the compiler calls every markup handler for every text node, giving the handler a
|
attribute name), the compiler calls every markup handler for every text node, giving the handler a
|
||||||
chance to transform the text. The markup handler needs to find all the matches in the text.
|
chance to transform the text. The markup handler needs to find all the matches in the text.
|
||||||
|
|
||||||
|
|
||||||
## Attribute Markup
|
## Attribute Markup
|
||||||
|
|
||||||
|
|
||||||
Attribute markup extends the angular compiler in a very similar way to markup, except that it
|
Attribute markup extends the angular compiler in a very similar way to markup, except that it
|
||||||
allows you to modify the state of attribute text rather then the content of a node.
|
allows you to modify the state of attribute text rather then the content of a node.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.attrMarkup('extraClass', function(attrValue, attrName, element){
|
angular.attrMarkup('extraClass', function(attrValue, attrName, element){
|
||||||
if (attrName == 'additional-class') {
|
if (attrName == 'additional-class') {
|
||||||
|
|
@ -106,15 +87,10 @@ angular.attrMarkup('extraClass', function(attrValue, attrName, element){
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile Compiler API Reference}
|
* {@link api/angular.compile Compiler API Reference}
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,18 @@
|
||||||
@name Developer Guide: Angular HTML Compiler
|
@name Developer Guide: Angular HTML Compiler
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
The core of angular is its HTML compiler. The compiler processes angular directives, widgets, and
|
The core of angular is its HTML compiler. The compiler processes angular directives, widgets, and
|
||||||
markup to transform a static HTML page into a dynamic web application.
|
markup to transform a static HTML page into a dynamic web application.
|
||||||
|
|
||||||
|
|
||||||
The default HTML transformations that the angular compiler provides are useful for building generic
|
The default HTML transformations that the angular compiler provides are useful for building generic
|
||||||
apps, but you can also extend the compiler to create a domain-specific language for building
|
apps, but you can also extend the compiler to create a domain-specific language for building
|
||||||
specific types of web applications.
|
specific types of web applications.
|
||||||
|
|
||||||
|
|
||||||
All compilation takes place in the web browser; no server is involved.
|
All compilation takes place in the web browser; no server is involved.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
||||||
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
||||||
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
||||||
|
|
@ -28,8 +22,6 @@ All compilation takes place in the web browser; no server is involved.
|
||||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||||
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile Angular Compiler API}
|
* {@link api/angular.compile Angular Compiler API}
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,15 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"Testing, testing, come in, over?"
|
"Testing, testing, come in, over?"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
||||||
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile angular.compile()}
|
* {@link api/angular.compile angular.compile()}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Understanding How the Compiler Works
|
@name Developer Guide: Angular HTML Compiler: Understanding How the Compiler Works
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Every {@link api/angular.widget widget}, {@link api/angular.directive directive} and {@link
|
Every {@link api/angular.widget widget}, {@link api/angular.directive directive} and {@link
|
||||||
dev_guide.compiler.markup markup} is defined with a compile function, which the angular compiler
|
dev_guide.compiler.markup markup} is defined with a compile function, which the angular compiler
|
||||||
executes on each widget or directive it encounters. The compile function optionally returns a link
|
executes on each widget or directive it encounters. The compile function optionally returns a link
|
||||||
|
|
@ -11,10 +10,8 @@ function. This compilation process happens automatically when the page is loade
|
||||||
`ng:autobind` in the script tag from which you load the angular script file. (See {@link
|
`ng:autobind` in the script tag from which you load the angular script file. (See {@link
|
||||||
dev_guide.bootstrap Initializing Angular}.)
|
dev_guide.bootstrap Initializing Angular}.)
|
||||||
|
|
||||||
|
|
||||||
The compile and link functions are related as follows:
|
The compile and link functions are related as follows:
|
||||||
|
|
||||||
|
|
||||||
* **compile function** — Registers a listener for the widget, directive, or markup expression. The
|
* **compile function** — Registers a listener for the widget, directive, or markup expression. The
|
||||||
compiler calls this function exactly once.
|
compiler calls this function exactly once.
|
||||||
* **link function** — Sets up the listener registered by the compile function. This function can be
|
* **link function** — Sets up the listener registered by the compile function. This function can be
|
||||||
|
|
@ -22,20 +19,16 @@ called multiple times, once per cloned DOM element. For example, in the case of
|
||||||
api/angular.widget.@ng:repeat repeater widget} used in a list element (`<li ng:repeat="[item in
|
api/angular.widget.@ng:repeat repeater widget} used in a list element (`<li ng:repeat="[item in
|
||||||
dataset]"`), the link function gets called to set up a listener on each element in the list.
|
dataset]"`), the link function gets called to set up a listener on each element in the list.
|
||||||
|
|
||||||
|
|
||||||
Note that angular's built-in widgets, directives, and markup have predefined compile and link
|
Note that angular's built-in widgets, directives, and markup have predefined compile and link
|
||||||
functions that you don't need to modify. When you create your own widgets, directives, or markup,
|
functions that you don't need to modify. When you create your own widgets, directives, or markup,
|
||||||
you must write compile and link functions for them. Refer to the {@link api/angular.compile
|
you must write compile and link functions for them. Refer to the {@link api/angular.compile
|
||||||
Compiler API} for details.
|
Compiler API} for details.
|
||||||
|
|
||||||
|
|
||||||
When the angular compiler compiles a page, it proceeds through 3 phases: Compile, Create Root
|
When the angular compiler compiles a page, it proceeds through 3 phases: Compile, Create Root
|
||||||
Scope, and Link:
|
Scope, and Link:
|
||||||
|
|
||||||
|
|
||||||
1. Compile Phase
|
1. Compile Phase
|
||||||
|
|
||||||
|
|
||||||
1. Recursively traverse the DOM, depth-first.
|
1. Recursively traverse the DOM, depth-first.
|
||||||
2. Look for a matching compile function of type widget, then markup, then directive.
|
2. Look for a matching compile function of type widget, then markup, then directive.
|
||||||
3. If a compile function is found then execute it.
|
3. If a compile function is found then execute it.
|
||||||
|
|
@ -43,46 +36,34 @@ Scope, and Link:
|
||||||
function with all link functions returned previously by step 3.
|
function with all link functions returned previously by step 3.
|
||||||
5. Repeat steps 3 and 4 for all compile functions found.
|
5. Repeat steps 3 and 4 for all compile functions found.
|
||||||
|
|
||||||
|
|
||||||
The result of the compilation phase is an aggregate link function, which comprises all of the
|
The result of the compilation phase is an aggregate link function, which comprises all of the
|
||||||
individual link functions.
|
individual link functions.
|
||||||
|
|
||||||
|
|
||||||
2. Create Root Scope Phase
|
2. Create Root Scope Phase
|
||||||
|
|
||||||
|
|
||||||
* Inject all services into the root scope.
|
* Inject all services into the root scope.
|
||||||
|
|
||||||
|
|
||||||
3. Link Phase
|
3. Link Phase
|
||||||
|
|
||||||
|
|
||||||
1. Execute the aggregate link function with the root scope. The aggregate link function calls
|
1. Execute the aggregate link function with the root scope. The aggregate link function calls
|
||||||
all of the individual link functions that were generated in the compile phase.
|
all of the individual link functions that were generated in the compile phase.
|
||||||
2. If there are any clones of the DOM caused by repeating elements, call the link function
|
2. If there are any clones of the DOM caused by repeating elements, call the link function
|
||||||
multiple times, one for each repeating item.
|
multiple times, one for each repeating item.
|
||||||
|
|
||||||
|
|
||||||
Note that while the compile function is executed exactly once, the link function can be executed
|
Note that while the compile function is executed exactly once, the link function can be executed
|
||||||
multiple times, for example, once for each iteration in a repeater.
|
multiple times, for example, once for each iteration in a repeater.
|
||||||
|
|
||||||
|
|
||||||
The angular compiler exposes methods that you will need to make use of when writing your own
|
The angular compiler exposes methods that you will need to make use of when writing your own
|
||||||
widgets and directives. For information on these methods, see the {@link api/angular.compile
|
widgets and directives. For information on these methods, see the {@link api/angular.compile
|
||||||
Compiler API doc}.
|
Compiler API doc}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
||||||
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile angular.compile()}
|
* {@link api/angular.compile angular.compile()}
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,19 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Widgets: Creating Custom Widgets
|
@name Developer Guide: Angular HTML Compiler: Widgets: Creating Custom Widgets
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
When you create your own widgets, you must set up your own namespace for them. (See
|
When you create your own widgets, you must set up your own namespace for them. (See
|
||||||
dev_guide.bootstrap Initializing Angular} for information about namespaces in angular.)
|
dev_guide.bootstrap Initializing Angular} for information about namespaces in angular.)
|
||||||
|
|
||||||
|
|
||||||
Let's say we would like to create a new element type in the namespace `my` that can watch an
|
Let's say we would like to create a new element type in the namespace `my` that can watch an
|
||||||
expression and `alert()` the user with each new value:
|
expression and `alert()` the user with each new value:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// An element widget
|
// An element widget
|
||||||
<my:watch exp="name"/>
|
<my:watch exp="name"/>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
You can implement `my:watch` like this:
|
You can implement `my:watch` like this:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.widget('my:watch', function(compileElement) {
|
angular.widget('my:watch', function(compileElement) {
|
||||||
var compiler = this;
|
var compiler = this;
|
||||||
|
|
@ -35,15 +30,11 @@ angular.widget('my:watch', function(compileElement) {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Creating a Custom Attribute Widget
|
# Creating a Custom Attribute Widget
|
||||||
|
|
||||||
|
|
||||||
Let's implement the same widget as in the example in Defining an Element Widget, but this time as
|
Let's implement the same widget as in the example in Defining an Element Widget, but this time as
|
||||||
an attribute that can be added to any existing DOM element:
|
an attribute that can be added to any existing DOM element:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// An attribute widget (my-watch) in a div tag
|
// An attribute widget (my-watch) in a div tag
|
||||||
<div my-watch="name">text</div>
|
<div my-watch="name">text</div>
|
||||||
|
|
@ -62,11 +53,8 @@ angular.widget('@my:watch', function(expression, compileElement) {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Live Example of a Custom Element Widget
|
# Live Example of a Custom Element Widget
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -88,29 +76,21 @@ angular.widget('my:time', function(compileElement){
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Additional Compiler Methods for Custom Widgets
|
# Additional Compiler Methods for Custom Widgets
|
||||||
|
|
||||||
|
|
||||||
The angular compiler exposes methods that you may need to use of when writing your own widgets and
|
The angular compiler exposes methods that you may need to use of when writing your own widgets and
|
||||||
directives. For example, the `descend()` method lets you control whether the compiler ignores or
|
directives. For example, the `descend()` method lets you control whether the compiler ignores or
|
||||||
processes child elements of the element it is compiling. For information on this and other
|
processes child elements of the element it is compiling. For information on this and other
|
||||||
compiler methods, see the {@link api/angular.compile Compiler API doc}.
|
compiler methods, see the {@link api/angular.compile Compiler API doc}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
* {@link dev_guide.compiler.directives Angular Directives}
|
* {@link dev_guide.compiler.directives Angular Directives}
|
||||||
* {@link dev_guide.compiler.widgets Angular Widgets}
|
* {@link dev_guide.compiler.widgets Angular Widgets}
|
||||||
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
|
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile Compiler API}
|
* {@link api/angular.compile Compiler API}
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,19 @@
|
||||||
@name Developer Guide: Angular HTML Compiler: Understanding Angular Widgets
|
@name Developer Guide: Angular HTML Compiler: Understanding Angular Widgets
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Widgets are DOM elements that the browser doesn't already understand. Angular provides some
|
Widgets are DOM elements that the browser doesn't already understand. Angular provides some
|
||||||
built-in widgets (such as {@link api/angular.widget.@ng:repeat ng:repeat}), and you can create your
|
built-in widgets (such as {@link api/angular.widget.@ng:repeat ng:repeat}), and you can create your
|
||||||
own custom widgets.
|
own custom widgets.
|
||||||
|
|
||||||
|
|
||||||
Widgets are intended to manipulate the DOM tree by adding new elements (unlike {@link
|
Widgets are intended to manipulate the DOM tree by adding new elements (unlike {@link
|
||||||
dev_guide.compiler.directives angular directives}, which are intended to modify only element
|
dev_guide.compiler.directives angular directives}, which are intended to modify only element
|
||||||
properties).
|
properties).
|
||||||
|
|
||||||
|
|
||||||
Widgets come in two types:
|
Widgets come in two types:
|
||||||
|
|
||||||
|
|
||||||
* Element Widget — A custom DOM element. An example of a custom element is shown in {@link
|
* Element Widget — A custom DOM element. An example of a custom element is shown in {@link
|
||||||
dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
|
dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
|
||||||
|
|
||||||
|
|
||||||
* Attribute Widget — A custom attribute on an existing DOM element. An attribute widget is similar
|
* Attribute Widget — A custom attribute on an existing DOM element. An attribute widget is similar
|
||||||
to an angular directive, with the main difference being that an attribute widget will always be
|
to an angular directive, with the main difference being that an attribute widget will always be
|
||||||
processed before any directives that are specified on the same element. Only one attribute widget
|
processed before any directives that are specified on the same element. Only one attribute widget
|
||||||
|
|
@ -29,19 +24,13 @@ dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
* {@link dev_guide.compiler.directives Angular Directives}
|
* {@link dev_guide.compiler.directives Angular Directives}
|
||||||
* {@link dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}
|
* {@link dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}
|
||||||
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
|
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile Compiler API}
|
* {@link api/angular.compile Compiler API}
|
||||||
|
|
|
||||||
|
|
@ -3,41 +3,31 @@
|
||||||
@name Developer Guide: About Dependency Injection (DI)
|
@name Developer Guide: About Dependency Injection (DI)
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Dependency Injection (DI) is an object-oriented software design pattern that supports the
|
Dependency Injection (DI) is an object-oriented software design pattern that supports the
|
||||||
decoupling and dependency management of application components.
|
decoupling and dependency management of application components.
|
||||||
|
|
||||||
|
|
||||||
The idea behind DI is to decouple each component from all of the other components that it depends
|
The idea behind DI is to decouple each component from all of the other components that it depends
|
||||||
on to do its particular job. The way this is done in DI is by moving the responsibility for
|
on to do its particular job. The way this is done in DI is by moving the responsibility for
|
||||||
managing dependencies out of each individual component and into a provider component. The provider
|
managing dependencies out of each individual component and into a provider component. The provider
|
||||||
(or injector) component manages the life cycles and dependencies for all of the other components in
|
(or injector) component manages the life cycles and dependencies for all of the other components in
|
||||||
an application.
|
an application.
|
||||||
|
|
||||||
|
|
||||||
Angular has a built-in dependency management subsystem that helps to make your applications easier
|
Angular has a built-in dependency management subsystem that helps to make your applications easier
|
||||||
to develop, understand, and test.
|
to develop, understand, and test.
|
||||||
|
|
||||||
|
|
||||||
For more information on DI in general, see {@link http://en.wikipedia.org/wiki/Dependency_injection
|
For more information on DI in general, see {@link http://en.wikipedia.org/wiki/Dependency_injection
|
||||||
Dependency Injection} at Wikipedia, and {@link http://martinfowler.com/articles/injection.html
|
Dependency Injection} at Wikipedia, and {@link http://martinfowler.com/articles/injection.html
|
||||||
Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
|
Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
|
||||||
book.
|
book.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
|
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
|
||||||
* {@link dev_guide.services Angular Services}
|
* {@link dev_guide.services Angular Services}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Service API}
|
* {@link api/angular.service Service API}
|
||||||
* {@link api/angular.injector Angular Injector API}
|
* {@link api/angular.injector Angular Injector API}
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,16 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
While DI is widely used in statically typed languages such as Java or C++, it has not been widely
|
While DI is widely used in statically typed languages such as Java or C++, it has not been widely
|
||||||
used in JavaScript. Angular brings the benefits of DI into JavaScript apps.
|
used in JavaScript. Angular brings the benefits of DI into JavaScript apps.
|
||||||
|
|
||||||
|
|
||||||
In angular, DI is implemented as a subsystem that manages dependencies between services,
|
In angular, DI is implemented as a subsystem that manages dependencies between services,
|
||||||
controllers, widgets, and filters. The most important of these are {@link api/angular.service
|
controllers, widgets, and filters. The most important of these are {@link api/angular.service
|
||||||
services}.
|
services}.
|
||||||
|
|
||||||
|
|
||||||
Services are objects that handle common tasks in web applications. Angular provides several{@link
|
Services are objects that handle common tasks in web applications. Angular provides several{@link
|
||||||
api/angular.service built-in services}, and you can create your own custom services.
|
api/angular.service built-in services}, and you can create your own custom services.
|
||||||
|
|
||||||
|
|
||||||
The main job of angular's DI subsystem is to provide services to angular components that depend on
|
The main job of angular's DI subsystem is to provide services to angular components that depend on
|
||||||
them. The way the DI subsystem provides services is as follows: all services are registered with
|
them. The way the DI subsystem provides services is as follows: all services are registered with
|
||||||
angular's {@link api/angular.service service API}, and all components that depend on services
|
angular's {@link api/angular.service service API}, and all components that depend on services
|
||||||
|
|
@ -27,13 +22,10 @@ manages the creation of service objects and the provision of those objects to th
|
||||||
need them, at the time they need them. The following illustration steps through the sequence of
|
need them, at the time they need them. The following illustration steps through the sequence of
|
||||||
events:
|
events:
|
||||||
|
|
||||||
|
|
||||||
<img src="img/guide/di_sequence_final.png">
|
<img src="img/guide/di_sequence_final.png">
|
||||||
|
|
||||||
|
|
||||||
In the illustration above, the dependency injection sequence proceeds as follows:
|
In the illustration above, the dependency injection sequence proceeds as follows:
|
||||||
|
|
||||||
|
|
||||||
1. Service factory functions are registered with angular's service factory repository.
|
1. Service factory functions are registered with angular's service factory repository.
|
||||||
2. `ng:autobind` triggers angular's bootstrap sequence, during which angular compiles the template,
|
2. `ng:autobind` triggers angular's bootstrap sequence, during which angular compiles the template,
|
||||||
creates the root scope, and creates the dependency injector.
|
creates the root scope, and creates the dependency injector.
|
||||||
|
|
@ -45,22 +37,17 @@ factory function from the service factory repository to construct it.
|
||||||
6. DI provides the instance of $xhr service to the PhoneListCtrl controller constructor
|
6. DI provides the instance of $xhr service to the PhoneListCtrl controller constructor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## How Scope Relates to DI
|
## How Scope Relates to DI
|
||||||
|
|
||||||
|
|
||||||
The {@link api/angular.injector injector} is responsible for resolving the service dependencies in
|
The {@link api/angular.injector injector} is responsible for resolving the service dependencies in
|
||||||
the application. It gets created and configured with the creation of a root scope. The injector
|
the application. It gets created and configured with the creation of a root scope. The injector
|
||||||
caches instances of services, with the services cache bound to the root scope.
|
caches instances of services, with the services cache bound to the root scope.
|
||||||
|
|
||||||
|
|
||||||
Different root scopes have different instances of the injector. While typical angular applications
|
Different root scopes have different instances of the injector. While typical angular applications
|
||||||
will only have one root scope (and hence the services will act like application singletons), in
|
will only have one root scope (and hence the services will act like application singletons), in
|
||||||
tests it is important to not share singletons across test invocations for isolation reasons. We
|
tests it is important to not share singletons across test invocations for isolation reasons. We
|
||||||
achieve the necessary isolation by having each test create its own separate root scope.
|
achieve the necessary isolation by having each test create its own separate root scope.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// create a root scope
|
// create a root scope
|
||||||
var rootScope = angular.scope();
|
var rootScope = angular.scope();
|
||||||
|
|
@ -68,50 +55,40 @@ var rootScope = angular.scope();
|
||||||
var myService = rootScope.$service('myService');
|
var myService = rootScope.$service('myService');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Inferring dependencies from the signature of the factory function or constructor
|
## Inferring dependencies from the signature of the factory function or constructor
|
||||||
|
|
||||||
|
|
||||||
**EXPERIMENTAL FEATURE**: This is an experimental feature. See the important note at the end of
|
**EXPERIMENTAL FEATURE**: This is an experimental feature. See the important note at the end of
|
||||||
this section for drawbacks.
|
this section for drawbacks.
|
||||||
|
|
||||||
|
|
||||||
We resort to `$inject` and our own annotation because there is no way in JavaScript to get a list
|
We resort to `$inject` and our own annotation because there is no way in JavaScript to get a list
|
||||||
of arguments. Or is there? It turns out that calling `.toString()` on a function returns the
|
of arguments. Or is there? It turns out that calling `.toString()` on a function returns the
|
||||||
function declaration along with the argument names as shown below:
|
function declaration along with the argument names as shown below:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function myFn(a,b){}
|
function myFn(a,b){}
|
||||||
expect(myFn.toString()).toEqual('function myFn(a,b){}');
|
expect(myFn.toString()).toEqual('function myFn(a,b){}');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
This means that angular can infer the function names after all and use that information to generate
|
This means that angular can infer the function names after all and use that information to generate
|
||||||
the `$inject` annotation automatically. Therefore the following two function definitions are
|
the `$inject` annotation automatically. Therefore the following two function definitions are
|
||||||
equivalent:
|
equivalent:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// given a user defined service
|
// given a user defined service
|
||||||
angular.service('serviceA', ...);
|
angular.service('serviceA', ...);
|
||||||
|
|
||||||
|
|
||||||
// inject '$window', 'serviceA', curry 'name';
|
// inject '$window', 'serviceA', curry 'name';
|
||||||
function fnA($window, serviceA, name){};
|
function fnA($window, serviceA, name){};
|
||||||
fnA.$inject = ['$window', 'serviceA'];
|
fnA.$inject = ['$window', 'serviceA'];
|
||||||
|
|
||||||
|
|
||||||
// inject '$window', 'serviceA', curry 'name';
|
// inject '$window', 'serviceA', curry 'name';
|
||||||
function fnB($window, serviceA_, name){};
|
function fnB($window, serviceA_, name){};
|
||||||
// implies: fnB.$inject = ['$window', 'serviceA'];
|
// implies: fnB.$inject = ['$window', 'serviceA'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
If angular does not find a `$inject` annotation on the function, then it calls the `.toString()`
|
If angular does not find a `$inject` annotation on the function, then it calls the `.toString()`
|
||||||
method and tries to infer what should be injected using the following rules:
|
method and tries to infer what should be injected using the following rules:
|
||||||
|
|
||||||
|
|
||||||
* Any argument starting with `$` is an angular service and will be added to the `$inject` property
|
* Any argument starting with `$` is an angular service and will be added to the `$inject` property
|
||||||
array
|
array
|
||||||
* Any argument ending with `_` will be added to the `$inject` property array (angular strips the
|
* Any argument ending with `_` will be added to the `$inject` property array (angular strips the
|
||||||
|
|
@ -119,7 +96,6 @@ array
|
||||||
* All arguments following an argument which has neither `$` nor `_` , must not have `$` nor `_`
|
* All arguments following an argument which has neither `$` nor `_` , must not have `$` nor `_`
|
||||||
(these are free arguments for {@link http://en.wikipedia.org/wiki/Currying currying})
|
(these are free arguments for {@link http://en.wikipedia.org/wiki/Currying currying})
|
||||||
|
|
||||||
|
|
||||||
**IMPORTANT**
|
**IMPORTANT**
|
||||||
Minifiers/obfuscators change the names of function arguments and will therefore break the `$inject`
|
Minifiers/obfuscators change the names of function arguments and will therefore break the `$inject`
|
||||||
inference. For this reason, either explicitly declare the `$inject` or do not use
|
inference. For this reason, either explicitly declare the `$inject` or do not use
|
||||||
|
|
@ -127,15 +103,10 @@ minifiers/obfuscators. In the future, we may provide a pre-processor which will
|
||||||
code and insert the `$inject` into the source code so that it can be minified/obfuscated.
|
code and insert the `$inject` into the source code so that it can be minified/obfuscated.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services Angular Services}
|
* {@link dev_guide.services Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Services API}
|
* {@link api/angular.service Services API}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
@name Developer Guide: DI: Using DI in Controllers
|
@name Developer Guide: DI: Using DI in Controllers
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
The most common place to use dependency injection in angular applications is in {@link
|
The most common place to use dependency injection in angular applications is in {@link
|
||||||
dev_guide.mvc.understanding_controller controllers}. Here is a simple example:
|
dev_guide.mvc.understanding_controller controllers}. Here is a simple example:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function MyController($route){
|
function MyController($route){
|
||||||
// configure the route service
|
// configure the route service
|
||||||
|
|
@ -16,14 +14,12 @@ function MyController($route){
|
||||||
MyController.$inject = ['$route'];
|
MyController.$inject = ['$route'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
In this example, the `MyController` constructor function takes one argument, the {@link
|
In this example, the `MyController` constructor function takes one argument, the {@link
|
||||||
api/angular.service.$route $route} service. Angular is then responsible for supplying the instance
|
api/angular.service.$route $route} service. Angular is then responsible for supplying the instance
|
||||||
of `$route` to the controller when the constructor is instantiated. There are two ways to cause
|
of `$route` to the controller when the constructor is instantiated. There are two ways to cause
|
||||||
controller instantiation – by configuring routes with the `$route` service, or by referencing the
|
controller instantiation – by configuring routes with the `$route` service, or by referencing the
|
||||||
controller from the HTML template, as follows:
|
controller from the HTML template, as follows:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html xmlns:ng="http://angularjs.org" ng:controller="MyController">
|
<html xmlns:ng="http://angularjs.org" ng:controller="MyController">
|
||||||
|
|
@ -34,33 +30,25 @@ controller from the HTML template, as follows:
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
When angular is instantiating your controller, it needs to know what services, if any, should be
|
When angular is instantiating your controller, it needs to know what services, if any, should be
|
||||||
injected (passed in as arguments) into the controller. Since there is no reflection in JavaScript,
|
injected (passed in as arguments) into the controller. Since there is no reflection in JavaScript,
|
||||||
we have to supply this information to angular in the form of an additional property on the
|
we have to supply this information to angular in the form of an additional property on the
|
||||||
controller constructor function called `$inject`. Think of it as annotations for JavaScript.
|
controller constructor function called `$inject`. Think of it as annotations for JavaScript.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
MyController.$inject = ['$route'];
|
MyController.$inject = ['$route'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The information in `$inject` is then used by the {@link api/angular.injector injector} to call the
|
The information in `$inject` is then used by the {@link api/angular.injector injector} to call the
|
||||||
function with the correct arguments.
|
function with the correct arguments.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.di About Dependency Injection}
|
* {@link dev_guide.di About Dependency Injection}
|
||||||
* {@link dev_guide.di.understanding_di Understanding Dependency Injection in Angular}
|
* {@link dev_guide.di.understanding_di Understanding Dependency Injection in Angular}
|
||||||
* {@link dev_guide.services Angular Services}
|
* {@link dev_guide.services Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.injector Angular Injector API}
|
* {@link api/angular.injector Angular Injector API}
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,24 @@
|
||||||
@name Developer Guide: Understanding Angular Expressions
|
@name Developer Guide: Understanding Angular Expressions
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Expressions are {@link dev_guide.templates.databinding bindings} that you write in HTML and embed
|
Expressions are {@link dev_guide.templates.databinding bindings} that you write in HTML and embed
|
||||||
in templates in order to create views in angular. Angular expressions are similar but not
|
in templates in order to create views in angular. Angular expressions are similar but not
|
||||||
equivalent to JavaScript expressions.
|
equivalent to JavaScript expressions.
|
||||||
|
|
||||||
|
|
||||||
For example, these are all valid expressions in angular:
|
For example, these are all valid expressions in angular:
|
||||||
|
|
||||||
|
|
||||||
* `1+2={{1+2}}`
|
* `1+2={{1+2}}`
|
||||||
* `3*10|currency`
|
* `3*10|currency`
|
||||||
* `Hello {{name}}!`
|
* `Hello {{name}}!`
|
||||||
* `Hello {{'World'}}!`
|
* `Hello {{'World'}}!`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Angular Expressions vs. JS Expressions
|
## Angular Expressions vs. JS Expressions
|
||||||
|
|
||||||
|
|
||||||
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
|
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
|
||||||
not entirely correct. Angular does not use a simple JavaScript eval of the expression text. You can
|
not entirely correct. Angular does not use a simple JavaScript eval of the expression text. You can
|
||||||
think of angular expressions as JavaScript expressions with these differences:
|
think of angular expressions as JavaScript expressions with these differences:
|
||||||
|
|
||||||
|
|
||||||
* **Attribute Evaluation:** evaluation of all attributes are against the current scope, not to the
|
* **Attribute Evaluation:** evaluation of all attributes are against the current scope, not to the
|
||||||
global window as in JavaScript.
|
global window as in JavaScript.
|
||||||
* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript.
|
* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript.
|
||||||
|
|
@ -38,12 +31,10 @@ conditionals, loops, or throw.
|
||||||
human-readable format.
|
human-readable format.
|
||||||
* **The $:** angular reserves this prefix to differentiate its API names from others.
|
* **The $:** angular reserves this prefix to differentiate its API names from others.
|
||||||
|
|
||||||
|
|
||||||
If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
|
If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
|
||||||
controller method and call that. If you want to `eval()` an angular expression from JavaScript, use
|
controller method and call that. If you want to `eval()` an angular expression from JavaScript, use
|
||||||
the `Scope:$eval()` method.
|
the `Scope:$eval()` method.
|
||||||
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
|
|
@ -56,10 +47,8 @@ the `Scope:$eval()` method.
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
You can try evaluating different expressions here:
|
You can try evaluating different expressions here:
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<div ng:init="exprs=[]" class="expressions">
|
<div ng:init="exprs=[]" class="expressions">
|
||||||
|
|
@ -85,18 +74,14 @@ You can try evaluating different expressions here:
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Attribute Evaluation
|
# Attribute Evaluation
|
||||||
|
|
||||||
|
|
||||||
Evaluation of all attributes takes place against the current scope. Unlike JavaScript, where names
|
Evaluation of all attributes takes place against the current scope. Unlike JavaScript, where names
|
||||||
default to global window properties, angular expressions have to use `$window` to refer to the
|
default to global window properties, angular expressions have to use `$window` to refer to the
|
||||||
global object. For example, if you want to call `alert()`, which is defined on `window`, an
|
global object. For example, if you want to call `alert()`, which is defined on `window`, an
|
||||||
expression must use `$window.alert()`. This is done intentionally to prevent accidental access to
|
expression must use `$window.alert()`. This is done intentionally to prevent accidental access to
|
||||||
the global state (a common source of subtle bugs).
|
the global state (a common source of subtle bugs).
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<div class="example2" ng:init="$window = $service('$window')">
|
<div class="example2" ng:init="$window = $service('$window')">
|
||||||
|
|
@ -121,67 +106,50 @@ the global state (a common source of subtle bugs).
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
## Forgiving
|
## Forgiving
|
||||||
|
|
||||||
|
|
||||||
Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating `a.b.c` throws
|
Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating `a.b.c` throws
|
||||||
an exception if `a` is not an object. While this makes sense for a general purpose language, the
|
an exception if `a` is not an object. While this makes sense for a general purpose language, the
|
||||||
expression evaluations are primarily used for data binding, which often look like this:
|
expression evaluations are primarily used for data binding, which often look like this:
|
||||||
|
|
||||||
|
|
||||||
{{a.b.c}}
|
{{a.b.c}}
|
||||||
|
|
||||||
|
|
||||||
It makes more sense to show nothing than to throw an exception if `a` is undefined (perhaps we are
|
It makes more sense to show nothing than to throw an exception if `a` is undefined (perhaps we are
|
||||||
waiting for the server response, and it will become defined soon). If expression evaluation wasn't
|
waiting for the server response, and it will become defined soon). If expression evaluation wasn't
|
||||||
forgiving we'd have to write bindings that clutter the code, for example: `{{((a||{}).b||{}).c}}`
|
forgiving we'd have to write bindings that clutter the code, for example: `{{((a||{}).b||{}).c}}`
|
||||||
|
|
||||||
|
|
||||||
Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined.
|
Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined.
|
||||||
|
|
||||||
|
|
||||||
Assignments work the same way in reverse:
|
Assignments work the same way in reverse:
|
||||||
|
|
||||||
|
|
||||||
a.b.c = 10
|
a.b.c = 10
|
||||||
|
|
||||||
|
|
||||||
...creates the intermediary objects even if a is undefined.
|
...creates the intermediary objects even if a is undefined.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## No Control Flow Statements
|
## No Control Flow Statements
|
||||||
|
|
||||||
|
|
||||||
You cannot write a control flow statement in an expression. The reason behind this is core to the
|
You cannot write a control flow statement in an expression. The reason behind this is core to the
|
||||||
angular philosophy that application logic should be in controllers, not in the view. If you need a
|
angular philosophy that application logic should be in controllers, not in the view. If you need a
|
||||||
conditional (including ternary operators), loop, or to throw from a view expression, delegate to a
|
conditional (including ternary operators), loop, or to throw from a view expression, delegate to a
|
||||||
JavaScript method instead.
|
JavaScript method instead.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Type Augmentation
|
## Type Augmentation
|
||||||
|
|
||||||
|
|
||||||
Built-in types have methods like `[].push()`, but the richness of these methods is limited.
|
Built-in types have methods like `[].push()`, but the richness of these methods is limited.
|
||||||
Consider the example below, which allows you to do a simple search over a canned set of contacts.
|
Consider the example below, which allows you to do a simple search over a canned set of contacts.
|
||||||
The example would be much more complicated if we did not have the `Array:$filter()`. There is no
|
The example would be much more complicated if we did not have the `Array:$filter()`. There is no
|
||||||
built-in method on `Array` called {@link api/angular.Array.filter $filter} and angular doesn't add
|
built-in method on `Array` called {@link api/angular.Array.filter $filter} and angular doesn't add
|
||||||
it to `Array.prototype` because that could collide with other JavaScript frameworks.
|
it to `Array.prototype` because that could collide with other JavaScript frameworks.
|
||||||
|
|
||||||
|
|
||||||
For this reason the scope expression evaluator augments the built-in types to make them act like
|
For this reason the scope expression evaluator augments the built-in types to make them act like
|
||||||
they have extra methods. The actual method for `$filter()` is `angular.Array.filter()`. You can
|
they have extra methods. The actual method for `$filter()` is `angular.Array.filter()`. You can
|
||||||
call it from JavaScript.
|
call it from JavaScript.
|
||||||
|
|
||||||
|
|
||||||
Extensions: You can further extend the expression vocabulary by adding new methods to
|
Extensions: You can further extend the expression vocabulary by adding new methods to
|
||||||
`angular.Array` or `angular.String`, etc.
|
`angular.Array` or `angular.String`, etc.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<div ng:init="friends = [
|
<div ng:init="friends = [
|
||||||
|
|
@ -206,48 +174,36 @@ Extensions: You can further extend the expression vocabulary by adding new metho
|
||||||
input('searchText').enter('a');
|
input('searchText').enter('a');
|
||||||
expect(tr.count()).toBe(2);
|
expect(tr.count()).toBe(2);
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
|
|
||||||
|
|
||||||
When presenting data to the user, you might need to convert the data from its raw format to a
|
When presenting data to the user, you might need to convert the data from its raw format to a
|
||||||
user-friendly format. For example, you might have a data object that needs to be formatted
|
user-friendly format. For example, you might have a data object that needs to be formatted
|
||||||
according to the locale before displaying it to the user. You can pass expressions through a chain
|
according to the locale before displaying it to the user. You can pass expressions through a chain
|
||||||
of filters like this:
|
of filters like this:
|
||||||
|
|
||||||
|
|
||||||
name | uppercase
|
name | uppercase
|
||||||
|
|
||||||
|
|
||||||
The expression evaluator simply passes the value of name to angular.filter.uppercase.
|
The expression evaluator simply passes the value of name to angular.filter.uppercase.
|
||||||
|
|
||||||
|
|
||||||
Chain filters using this syntax:
|
Chain filters using this syntax:
|
||||||
|
|
||||||
|
|
||||||
value | filter1 | filter2
|
value | filter1 | filter2
|
||||||
|
|
||||||
|
|
||||||
You can also pass colon-delimited arguments to filters, for example, to display the number 123 with
|
You can also pass colon-delimited arguments to filters, for example, to display the number 123 with
|
||||||
2 decimal points:
|
2 decimal points:
|
||||||
|
|
||||||
|
|
||||||
123 | number:2
|
123 | number:2
|
||||||
|
|
||||||
|
|
||||||
# The $
|
# The $
|
||||||
|
|
||||||
|
|
||||||
You might be wondering, what is the significance of the $ prefix? It is simply a prefix that
|
You might be wondering, what is the significance of the $ prefix? It is simply a prefix that
|
||||||
angular uses, to differentiate its API names from others. If angular didn't use $, then evaluating
|
angular uses, to differentiate its API names from others. If angular didn't use $, then evaluating
|
||||||
`a.length()` would return undefined because neither a nor angular define such a property.
|
`a.length()` would return undefined because neither a nor angular define such a property.
|
||||||
|
|
||||||
|
|
||||||
Consider that in a future version of angular we might choose to add a length method, in which case
|
Consider that in a future version of angular we might choose to add a length method, in which case
|
||||||
the behavior of the expression would change. Worse yet, you the developer could create a length
|
the behavior of the expression would change. Worse yet, you the developer could create a length
|
||||||
property and then we would have a collision. This problem exists because angular augments existing
|
property and then we would have a collision. This problem exists because angular augments existing
|
||||||
|
|
@ -255,16 +211,11 @@ objects with additional behavior. By prefixing its additions with $ we are reser
|
||||||
so that angular developers and developers who use angular can develop in harmony without collisions.
|
so that angular developers and developers who use angular can develop in harmony without collisions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
||||||
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.compile Angular Compiler API}
|
* {@link api/angular.compile Angular Compiler API}
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,24 @@
|
||||||
@name Developer Guide: Introduction
|
@name Developer Guide: Introduction
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular is pure client-side technology, written entirely in JavaScript. It works with the
|
Angular is pure client-side technology, written entirely in JavaScript. It works with the
|
||||||
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of web
|
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of web
|
||||||
apps easier and faster than ever before.
|
apps easier and faster than ever before.
|
||||||
|
|
||||||
|
|
||||||
One important way that angular simplifies web development is by increasing the level of abstraction
|
One important way that angular simplifies web development is by increasing the level of abstraction
|
||||||
between the developer and most low-level web app development tasks. Angular automatically takes
|
between the developer and most low-level web app development tasks. Angular automatically takes
|
||||||
care of many of these tasks, including:
|
care of many of these tasks, including:
|
||||||
|
|
||||||
|
|
||||||
* DOM Manipulation
|
* DOM Manipulation
|
||||||
* Setting Up Listeners and Notifiers
|
* Setting Up Listeners and Notifiers
|
||||||
* Input Validation
|
* Input Validation
|
||||||
|
|
||||||
|
|
||||||
Because angular handles much of the work involved in these tasks, developers can concentrate more
|
Because angular handles much of the work involved in these tasks, developers can concentrate more
|
||||||
on application logic and less on repetitive, error-prone, lower-level coding.
|
on application logic and less on repetitive, error-prone, lower-level coding.
|
||||||
|
|
||||||
|
|
||||||
At the same time that angular simplifies the development of web apps, it brings relatively
|
At the same time that angular simplifies the development of web apps, it brings relatively
|
||||||
sophisticated techniques to the client-side, including:
|
sophisticated techniques to the client-side, including:
|
||||||
|
|
||||||
|
|
||||||
* Separation of data, application logic, and presentation components
|
* Separation of data, application logic, and presentation components
|
||||||
* Data Binding between data and presentation components
|
* Data Binding between data and presentation components
|
||||||
* Services (common web app operations, implemented as substitutable objects)
|
* Services (common web app operations, implemented as substitutable objects)
|
||||||
|
|
@ -34,18 +28,14 @@ sophisticated techniques to the client-side, including:
|
||||||
* An extensible HTML compiler (written entirely in JavaScript)
|
* An extensible HTML compiler (written entirely in JavaScript)
|
||||||
* Ease of Testing
|
* Ease of Testing
|
||||||
|
|
||||||
|
|
||||||
These techniques have been for the most part absent from the client-side for far too long.
|
These techniques have been for the most part absent from the client-side for far too long.
|
||||||
|
|
||||||
|
|
||||||
## Single-page / Round-trip Applications
|
## Single-page / Round-trip Applications
|
||||||
|
|
||||||
|
|
||||||
You can use angular to develop both single-page and round-trip apps, but angular is designed
|
You can use angular to develop both single-page and round-trip apps, but angular is designed
|
||||||
primarily for developing single-page apps. Angular supports browser history, forward and back
|
primarily for developing single-page apps. Angular supports browser history, forward and back
|
||||||
buttons, and bookmarking in single-page apps.
|
buttons, and bookmarking in single-page apps.
|
||||||
|
|
||||||
|
|
||||||
You normally wouldn't want to load angular with every page change, as would be the case with using
|
You normally wouldn't want to load angular with every page change, as would be the case with using
|
||||||
angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
|
angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
|
||||||
angular's features (for example, templates to leverage angular's data-binding feature) to an
|
angular's features (for example, templates to leverage angular's data-binding feature) to an
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,23 @@
|
||||||
@name Developer Guide: About MVC in Angular
|
@name Developer Guide: About MVC in Angular
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
|
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
|
||||||
first appeared, angular incorporates the basic principles behind the original {@link
|
first appeared, angular incorporates the basic principles behind the original {@link
|
||||||
http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of
|
http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of
|
||||||
building client-side web applications.
|
building client-side web applications.
|
||||||
|
|
||||||
|
|
||||||
The MVC pattern greatly summarized:
|
The MVC pattern greatly summarized:
|
||||||
|
|
||||||
|
|
||||||
* Separate applications into distinct presentation, data, and logic components
|
* Separate applications into distinct presentation, data, and logic components
|
||||||
* Encourage loose coupling between these components
|
* Encourage loose coupling between these components
|
||||||
|
|
||||||
|
|
||||||
Along with {@link dev_guide.services services} and {@link dev_guide.di dependency injection}, MVC
|
Along with {@link dev_guide.services services} and {@link dev_guide.di dependency injection}, MVC
|
||||||
makes angular applications better structured, easier to maintain and more testable.
|
makes angular applications better structured, easier to maintain and more testable.
|
||||||
|
|
||||||
|
|
||||||
The following topics explain how angular incorporates the MVC pattern into the angular way of
|
The following topics explain how angular incorporates the MVC pattern into the angular way of
|
||||||
developing web applications:
|
developing web applications:
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,56 +3,43 @@
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
In angular, a controller is a JavaScript function (type/class) that is used to augment instances of
|
In angular, a controller is a JavaScript function (type/class) that is used to augment instances of
|
||||||
angular {@link dev_guide.scopes Scope}, excluding the root scope. When you or angular create a new
|
angular {@link dev_guide.scopes Scope}, excluding the root scope. When you or angular create a new
|
||||||
child scope object via the {@link api/angular.scope.$new scope.$new} API , there is an
|
child scope object via the {@link api/angular.scope.$new scope.$new} API , there is an
|
||||||
option to pass in a controller as a method argument. This will tell angular to associate the
|
option to pass in a controller as a method argument. This will tell angular to associate the
|
||||||
controller with the new scope and to augment its behavior.
|
controller with the new scope and to augment its behavior.
|
||||||
|
|
||||||
|
|
||||||
Use controllers to:
|
Use controllers to:
|
||||||
|
|
||||||
|
|
||||||
- Set up the initial state of a scope object.
|
- Set up the initial state of a scope object.
|
||||||
- Add behavior to the scope object.
|
- Add behavior to the scope object.
|
||||||
|
|
||||||
|
|
||||||
# Setting up the initial state of a scope object
|
# Setting up the initial state of a scope object
|
||||||
|
|
||||||
|
|
||||||
Typically, when you create an application you need to set up an initial state for an angular scope.
|
Typically, when you create an application you need to set up an initial state for an angular scope.
|
||||||
|
|
||||||
|
|
||||||
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
|
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
|
||||||
to a new angular scope object, which sets up an initial scope state. This means that angular never
|
to a new angular scope object, which sets up an initial scope state. This means that angular never
|
||||||
creates instances of the controller type (by invoking the `new` operator on the controller
|
creates instances of the controller type (by invoking the `new` operator on the controller
|
||||||
constructor). Constructors are always applied to an existing scope object.
|
constructor). Constructors are always applied to an existing scope object.
|
||||||
|
|
||||||
|
|
||||||
You set up the initial state of a scope by creating model properties. For example:
|
You set up the initial state of a scope by creating model properties. For example:
|
||||||
|
|
||||||
|
|
||||||
function GreetingCtrl() {
|
function GreetingCtrl() {
|
||||||
this.greeting = 'Hola!';
|
this.greeting = 'Hola!';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
|
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
|
||||||
|
|
||||||
|
|
||||||
When a controller function is applied to an angular scope object, the `this` of the controller
|
When a controller function is applied to an angular scope object, the `this` of the controller
|
||||||
function becomes the scope of the angular scope object, so any assignment to `this` within the
|
function becomes the scope of the angular scope object, so any assignment to `this` within the
|
||||||
controller function happens on the angular scope object.
|
controller function happens on the angular scope object.
|
||||||
|
|
||||||
|
|
||||||
# Adding Behavior to a Scope Object
|
# Adding Behavior to a Scope Object
|
||||||
|
|
||||||
|
|
||||||
Behavior on an angular scope object is in the form of scope method properties available to the
|
Behavior on an angular scope object is in the form of scope method properties available to the
|
||||||
template/view. This behavior interacts with and modifies the application model.
|
template/view. This behavior interacts with and modifies the application model.
|
||||||
|
|
||||||
|
|
||||||
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
||||||
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
|
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
|
||||||
the scope, along with any prototype methods of the controller type, become functions available in
|
the scope, along with any prototype methods of the controller type, become functions available in
|
||||||
|
|
@ -63,24 +50,18 @@ the `this` keyword of any controller method is always bound to the scope that th
|
||||||
augments). This is how the second task of adding behavior to the scope is accomplished.
|
augments). This is how the second task of adding behavior to the scope is accomplished.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Using Controllers Correctly
|
# Using Controllers Correctly
|
||||||
|
|
||||||
|
|
||||||
In general, a controller shouldn't try to do too much. It should contain only the business logic
|
In general, a controller shouldn't try to do too much. It should contain only the business logic
|
||||||
needed for a single view.
|
needed for a single view.
|
||||||
|
|
||||||
|
|
||||||
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
|
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
|
||||||
controllers into services and then using these services in controllers via dependency injection.
|
controllers into services and then using these services in controllers via dependency injection.
|
||||||
This is discussed in the {@link dev_guide.di Dependency Injection} {@link dev_guide.services
|
This is discussed in the {@link dev_guide.di Dependency Injection} {@link dev_guide.services
|
||||||
Services} sections of this guide.
|
Services} sections of this guide.
|
||||||
|
|
||||||
|
|
||||||
Do not use controllers for:
|
Do not use controllers for:
|
||||||
|
|
||||||
|
|
||||||
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
||||||
manipulation—the presentation logic of an application—is well known for being hard to test.
|
manipulation—the presentation logic of an application—is well known for being hard to test.
|
||||||
Putting any presentation logic into controllers significantly affects testability of the business
|
Putting any presentation logic into controllers significantly affects testability of the business
|
||||||
|
|
@ -95,40 +76,29 @@ services} instead.
|
||||||
instances).
|
instances).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Associating Controllers with Angular Scope Objects
|
# Associating Controllers with Angular Scope Objects
|
||||||
|
|
||||||
|
|
||||||
You can associate controllers with scope objects explicitly via the {@link api/angular.scope.$new
|
You can associate controllers with scope objects explicitly via the {@link api/angular.scope.$new
|
||||||
scope.$new} api or implicitly via the {@link api/angular.directive.ng:controller ng:controller
|
scope.$new} api or implicitly via the {@link api/angular.directive.ng:controller ng:controller
|
||||||
directive} or {@link api/angular.service.$route $route service}.
|
directive} or {@link api/angular.service.$route $route service}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller Constructor and Methods Example
|
## Controller Constructor and Methods Example
|
||||||
|
|
||||||
|
|
||||||
To illustrate how the controller component works in angular, let's create a little app with the
|
To illustrate how the controller component works in angular, let's create a little app with the
|
||||||
following components:
|
following components:
|
||||||
|
|
||||||
|
|
||||||
- A {@link dev_guide.templates template} with two buttons and a simple message
|
- A {@link dev_guide.templates template} with two buttons and a simple message
|
||||||
- A model consisting of a string named `spice`
|
- A model consisting of a string named `spice`
|
||||||
- A controller with two functions that set the value of `spice`
|
- A controller with two functions that set the value of `spice`
|
||||||
|
|
||||||
|
|
||||||
The message in our template contains a binding to the `spice` model, which by default is set to the
|
The message in our template contains a binding to the `spice` model, which by default is set to the
|
||||||
string "very". Depending on which button is clicked, the `spice` model is set to `chili` or
|
string "very". Depending on which button is clicked, the `spice` model is set to `chili` or
|
||||||
`jalapeño`, and the message is automatically updated by data-binding.
|
`jalapeño`, and the message is automatically updated by data-binding.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## A Spicy Controller Example
|
## A Spicy Controller Example
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<body ng:controller="SpicyCtrl">
|
<body ng:controller="SpicyCtrl">
|
||||||
<button ng:click="chiliSpicy()">Chili</button>
|
<button ng:click="chiliSpicy()">Chili</button>
|
||||||
|
|
@ -136,7 +106,6 @@ string "very". Depending on which button is clicked, the `spice` model is set to
|
||||||
<p>The food is {{spice}} spicy!</p>
|
<p>The food is {{spice}} spicy!</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
function SpicyCtrl() {
|
function SpicyCtrl() {
|
||||||
this.spice = 'very';
|
this.spice = 'very';
|
||||||
this.chiliSpicy = function() {
|
this.chiliSpicy = function() {
|
||||||
|
|
@ -144,16 +113,13 @@ function SpicyCtrl() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SpicyCtrl.prototype.jalapenoSpicy = function() {
|
SpicyCtrl.prototype.jalapenoSpicy = function() {
|
||||||
this.spice = 'jalapeño';
|
this.spice = 'jalapeño';
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Things to notice in the example above:
|
Things to notice in the example above:
|
||||||
|
|
||||||
|
|
||||||
- The `ng:controller` directive is used to (implicitly) create a scope for our template, and the
|
- The `ng:controller` directive is used to (implicitly) create a scope for our template, and the
|
||||||
scope is augmented (managed) by the `SpicyCtrl` controller.
|
scope is augmented (managed) by the `SpicyCtrl` controller.
|
||||||
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
|
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
|
||||||
|
|
@ -166,14 +132,11 @@ as prototype methods of the controller constructor function (the `jalapenoSpicy`
|
||||||
- Both controller methods are available in the template (for the `body` element and and its
|
- Both controller methods are available in the template (for the `body` element and and its
|
||||||
children).
|
children).
|
||||||
|
|
||||||
|
|
||||||
Controller methods can also take arguments, as demonstrated in the following variation of the
|
Controller methods can also take arguments, as demonstrated in the following variation of the
|
||||||
previous example.
|
previous example.
|
||||||
|
|
||||||
|
|
||||||
## Controller Method Arguments Example
|
## Controller Method Arguments Example
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<body ng:controller="SpicyCtrl">
|
<body ng:controller="SpicyCtrl">
|
||||||
<input name="customSpice" value="wasabi">
|
<input name="customSpice" value="wasabi">
|
||||||
|
|
@ -182,7 +145,6 @@ previous example.
|
||||||
<p>The food is {{spice}} spicy!</p>
|
<p>The food is {{spice}} spicy!</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
function SpicyCtrl() {
|
function SpicyCtrl() {
|
||||||
this.spice = 'very';
|
this.spice = 'very';
|
||||||
this.spicy = function(spice) {
|
this.spicy = function(spice) {
|
||||||
|
|
@ -191,22 +153,17 @@ function SpicyCtrl() {
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Notice that the `SpicyCtrl` controller now defines just one method called `spicy`, which takes one
|
Notice that the `SpicyCtrl` controller now defines just one method called `spicy`, which takes one
|
||||||
argument called `spice`. The template then refers to this controller method and passes in a string
|
argument called `spice`. The template then refers to this controller method and passes in a string
|
||||||
constant `'chili'` in the binding for the first button and a model property `spice` (bound to an
|
constant `'chili'` in the binding for the first button and a model property `spice` (bound to an
|
||||||
input box) in the second button.
|
input box) in the second button.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller Inheritance Example
|
## Controller Inheritance Example
|
||||||
|
|
||||||
|
|
||||||
Controller inheritance in angular is based on {@link api/angular.scope Scope} inheritance. Let's
|
Controller inheritance in angular is based on {@link api/angular.scope Scope} inheritance. Let's
|
||||||
have a look at an example:
|
have a look at an example:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<body ng:controller="MainCtrl">
|
<body ng:controller="MainCtrl">
|
||||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||||
|
|
@ -215,29 +172,24 @@ have a look at an example:
|
||||||
<p ng:controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
<p ng:controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
function MainCtrl() {
|
function MainCtrl() {
|
||||||
this.timeOfDay = 'morning';
|
this.timeOfDay = 'morning';
|
||||||
this.name = 'Nikki';
|
this.name = 'Nikki';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ChildCtrl() {
|
function ChildCtrl() {
|
||||||
this.name = 'Mattie';
|
this.name = 'Mattie';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function BabyCtrl() {
|
function BabyCtrl() {
|
||||||
this.timeOfDay = 'evening';
|
this.timeOfDay = 'evening';
|
||||||
this.name = 'Gingerbreak Baby';
|
this.name = 'Gingerbreak Baby';
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Notice how we nested three `ng:controller` directives in our template. This template construct will
|
Notice how we nested three `ng:controller` directives in our template. This template construct will
|
||||||
result in 4 scopes being created for our view:
|
result in 4 scopes being created for our view:
|
||||||
|
|
||||||
|
|
||||||
- The root scope
|
- The root scope
|
||||||
- The `MainCtrl` scope, which contains `timeOfDay` and `name` models
|
- The `MainCtrl` scope, which contains `timeOfDay` and `name` models
|
||||||
- The `ChildCtrl` scope, which shadows the `name` model from the previous scope and inherits the
|
- The `ChildCtrl` scope, which shadows the `name` model from the previous scope and inherits the
|
||||||
|
|
@ -245,28 +197,21 @@ result in 4 scopes being created for our view:
|
||||||
- The `BabyCtrl` scope, which shadows both the `timeOfDay` model defined in `MainCtrl` and `name`
|
- The `BabyCtrl` scope, which shadows both the `timeOfDay` model defined in `MainCtrl` and `name`
|
||||||
model defined in the ChildCtrl
|
model defined in the ChildCtrl
|
||||||
|
|
||||||
|
|
||||||
Inheritance works between controllers in the same way as it does with models. So in our previous
|
Inheritance works between controllers in the same way as it does with models. So in our previous
|
||||||
examples, all of the models could be replaced with controller methods that return string values.
|
examples, all of the models could be replaced with controller methods that return string values.
|
||||||
|
|
||||||
|
|
||||||
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
|
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
|
||||||
because as we mentioned earlier, controllers are not instantiated directly by angular, but rather
|
because as we mentioned earlier, controllers are not instantiated directly by angular, but rather
|
||||||
are applied to the scope object.
|
are applied to the scope object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Testing Controllers
|
## Testing Controllers
|
||||||
|
|
||||||
|
|
||||||
The way to test a controller depends upon how complicated the controller is.
|
The way to test a controller depends upon how complicated the controller is.
|
||||||
|
|
||||||
|
|
||||||
- If your controller doesn't use DI or scope methods — create the controller with the `new`
|
- If your controller doesn't use DI or scope methods — create the controller with the `new`
|
||||||
operator and test away. For example:
|
operator and test away. For example:
|
||||||
|
|
||||||
|
|
||||||
Controller Function:
|
Controller Function:
|
||||||
<pre>
|
<pre>
|
||||||
function myController() {
|
function myController() {
|
||||||
|
|
@ -274,31 +219,25 @@ function myController() {
|
||||||
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
|
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
|
||||||
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
|
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
|
||||||
|
|
||||||
|
|
||||||
this.spice = "habanero";
|
this.spice = "habanero";
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Controller Test:
|
Controller Test:
|
||||||
<pre>
|
<pre>
|
||||||
describe('myController function', function() {
|
describe('myController function', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('myController', function(){
|
describe('myController', function(){
|
||||||
var ctrl;
|
var ctrl;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
ctrl = new myController();
|
ctrl = new myController();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should create "spices" model with 3 spices', function() {
|
it('should create "spices" model with 3 spices', function() {
|
||||||
expect(ctrl.spices.length).toBe(3);
|
expect(ctrl.spices.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should set the default value of spice', function() {
|
it('should set the default value of spice', function() {
|
||||||
expect(ctrl.spice).toBe('habanero');
|
expect(ctrl.spice).toBe('habanero');
|
||||||
});
|
});
|
||||||
|
|
@ -306,18 +245,16 @@ describe('myController function', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
- If your controller does use DI or scope methods — create a root scope, then create the controller
|
- If your controller does use DI or scope methods — create a root scope, then create the controller
|
||||||
in the root scope with `scope.$new(MyController)`. Test the controller using `$eval`, if necessary.
|
in the root scope with `scope.$new(MyController)`. Test the controller using `$eval`, if necessary.
|
||||||
- If you need to test a nested controller that depends on its parent's state — create a root scope,
|
- If you need to test a nested controller that depends on its parent's state — create a root scope,
|
||||||
create a parent scope, create a child scope, and test the controller using $eval if necessary.
|
create a parent scope, create a child scope, and test the controller using $eval if necessary.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc About MVC in Angular}
|
* {@link dev_guide.mvc About MVC in Angular}
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,94 +3,70 @@
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Depending on the context of the discussion in angular documentation, the term _model_ can refer to
|
Depending on the context of the discussion in angular documentation, the term _model_ can refer to
|
||||||
either a single object representing one entity (for example, a model called "phones" with its value
|
either a single object representing one entity (for example, a model called "phones" with its value
|
||||||
being an array of phones) or the entire data model for the application (all entities).
|
being an array of phones) or the entire data model for the application (all entities).
|
||||||
|
|
||||||
|
|
||||||
In angular, a model is any data that is reachable as a property of an angular {@link
|
In angular, a model is any data that is reachable as a property of an angular {@link
|
||||||
dev_guide.scopes Scope} object. The name of the property is the model identifier and the value is
|
dev_guide.scopes Scope} object. The name of the property is the model identifier and the value is
|
||||||
any JavaScript object (including arrays and primitives).
|
any JavaScript object (including arrays and primitives).
|
||||||
|
|
||||||
|
|
||||||
The only requirement for a JavaScript object to be a model in angular is that the object must be
|
The only requirement for a JavaScript object to be a model in angular is that the object must be
|
||||||
referenced by an angular scope as a property of that scope object. This property reference can be
|
referenced by an angular scope as a property of that scope object. This property reference can be
|
||||||
created explicitly or implicitly.
|
created explicitly or implicitly.
|
||||||
|
|
||||||
|
|
||||||
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
||||||
following ways:
|
following ways:
|
||||||
|
|
||||||
|
|
||||||
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
|
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
|
||||||
occurs in controllers:
|
occurs in controllers:
|
||||||
|
|
||||||
|
|
||||||
function MyCtrl() {
|
function MyCtrl() {
|
||||||
// create property 'foo' on the MyCtrl's scope
|
// create property 'foo' on the MyCtrl's scope
|
||||||
// and assign it an initial value 'bar'
|
// and assign it an initial value 'bar'
|
||||||
this.foo = 'bar';
|
this.foo = 'bar';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
* Use an {@link dev_guide.expressions angular expression} with an assignment operator in templates:
|
* Use an {@link dev_guide.expressions angular expression} with an assignment operator in templates:
|
||||||
|
|
||||||
|
|
||||||
<button ng:click="{{foos='ball'}}">Click me</button>
|
<button ng:click="{{foos='ball'}}">Click me</button>
|
||||||
|
|
||||||
|
|
||||||
* Use {@link api/angular.directive.ng:init ng:init directive} in templates (for toy/example apps
|
* Use {@link api/angular.directive.ng:init ng:init directive} in templates (for toy/example apps
|
||||||
only, not recommended for real applications):
|
only, not recommended for real applications):
|
||||||
|
|
||||||
|
|
||||||
<body ng:init=" foo = 'bar' ">
|
<body ng:init=" foo = 'bar' ">
|
||||||
|
|
||||||
|
|
||||||
Angular creates models implicitly (by creating a scope property and assigning it a suitable value)
|
Angular creates models implicitly (by creating a scope property and assigning it a suitable value)
|
||||||
when processing the following template constructs:
|
when processing the following template constructs:
|
||||||
|
|
||||||
|
|
||||||
* Form input, select, and textarea elements:
|
* Form input, select, and textarea elements:
|
||||||
|
|
||||||
|
|
||||||
<input name="query" value="fluffy cloud">
|
<input name="query" value="fluffy cloud">
|
||||||
|
|
||||||
The code above creates a model called "query" on the current scope with the value set to "fluffy
|
The code above creates a model called "query" on the current scope with the value set to "fluffy
|
||||||
cloud".
|
cloud".
|
||||||
|
|
||||||
|
|
||||||
* An iterator declaration in {@link api/angular.widget.@ng:repeat ng:repeater}:
|
* An iterator declaration in {@link api/angular.widget.@ng:repeat ng:repeater}:
|
||||||
|
|
||||||
|
|
||||||
<p ng:repeat="phone in phones"></p>
|
<p ng:repeat="phone in phones"></p>
|
||||||
|
|
||||||
|
|
||||||
The code above creates one child scope for each item in the "phones" array and creates a "phone"
|
The code above creates one child scope for each item in the "phones" array and creates a "phone"
|
||||||
object (model) on each of these scopes with its value set to the value of "phone" in the array.
|
object (model) on each of these scopes with its value set to the value of "phone" in the array.
|
||||||
|
|
||||||
|
|
||||||
In angular, a JavaScript object stops being a model when:
|
In angular, a JavaScript object stops being a model when:
|
||||||
|
|
||||||
|
|
||||||
* No angular scope contains a property that references the object.
|
* No angular scope contains a property that references the object.
|
||||||
|
|
||||||
|
|
||||||
* All angular scopes that contain a property referencing the object become stale and eligible for
|
* All angular scopes that contain a property referencing the object become stale and eligible for
|
||||||
garbage collection.
|
garbage collection.
|
||||||
|
|
||||||
|
|
||||||
The following illustration shows a simple data model created implicitly from a simple template:
|
The following illustration shows a simple data model created implicitly from a simple template:
|
||||||
|
|
||||||
|
|
||||||
<img src="img/guide/about_model_final.png">
|
<img src="img/guide/about_model_final.png">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc About MVC in Angular}
|
* {@link dev_guide.mvc About MVC in Angular}
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,11 @@
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the View Component
|
@name Developer Guide: About MVC in Angular: Understanding the View Component
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
In angular, the view is the DOM loaded and rendered in the browser, after angular has transformed
|
In angular, the view is the DOM loaded and rendered in the browser, after angular has transformed
|
||||||
the DOM based on information in the template, controller and model.
|
the DOM based on information in the template, controller and model.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/guide/about_view_final.png">
|
<img src="img/guide/about_view_final.png">
|
||||||
|
|
||||||
|
|
||||||
In the angular implementation of MVC, the view has knowledge of both the model and the controller.
|
In the angular implementation of MVC, the view has knowledge of both the model and the controller.
|
||||||
The view knows about the model where two-way data-binding occurs. The view has knowledge of the
|
The view knows about the model where two-way data-binding occurs. The view has knowledge of the
|
||||||
controller through angular directives, such as {@link api/angular.directive.ng:controller
|
controller through angular directives, such as {@link api/angular.directive.ng:controller
|
||||||
|
|
@ -19,11 +16,8 @@ ng:controller} and {@link api/angular.widget.ng:view ng:view}, and through bindi
|
||||||
controller function.
|
controller function.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc About MVC in Angular}
|
* {@link dev_guide.mvc About MVC in Angular}
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,25 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# What Is Angular?
|
# What Is Angular?
|
||||||
|
|
||||||
|
|
||||||
The short answer: angular is a new, powerful, client-side technology that makes it much easier for
|
The short answer: angular is a new, powerful, client-side technology that makes it much easier for
|
||||||
you to create dynamic web sites and complex web apps, all without leaving the comfort of your HTML
|
you to create dynamic web sites and complex web apps, all without leaving the comfort of your HTML
|
||||||
/ JavaScript home.
|
/ JavaScript home.
|
||||||
|
|
||||||
|
|
||||||
The long answer: it depends on where you're coming from...
|
The long answer: it depends on where you're coming from...
|
||||||
|
|
||||||
|
|
||||||
* If you're a web designer, you might perceive angular to be a sweet {@link dev_guide.templates
|
* If you're a web designer, you might perceive angular to be a sweet {@link dev_guide.templates
|
||||||
templating} system, that doesn't get in your way and provides you with lots of nice built-ins that
|
templating} system, that doesn't get in your way and provides you with lots of nice built-ins that
|
||||||
make it easier to do what you want to do.
|
make it easier to do what you want to do.
|
||||||
|
|
||||||
|
|
||||||
* If you're a web developer, you might be thrilled that angular functions as an excellent web
|
* If you're a web developer, you might be thrilled that angular functions as an excellent web
|
||||||
framework, one that assists you all the way through the development cycle.
|
framework, one that assists you all the way through the development cycle.
|
||||||
|
|
||||||
|
|
||||||
* If you want to go deeper, you can immerse yourself in angular's extensible HTML {@link
|
* If you want to go deeper, you can immerse yourself in angular's extensible HTML {@link
|
||||||
dev_guide.compiler compiler} that runs in your browser. The angular compiler teaches your browser
|
dev_guide.compiler compiler} that runs in your browser. The angular compiler teaches your browser
|
||||||
new tricks.
|
new tricks.
|
||||||
|
|
||||||
|
|
||||||
Angular is not just a templating system, but you can create fantastic templates with it. Angular is
|
Angular is not just a templating system, but you can create fantastic templates with it. Angular is
|
||||||
not just a web framework, but it features a very nice framework. Angular is not just an extensible
|
not just a web framework, but it features a very nice framework. Angular is not just an extensible
|
||||||
HTML compiler, but the compiler is at the core of Angular. Angular includes all of these
|
HTML compiler, but the compiler is at the core of Angular. Angular includes all of these
|
||||||
|
|
@ -37,22 +29,17 @@ components, along with others. Angular is far greater than the sum of its parts.
|
||||||
better way to develop web applications!
|
better way to develop web applications!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## An Introductory Angular Example
|
## An Introductory Angular Example
|
||||||
|
|
||||||
|
|
||||||
Let's say that you are a web designer, and you've spent many thous — erm, hundreds of hours
|
Let's say that you are a web designer, and you've spent many thous — erm, hundreds of hours
|
||||||
designing web sites. But at this point, the thought of manipulating the DOM, writing listeners and
|
designing web sites. But at this point, the thought of manipulating the DOM, writing listeners and
|
||||||
input validators, all just to implement a simple form? No. You either don't want to go there in
|
input validators, all just to implement a simple form? No. You either don't want to go there in
|
||||||
the first place or you've been there and the thrill is gone.
|
the first place or you've been there and the thrill is gone.
|
||||||
|
|
||||||
|
|
||||||
So look over the following simple example written using angular. Note that it features only the
|
So look over the following simple example written using angular. Note that it features only the
|
||||||
templating aspect of angular, but this should suffice for now to quickly demonstrate how much
|
templating aspect of angular, but this should suffice for now to quickly demonstrate how much
|
||||||
easier a web developer's life can if they're using angular:
|
easier a web developer's life can if they're using angular:
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<b>Invoice:</b>
|
<b>Invoice:</b>
|
||||||
|
|
@ -85,43 +72,32 @@ ng:required/></td>
|
||||||
-->
|
-->
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
Try out the Live Preview above, and then let's walk through the example and describe what's going
|
Try out the Live Preview above, and then let's walk through the example and describe what's going
|
||||||
on.
|
on.
|
||||||
|
|
||||||
|
|
||||||
In the `<html>` tag, we add an attribute to let the browser know about the angular namespace:
|
In the `<html>` tag, we add an attribute to let the browser know about the angular namespace:
|
||||||
|
|
||||||
|
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
||||||
|
|
||||||
This ensures angular runs nicely in all major browsers.
|
This ensures angular runs nicely in all major browsers.
|
||||||
|
|
||||||
|
|
||||||
In the `<script>` tag we do two angular setup tasks:
|
In the `<script>` tag we do two angular setup tasks:
|
||||||
|
|
||||||
|
|
||||||
1. We load `angular.js`.
|
1. We load `angular.js`.
|
||||||
2. The angular {@link api/angular.directive.ng:autobind ng:autobind} directive tells angular to
|
2. The angular {@link api/angular.directive.ng:autobind ng:autobind} directive tells angular to
|
||||||
{@link dev_guide.compiler compile} and manage the whole HTML document.
|
{@link dev_guide.compiler compile} and manage the whole HTML document.
|
||||||
|
|
||||||
|
|
||||||
`<script src="http://code.angularjs.org/0.9.15/angular-0.9.15.min.js"
|
`<script src="http://code.angularjs.org/0.9.15/angular-0.9.15.min.js"
|
||||||
ng:autobind></script>`
|
ng:autobind></script>`
|
||||||
|
|
||||||
|
|
||||||
From the `name` attribute of the `<input>` tags, angular automatically sets up two-way data
|
From the `name` attribute of the `<input>` tags, angular automatically sets up two-way data
|
||||||
binding, and we also demonstrate some easy input validation:
|
binding, and we also demonstrate some easy input validation:
|
||||||
|
|
||||||
|
|
||||||
Quantity: <input name="qty" value="1" ng:validate="integer:0" ng:required/>
|
Quantity: <input name="qty" value="1" ng:validate="integer:0" ng:required/>
|
||||||
Cost: <input name="cost" value="199.95" ng:validate="number" ng:required/>
|
Cost: <input name="cost" value="199.95" ng:validate="number" ng:required/>
|
||||||
|
|
||||||
|
|
||||||
These input widgets look normal enough, but consider these points:
|
These input widgets look normal enough, but consider these points:
|
||||||
|
|
||||||
|
|
||||||
* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to
|
* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to
|
||||||
variables of the same name. Think of those variables as the "Model" component of the
|
variables of the same name. Think of those variables as the "Model" component of the
|
||||||
Model-View-Controller design pattern.
|
Model-View-Controller design pattern.
|
||||||
|
|
@ -131,13 +107,10 @@ or leave the the input fields blank, the borders turn red color, and the display
|
||||||
These `ng:` directives make it easier to implement field validators than coding them in JavaScript,
|
These `ng:` directives make it easier to implement field validators than coding them in JavaScript,
|
||||||
no? Yes.
|
no? Yes.
|
||||||
|
|
||||||
|
|
||||||
And finally, the mysterious `{{ double curly braces }}`:
|
And finally, the mysterious `{{ double curly braces }}`:
|
||||||
|
|
||||||
|
|
||||||
Total: {{qty * cost | currency}}
|
Total: {{qty * cost | currency}}
|
||||||
|
|
||||||
|
|
||||||
This notation, `{{ _expression_ }}`, is a bit of built-in angular {@link dev_guide.compiler.markup
|
This notation, `{{ _expression_ }}`, is a bit of built-in angular {@link dev_guide.compiler.markup
|
||||||
markup}, a shortcut for displaying data to the user. The expression within curly braces gets
|
markup}, a shortcut for displaying data to the user. The expression within curly braces gets
|
||||||
transformed by the angular compiler into an angular directive ({@link api/angular.directive.ng:bind
|
transformed by the angular compiler into an angular directive ({@link api/angular.directive.ng:bind
|
||||||
|
|
@ -145,36 +118,28 @@ ng:bind}). The expression itself can be a combination of both an expression and
|
||||||
dev_guide.templates.filters filter}: `{{ expression | filter }}`. Angular provides filters for
|
dev_guide.templates.filters filter}: `{{ expression | filter }}`. Angular provides filters for
|
||||||
formatting display data.
|
formatting display data.
|
||||||
|
|
||||||
|
|
||||||
In the example above, the expression in double-curly braces directs angular to, "Bind the data we
|
In the example above, the expression in double-curly braces directs angular to, "Bind the data we
|
||||||
got from the input widgets to the display, multiply them together, and format the resulting number
|
got from the input widgets to the display, multiply them together, and format the resulting number
|
||||||
into output that looks like money."
|
into output that looks like money."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The Angular Philosophy
|
# The Angular Philosophy
|
||||||
|
|
||||||
|
|
||||||
Angular is built around the belief that declarative code is better than imperative when it comes to
|
Angular is built around the belief that declarative code is better than imperative when it comes to
|
||||||
building UIs and wiring software components together, while imperative code is excellent for
|
building UIs and wiring software components together, while imperative code is excellent for
|
||||||
expressing business logic.
|
expressing business logic.
|
||||||
|
|
||||||
|
|
||||||
Not to put too fine a point on it, but if you wanted to add a new label to your application, you
|
Not to put too fine a point on it, but if you wanted to add a new label to your application, you
|
||||||
could do so by simply adding text to the HTML template, saving the code, and refreshing your
|
could do so by simply adding text to the HTML template, saving the code, and refreshing your
|
||||||
browser:
|
browser:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<span class="label">Hello</span>
|
<span class="label">Hello</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Or, as in programmatic systems (like {@link http://code.google.com/webtoolkit/ GWT}), you would
|
Or, as in programmatic systems (like {@link http://code.google.com/webtoolkit/ GWT}), you would
|
||||||
have to write the code and then run the code like this:
|
have to write the code and then run the code like this:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
label.setText('Hello');
|
label.setText('Hello');
|
||||||
|
|
@ -182,15 +147,11 @@ label.setClass('label');
|
||||||
parent.addChild(label);
|
parent.addChild(label);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
That's one line of markup versus four times as much code.
|
That's one line of markup versus four times as much code.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## More Angular Philosophy
|
## More Angular Philosophy
|
||||||
|
|
||||||
|
|
||||||
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
|
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
|
||||||
the testability of the code.
|
the testability of the code.
|
||||||
* It is a really, _really_ good idea to regard app testing as equal in importance to app writing.
|
* It is a really, _really_ good idea to regard app testing as equal in importance to app writing.
|
||||||
|
|
@ -201,11 +162,9 @@ development work to progress in parallel, and allows for reuse of both sides.
|
||||||
building an app: from designing the UI, through writing the business logic, to testing.
|
building an app: from designing the UI, through writing the business logic, to testing.
|
||||||
* It is always good to make common tasks trivial and difficult tasks possible.
|
* It is always good to make common tasks trivial and difficult tasks possible.
|
||||||
|
|
||||||
|
|
||||||
Now that we're homing in on what angular is, perhaps now would be a good time to list a few things
|
Now that we're homing in on what angular is, perhaps now would be a good time to list a few things
|
||||||
that angular is not:
|
that angular is not:
|
||||||
|
|
||||||
|
|
||||||
* It's not a Library. You don't just call its functions, although it does provide you with some
|
* It's not a Library. You don't just call its functions, although it does provide you with some
|
||||||
utility APIs.
|
utility APIs.
|
||||||
* It's not a DOM Manipulation Library. Angular uses jQuery to manipulate the DOM behind the scenes,
|
* It's not a DOM Manipulation Library. Angular uses jQuery to manipulate the DOM behind the scenes,
|
||||||
|
|
@ -225,14 +184,10 @@ changes to the model are automatically reflected in the view. Any changes by the
|
||||||
are automatically reflected in the model.
|
are automatically reflected in the model.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Why You Want Angular
|
# Why You Want Angular
|
||||||
|
|
||||||
|
|
||||||
Angular frees you from the following pain:
|
Angular frees you from the following pain:
|
||||||
|
|
||||||
|
|
||||||
* **Registering callbacks:** Registering callbacks clutters your code, making it hard to see the
|
* **Registering callbacks:** Registering callbacks clutters your code, making it hard to see the
|
||||||
forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It vastly
|
forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It vastly
|
||||||
reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see what your
|
reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see what your
|
||||||
|
|
@ -256,15 +211,11 @@ get started developing features quickly. As a bonus, you get full control over t
|
||||||
process in automated tests.
|
process in automated tests.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Watch a Presentation About Angular
|
# Watch a Presentation About Angular
|
||||||
|
|
||||||
|
|
||||||
Here is an early presentation on angular, but note that substantial development has occurred since
|
Here is an early presentation on angular, but note that substantial development has occurred since
|
||||||
the talk was given in July of 2010.
|
the talk was given in July of 2010.
|
||||||
|
|
||||||
|
|
||||||
<object width="480" height="385">
|
<object width="480" height="385">
|
||||||
<param name="movie" value="http://www.youtube.com/v/elvcgVSynRg&hl=en_US&fs=1"></param>
|
<param name="movie" value="http://www.youtube.com/v/elvcgVSynRg&hl=en_US&fs=1"></param>
|
||||||
<param name="allowFullScreen" value="true"></param>
|
<param name="allowFullScreen" value="true"></param>
|
||||||
|
|
@ -274,7 +225,6 @@ the talk was given in July of 2010.
|
||||||
allowfullscreen="true" width="480" height="385"></embed>
|
allowfullscreen="true" width="480" height="385"></embed>
|
||||||
</object>
|
</object>
|
||||||
|
|
||||||
|
|
||||||
{@link
|
{@link
|
||||||
|
|
||||||
https://docs.google.com/present/edit?id=0Abz6S2TvsDWSZDQ0OWdjaF8yNTRnODczazdmZg&hl=en&authkey=CO-b7oID
|
https://docs.google.com/present/edit?id=0Abz6S2TvsDWSZDQ0OWdjaF8yNTRnODczazdmZg&hl=en&authkey=CO-b7oID
|
||||||
|
|
|
||||||
|
|
@ -3,48 +3,37 @@
|
||||||
@name Developer Guide: Scopes: Applying Controllers to Scopes
|
@name Developer Guide: Scopes: Applying Controllers to Scopes
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
When a controller function is applied to a scope, the scope is augmented with the behavior defined
|
When a controller function is applied to a scope, the scope is augmented with the behavior defined
|
||||||
in the controller. The end result is that the scope behaves as if it were the controller:
|
in the controller. The end result is that the scope behaves as if it were the controller:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var scope = angular.scope();
|
var scope = angular.scope();
|
||||||
scope.salutation = 'Hello';
|
scope.salutation = 'Hello';
|
||||||
scope.name = 'World';
|
scope.name = 'World';
|
||||||
|
|
||||||
|
|
||||||
expect(scope.greeting).toEqual(undefined);
|
expect(scope.greeting).toEqual(undefined);
|
||||||
|
|
||||||
|
|
||||||
scope.$watch('name', function(){
|
scope.$watch('name', function(){
|
||||||
this.greeting = this.salutation + ' ' + this.name + '!';
|
this.greeting = this.salutation + ' ' + this.name + '!';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
expect(scope.greeting).toEqual('Hello World!');
|
expect(scope.greeting).toEqual('Hello World!');
|
||||||
scope.name = 'Misko';
|
scope.name = 'Misko';
|
||||||
// scope.$eval() will propagate the change to listeners
|
// scope.$eval() will propagate the change to listeners
|
||||||
expect(scope.greeting).toEqual('Hello World!');
|
expect(scope.greeting).toEqual('Hello World!');
|
||||||
|
|
||||||
|
|
||||||
scope.$eval();
|
scope.$eval();
|
||||||
expect(scope.greeting).toEqual('Hello Misko!');
|
expect(scope.greeting).toEqual('Hello Misko!');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes Angular Scope Objects}
|
* {@link dev_guide.scopes Angular Scope Objects}
|
||||||
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scopes}
|
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scopes}
|
||||||
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
|
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
|
||||||
* {@link dev_guide.scopes.updating_scopes Updating Angular Scopes}
|
* {@link dev_guide.scopes.updating_scopes Updating Angular Scopes}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.scope Angular Scope API}
|
* {@link api/angular.scope Angular Scope API}
|
||||||
|
|
|
||||||
|
|
@ -4,48 +4,35 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
An angular scope is a JavaScript type defined by angular. Instances of this type are objects that
|
An angular scope is a JavaScript type defined by angular. Instances of this type are objects that
|
||||||
serve as the context within which all model and controller methods live and get evaluated.
|
serve as the context within which all model and controller methods live and get evaluated.
|
||||||
|
|
||||||
|
|
||||||
Angular links scope objects to specific points in a compiled (processed) template. This linkage
|
Angular links scope objects to specific points in a compiled (processed) template. This linkage
|
||||||
provides the contexts in which angular creates data-bindings between the model and the view. You
|
provides the contexts in which angular creates data-bindings between the model and the view. You
|
||||||
can think of angular scope objects as the medium through which the model, view, and controller
|
can think of angular scope objects as the medium through which the model, view, and controller
|
||||||
communicate.
|
communicate.
|
||||||
|
|
||||||
|
|
||||||
In addition to providing the context in which data is evaluated, angular scope objects watch for
|
In addition to providing the context in which data is evaluated, angular scope objects watch for
|
||||||
model changes. The scope objects also notify all components interested in any model changes (for
|
model changes. The scope objects also notify all components interested in any model changes (for
|
||||||
example, functions registered through {@link api/angular.scope.$watch $watch}, bindings created by
|
example, functions registered through {@link api/angular.scope.$watch $watch}, bindings created by
|
||||||
{@link api/angular.directive.ng:bind ng:bind}, or HTML input elements).
|
{@link api/angular.directive.ng:bind ng:bind}, or HTML input elements).
|
||||||
|
|
||||||
|
|
||||||
Angular scope objects are responsible for:
|
Angular scope objects are responsible for:
|
||||||
|
|
||||||
|
|
||||||
* Gluing the model, controller and view template together.
|
* Gluing the model, controller and view template together.
|
||||||
* Providing the mechanism to watch for model changes ({@link api/angular.scope.$watch}).
|
* Providing the mechanism to watch for model changes ({@link api/angular.scope.$watch}).
|
||||||
* Notifying interested components when the model changes ({@link api/angular.scope.$eval}).
|
* Notifying interested components when the model changes ({@link api/angular.scope.$eval}).
|
||||||
* Providing the context in which all controller functions and angular expressions are evaluated.
|
* Providing the context in which all controller functions and angular expressions are evaluated.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
|
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
|
||||||
* {@link dev_guide.scopes.working_scopes Working With Scopes}
|
* {@link dev_guide.scopes.working_scopes Working With Scopes}
|
||||||
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
||||||
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
|
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.scope Angular Scope API}
|
* {@link api/angular.scope Angular Scope API}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
@name Developer Guide: Scopes: Understanding Scopes
|
@name Developer Guide: Scopes: Understanding Scopes
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular automatically creates a root scope during initialization, and attaches it to the page's
|
Angular automatically creates a root scope during initialization, and attaches it to the page's
|
||||||
root DOM element (usually `<html>`). The root scope object, along with any of its child scope
|
root DOM element (usually `<html>`). The root scope object, along with any of its child scope
|
||||||
objects, serves as the infrastructure on which your data model is built. The data model (JavaScript
|
objects, serves as the infrastructure on which your data model is built. The data model (JavaScript
|
||||||
|
|
@ -11,20 +10,16 @@ objects, arrays, or primitives) is attached to angular scope properties. Angular
|
||||||
values to the DOM where bindings are specified in the template. Angular attaches any controller
|
values to the DOM where bindings are specified in the template. Angular attaches any controller
|
||||||
functions you have created to their respective scope objects.
|
functions you have created to their respective scope objects.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/guide/simple_scope_final.png">
|
<img src="img/guide/simple_scope_final.png">
|
||||||
|
|
||||||
|
|
||||||
Angular scopes can be nested, so a child scope has a parent scope upstream in the DOM. When you
|
Angular scopes can be nested, so a child scope has a parent scope upstream in the DOM. When you
|
||||||
display an angular expression in the view, angular walks the DOM tree looking in the closest
|
display an angular expression in the view, angular walks the DOM tree looking in the closest
|
||||||
attached scope object for the specified data. If it doesn't find the data in the closest attached
|
attached scope object for the specified data. If it doesn't find the data in the closest attached
|
||||||
scope, it looks further up the scope hierarchy until it finds the data.
|
scope, it looks further up the scope hierarchy until it finds the data.
|
||||||
|
|
||||||
|
|
||||||
A child scope object inherits properties from its parents. For example, in the following snippet of
|
A child scope object inherits properties from its parents. For example, in the following snippet of
|
||||||
code, observe how the value of `name` changes, based on the HTML element it is displayed in:
|
code, observe how the value of `name` changes, based on the HTML element it is displayed in:
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<ul ng:init="name='Hank'; names=['Igor', 'Misko', 'Gail', 'Kai']">
|
<ul ng:init="name='Hank'; names=['Igor', 'Misko', 'Gail', 'Kai']">
|
||||||
|
|
@ -41,7 +36,6 @@ code, observe how the value of `name` changes, based on the HTML element it is d
|
||||||
expect(using('.doc-example-live').repeater('li').row(1)).
|
expect(using('.doc-example-live').repeater('li').row(1)).
|
||||||
toEqual(['Misko']);
|
toEqual(['Misko']);
|
||||||
|
|
||||||
|
|
||||||
expect(using('.doc-example-live').repeater('li').row(2)).
|
expect(using('.doc-example-live').repeater('li').row(2)).
|
||||||
toEqual(['Gail']);
|
toEqual(['Gail']);
|
||||||
expect(using('.doc-example-live').repeater('li').row(3)).
|
expect(using('.doc-example-live').repeater('li').row(3)).
|
||||||
|
|
@ -52,32 +46,24 @@ code, observe how the value of `name` changes, based on the HTML element it is d
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
The angular {@link api/angular.widget.@ng:repeat ng:repeat} directive creates a new scope for each
|
The angular {@link api/angular.widget.@ng:repeat ng:repeat} directive creates a new scope for each
|
||||||
element that it repeats (in this example the elements are list items). In the `<ul>` element, we
|
element that it repeats (in this example the elements are list items). In the `<ul>` element, we
|
||||||
initialized `name` to "Hank", and we created an array called `names` to use as the data source for
|
initialized `name` to "Hank", and we created an array called `names` to use as the data source for
|
||||||
the list items. In each `<li>` element, `name` is overridden. Outside of the `<li>` repeater, the
|
the list items. In each `<li>` element, `name` is overridden. Outside of the `<li>` repeater, the
|
||||||
original value of `name` is displayed.
|
original value of `name` is displayed.
|
||||||
|
|
||||||
|
|
||||||
The following illustration shows the DOM and angular scopes for the example above:
|
The following illustration shows the DOM and angular scopes for the example above:
|
||||||
|
|
||||||
|
|
||||||
<img src="img/guide/dom_scope_final.png">
|
<img src="img/guide/dom_scope_final.png">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes Angular Scope Objects}
|
* {@link dev_guide.scopes Angular Scope Objects}
|
||||||
* {@link dev_guide.scopes.working_scopes Working With Scopes}
|
* {@link dev_guide.scopes.working_scopes Working With Scopes}
|
||||||
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
||||||
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
|
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.scope Angular Scope API}
|
* {@link api/angular.scope Angular Scope API}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,16 @@
|
||||||
@name Developer Guide: Scopes: Updating Scope Properties
|
@name Developer Guide: Scopes: Updating Scope Properties
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
You can update a scope by calling its {@link api/angular.scope.$eval $eval()} method, but usually
|
You can update a scope by calling its {@link api/angular.scope.$eval $eval()} method, but usually
|
||||||
you do not have to do this explicitly. In most cases, angular intercepts all external events (such
|
you do not have to do this explicitly. In most cases, angular intercepts all external events (such
|
||||||
as user interactions, XHRs, and timers) and calls the `$eval()` method on the scope object for you
|
as user interactions, XHRs, and timers) and calls the `$eval()` method on the scope object for you
|
||||||
at the right time. The only time you might need to call `$eval()` explicitly is when you create
|
at the right time. The only time you might need to call `$eval()` explicitly is when you create
|
||||||
your own custom widget or service.
|
your own custom widget or service.
|
||||||
|
|
||||||
|
|
||||||
The reason it is unnecessary to call `$eval()` from within your controller functions when you use
|
The reason it is unnecessary to call `$eval()` from within your controller functions when you use
|
||||||
built-in angular widgets and services is because a change in the data model triggers a call to the
|
built-in angular widgets and services is because a change in the data model triggers a call to the
|
||||||
`$eval()` method on the scope object where the data model changed.
|
`$eval()` method on the scope object where the data model changed.
|
||||||
|
|
||||||
|
|
||||||
When a user inputs data, angularized widgets copy the data to the appropriate scope and then call
|
When a user inputs data, angularized widgets copy the data to the appropriate scope and then call
|
||||||
the `$eval()` method on the root scope to update the view. It works this way because scopes are
|
the `$eval()` method on the root scope to update the view. It works this way because scopes are
|
||||||
inherited, and a child scope `$eval()` overrides its parent's `$eval()` method. Updating the whole
|
inherited, and a child scope `$eval()` overrides its parent's `$eval()` method. Updating the whole
|
||||||
|
|
@ -23,25 +20,19 @@ page requires a call to `$eval()` on the root scope as `$root.$eval()`. Similarl
|
||||||
to fetch data from a server is made and the response comes back, the data is written into the model
|
to fetch data from a server is made and the response comes back, the data is written into the model
|
||||||
and then `$eval()` is called to push updates through to the view and any other dependents.
|
and then `$eval()` is called to push updates through to the view and any other dependents.
|
||||||
|
|
||||||
|
|
||||||
A widget that creates scopes (such as {@link api/angular.widget.@ng:repeat ng:repeat}) is
|
A widget that creates scopes (such as {@link api/angular.widget.@ng:repeat ng:repeat}) is
|
||||||
responsible for forwarding `$eval()` calls from the parent to those child scopes. That way, calling
|
responsible for forwarding `$eval()` calls from the parent to those child scopes. That way, calling
|
||||||
`$eval()` on the root scope will update the whole page. This creates a spreadsheet-like behavior
|
`$eval()` on the root scope will update the whole page. This creates a spreadsheet-like behavior
|
||||||
for your app; the bound views update immediately as the user enters data.
|
for your app; the bound views update immediately as the user enters data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Documents
|
## Related Documents
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes Angular Scope Objects}
|
* {@link dev_guide.scopes Angular Scope Objects}
|
||||||
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects}
|
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects}
|
||||||
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
|
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
|
||||||
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.scope Angular Scope API}
|
* {@link api/angular.scope Angular Scope API}
|
||||||
|
|
|
||||||
|
|
@ -3,27 +3,22 @@
|
||||||
@name Developer Guide: Scopes: Working With Angular Scopes
|
@name Developer Guide: Scopes: Working With Angular Scopes
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
When you use {@link api/angular.directive.ng:autobind ng:autobind} to bootstrap your application,
|
When you use {@link api/angular.directive.ng:autobind ng:autobind} to bootstrap your application,
|
||||||
angular creates the root scope automatically for you. If you need more control over the
|
angular creates the root scope automatically for you. If you need more control over the
|
||||||
bootstrapping process, or if you need to create a root scope for a test, you can do so using the
|
bootstrapping process, or if you need to create a root scope for a test, you can do so using the
|
||||||
{@link api/angular.scope angular.scope()} API.
|
{@link api/angular.scope angular.scope()} API.
|
||||||
|
|
||||||
|
|
||||||
Here is a simple code snippet that demonstrates how to create a scope object, assign model
|
Here is a simple code snippet that demonstrates how to create a scope object, assign model
|
||||||
properties to it, and register listeners to watch for changes to the model properties:
|
properties to it, and register listeners to watch for changes to the model properties:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var scope = angular.scope();
|
var scope = angular.scope();
|
||||||
scope.salutation = 'Hello';
|
scope.salutation = 'Hello';
|
||||||
scope.name = 'World';
|
scope.name = 'World';
|
||||||
|
|
||||||
|
|
||||||
// Verify that greeting is undefined
|
// Verify that greeting is undefined
|
||||||
expect(scope.greeting).toEqual(undefined);
|
expect(scope.greeting).toEqual(undefined);
|
||||||
|
|
||||||
|
|
||||||
// Set up the watcher...
|
// Set up the watcher...
|
||||||
scope.$watch('name', function(){
|
scope.$watch('name', function(){
|
||||||
// when 'name' changes, set 'greeting'...
|
// when 'name' changes, set 'greeting'...
|
||||||
|
|
@ -31,35 +26,27 @@ this.greeting = this.salutation + ' ' + this.name + '!';
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// verify that 'greeting' was set...
|
// verify that 'greeting' was set...
|
||||||
expect(scope.greeting).toEqual('Hello World!');
|
expect(scope.greeting).toEqual('Hello World!');
|
||||||
|
|
||||||
|
|
||||||
// 'name' changed!
|
// 'name' changed!
|
||||||
scope.name = 'Misko';
|
scope.name = 'Misko';
|
||||||
|
|
||||||
|
|
||||||
// scope.$eval() will propagate the change to listeners
|
// scope.$eval() will propagate the change to listeners
|
||||||
expect(scope.greeting).toEqual('Hello World!');
|
expect(scope.greeting).toEqual('Hello World!');
|
||||||
|
|
||||||
|
|
||||||
scope.$eval();
|
scope.$eval();
|
||||||
// verify that '$eval' propagated the change
|
// verify that '$eval' propagated the change
|
||||||
expect(scope.greeting).toEqual('Hello Misko!');
|
expect(scope.greeting).toEqual('Hello Misko!');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes Angular Scope Objects}
|
* {@link dev_guide.scopes Angular Scope Objects}
|
||||||
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
|
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
|
||||||
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
||||||
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
|
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.scope Angular Scope API}
|
* {@link api/angular.scope Angular Scope API}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,12 @@
|
||||||
@name Developer Guide: Angular Services: Creating Angular Services
|
@name Developer Guide: Angular Services: Creating Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
While angular offers several useful services, for any nontrivial application you'll find it useful
|
While angular offers several useful services, for any nontrivial application you'll find it useful
|
||||||
to write your own custom services. To do this you begin by registering a service factory function
|
to write your own custom services. To do this you begin by registering a service factory function
|
||||||
that angular's DI will use to create the service object when it is needed.
|
that angular's DI will use to create the service object when it is needed.
|
||||||
|
|
||||||
|
|
||||||
The `angular.service` method accepts three parameters:
|
The `angular.service` method accepts three parameters:
|
||||||
|
|
||||||
|
|
||||||
- `{string} name` - Name of the service.
|
- `{string} name` - Name of the service.
|
||||||
- `{function()} factory` - Factory function (called just once by DI).
|
- `{function()} factory` - Factory function (called just once by DI).
|
||||||
- `{Object} config` - Configuration object with the following properties:
|
- `{Object} config` - Configuration object with the following properties:
|
||||||
|
|
@ -22,23 +19,19 @@ array. Defaults to `[]`.
|
||||||
instantiated when angular boots. If false, the service will be lazily instantiated when it is first
|
instantiated when angular boots. If false, the service will be lazily instantiated when it is first
|
||||||
requested during instantiation of a dependant. Defaults to `false`.
|
requested during instantiation of a dependant. Defaults to `false`.
|
||||||
|
|
||||||
|
|
||||||
The `this` of the factory function is bound to the root scope of the angular application.
|
The `this` of the factory function is bound to the root scope of the angular application.
|
||||||
|
|
||||||
|
|
||||||
All angular services participate in {@link dev_guide.di dependency injection (DI)} by registering
|
All angular services participate in {@link dev_guide.di dependency injection (DI)} by registering
|
||||||
themselves with angular's DI system (injector) under a `name` (id) as well as by declaring
|
themselves with angular's DI system (injector) under a `name` (id) as well as by declaring
|
||||||
dependencies which need to be provided for the factory function of the registered service. The
|
dependencies which need to be provided for the factory function of the registered service. The
|
||||||
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
||||||
testable.
|
testable.
|
||||||
|
|
||||||
|
|
||||||
Following is an example of a very simple service. This service depends on the `$window` service
|
Following is an example of a very simple service. This service depends on the `$window` service
|
||||||
(which is passed as a parameter to the factory function) and is just a function. The service simply
|
(which is passed as a parameter to the factory function) and is just a function. The service simply
|
||||||
stores all notifications; after the third one, the service displays all of the notifications by
|
stores all notifications; after the third one, the service displays all of the notifications by
|
||||||
window alert.
|
window alert.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.service('notify', function(win) {
|
angular.service('notify', function(win) {
|
||||||
var msgs = [];
|
var msgs = [];
|
||||||
|
|
@ -53,19 +46,14 @@ window alert.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.registering_services Registering Angular Services}
|
* {@link dev_guide.services.registering_services Registering Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Angular Service API}
|
* {@link api/angular.service Angular Service API}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
@name Developer Guide: Angular Services: Injecting Services Into Controllers
|
@name Developer Guide: Angular Services: Injecting Services Into Controllers
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Using services as dependencies for controllers is very similar to using services as dependencies
|
Using services as dependencies for controllers is very similar to using services as dependencies
|
||||||
for another service.
|
for another service.
|
||||||
|
|
||||||
|
|
||||||
Since JavaScript is a dynamic language, DI can't figure out which services to inject by static
|
Since JavaScript is a dynamic language, DI can't figure out which services to inject by static
|
||||||
types (like in static typed languages). Therefore, you must specify the service name by using the
|
types (like in static typed languages). Therefore, you must specify the service name by using the
|
||||||
`$inject` property, which is an array containing strings with names of services to be injected.
|
`$inject` property, which is an array containing strings with names of services to be injected.
|
||||||
|
|
@ -16,7 +14,6 @@ IDs matters: the order of the services in the array will be used when calling th
|
||||||
with injected parameters. The names of parameters in factory function don't matter, but by
|
with injected parameters. The names of parameters in factory function don't matter, but by
|
||||||
convention they match the service IDs.
|
convention they match the service IDs.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function myController($loc, $log) {
|
function myController($loc, $log) {
|
||||||
this.firstMethod = function() {
|
this.firstMethod = function() {
|
||||||
|
|
@ -32,7 +29,6 @@ this.secondMethod = function() {
|
||||||
myController.$inject = ['$location', '$log'];
|
myController.$inject = ['$location', '$log'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
@ -47,18 +43,15 @@ angular.service('notify', function(win) {
|
||||||
};
|
};
|
||||||
}, {$inject: ['$window']});
|
}, {$inject: ['$window']});
|
||||||
|
|
||||||
|
|
||||||
function myController(notifyService) {
|
function myController(notifyService) {
|
||||||
this.callNotify = function(msg) {
|
this.callNotify = function(msg) {
|
||||||
notifyService(msg);
|
notifyService(msg);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
myController.$inject = ['notify'];
|
myController.$inject = ['notify'];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div ng:controller="myController">
|
<div ng:controller="myController">
|
||||||
<p>Let's try this simple notify service, injected into the controller...</p>
|
<p>Let's try this simple notify service, injected into the controller...</p>
|
||||||
<input ng:init="message='test'" type="text" name="message" />
|
<input ng:init="message='test'" type="text" name="message" />
|
||||||
|
|
@ -73,19 +66,14 @@ it('should test service', function(){
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
{@link dev_guide.services.understanding_services Understanding Angular Services}
|
{@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
{@link dev_guide.services.creating_services Creating Angular Services}
|
{@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
{@link dev_guide.services.registering_services Registering Angular Services}
|
{@link dev_guide.services.registering_services Registering Angular Services}
|
||||||
{@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
{@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
{@link dev_guide.services.testing_services Testing Angular Services}
|
{@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
{@link api/angular.service Angular Service API}
|
{@link api/angular.service Angular Service API}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,16 @@
|
||||||
@name Developer Guide: Angular Services: Managing Service Dependencies
|
@name Developer Guide: Angular Services: Managing Service Dependencies
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular allows services to declare other services as dependencies needed for construction of their
|
Angular allows services to declare other services as dependencies needed for construction of their
|
||||||
instances.
|
instances.
|
||||||
|
|
||||||
|
|
||||||
To declare dependencies, you specify them in the factory function signature and via the `$inject`
|
To declare dependencies, you specify them in the factory function signature and via the `$inject`
|
||||||
property, as an array of string identifiers. Optionally the `$inject` property declaration can be
|
property, as an array of string identifiers. Optionally the `$inject` property declaration can be
|
||||||
dropped (see "Inferring `$inject`" but note that that is currently an experimental feature).
|
dropped (see "Inferring `$inject`" but note that that is currently an experimental feature).
|
||||||
|
|
||||||
|
|
||||||
Here is an example of two services that depend on each other, as well as on other services that are
|
Here is an example of two services that depend on each other, as well as on other services that are
|
||||||
provided by angular's web framework:
|
provided by angular's web framework:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
/**
|
/**
|
||||||
* batchLog service allows for messages to be queued in memory and flushed
|
* batchLog service allows for messages to be queued in memory and flushed
|
||||||
|
|
@ -27,7 +23,6 @@ provided by angular's web framework:
|
||||||
angular.service('batchLog', function($defer, $log) {
|
angular.service('batchLog', function($defer, $log) {
|
||||||
var messageQueue = [];
|
var messageQueue = [];
|
||||||
|
|
||||||
|
|
||||||
function log() {
|
function log() {
|
||||||
if (messageQueue.length) {
|
if (messageQueue.length) {
|
||||||
$log('batchLog messages: ', messageQueue);
|
$log('batchLog messages: ', messageQueue);
|
||||||
|
|
@ -36,14 +31,12 @@ function log() {
|
||||||
$defer(log, 50000);
|
$defer(log, 50000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return function(message) {
|
return function(message) {
|
||||||
messageQueue.push(message);
|
messageQueue.push(message);
|
||||||
}
|
}
|
||||||
}, {$inject: ['$defer', '$log']);
|
}, {$inject: ['$defer', '$log']);
|
||||||
// note how we declared dependency on built-in $defer and $log services above
|
// note how we declared dependency on built-in $defer and $log services above
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* routeTemplateMonitor monitors each $route change and logs the current
|
* routeTemplateMonitor monitors each $route change and logs the current
|
||||||
* template via the batchLog service.
|
* template via the batchLog service.
|
||||||
|
|
@ -55,10 +48,8 @@ $route.onChange(function() {
|
||||||
}, {$inject: ['$route', 'batchLog'], $eager: true});
|
}, {$inject: ['$route', 'batchLog'], $eager: true});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Things to notice in this example:
|
Things to notice in this example:
|
||||||
|
|
||||||
|
|
||||||
* The `batchLog` service depends on the built-in {@link api/angular.service.$defer $defer} and
|
* The `batchLog` service depends on the built-in {@link api/angular.service.$defer $defer} and
|
||||||
{@link api/angular.service.$log $log} services, and allows messages to be logged into the
|
{@link api/angular.service.$log $log} services, and allows messages to be logged into the
|
||||||
`console.log` in batches.
|
`console.log` in batches.
|
||||||
|
|
@ -77,20 +68,15 @@ this array with IDs and their order that the injector uses to determine which se
|
||||||
order to inject.
|
order to inject.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.registering_services Registering Services}
|
* {@link dev_guide.services.registering_services Registering Services}
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Angular Service API}
|
* {@link api/angular.service Angular Service API}
|
||||||
* {@link api/angular.injector Angular Injector API}
|
* {@link api/angular.injector Angular Injector API}
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,14 @@
|
||||||
@name Developer Guide: Angular Services
|
@name Developer Guide: Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Services are a feature that angular brings to client-side web apps from the server side, where
|
Services are a feature that angular brings to client-side web apps from the server side, where
|
||||||
services have been commonly used for a long time. Services in angular apps are substitutable
|
services have been commonly used for a long time. Services in angular apps are substitutable
|
||||||
objects that are wired together using {@link dev_guide.di dependency injection (DI)}. Services are
|
objects that are wired together using {@link dev_guide.di dependency injection (DI)}. Services are
|
||||||
most often used with {@link dev_guide.di dependency injection}, also a key feature of angular apps.
|
most often used with {@link dev_guide.di dependency injection}, also a key feature of angular apps.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.registering_services Registering Angular Services}
|
* {@link dev_guide.services.registering_services Registering Angular Services}
|
||||||
|
|
@ -22,8 +18,6 @@ most often used with {@link dev_guide.di dependency injection}, also a key featu
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Angular Service API}
|
* {@link api/angular.service Angular Service API}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,10 @@
|
||||||
@name Developer Guide: Angular Services: Registering Angular Services
|
@name Developer Guide: Angular Services: Registering Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
To register a service, register a factory function that creates the service with angular's
|
To register a service, register a factory function that creates the service with angular's
|
||||||
Injector. The Injector is exposed as {@link api/angular.scope.$service scope.$service}. The
|
Injector. The Injector is exposed as {@link api/angular.scope.$service scope.$service}. The
|
||||||
following pseudo-code shows a simple service registration:
|
following pseudo-code shows a simple service registration:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.service('service id', function() {
|
angular.service('service id', function() {
|
||||||
var shinyNewServiceInstance;
|
var shinyNewServiceInstance;
|
||||||
|
|
@ -17,27 +15,21 @@ angular.service('service id', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Note that you are not registering a service instance, but rather a factory function that will
|
Note that you are not registering a service instance, but rather a factory function that will
|
||||||
create this instance when called.
|
create this instance when called.
|
||||||
|
|
||||||
|
|
||||||
# Instantiating Angular Services
|
# Instantiating Angular Services
|
||||||
|
|
||||||
|
|
||||||
A service can be instantiated eagerly or lazily. By default angular instantiates services lazily,
|
A service can be instantiated eagerly or lazily. By default angular instantiates services lazily,
|
||||||
which means that a service will be created only when it is needed for instantiation of a service or
|
which means that a service will be created only when it is needed for instantiation of a service or
|
||||||
an application component that depends on it. In other words, angular won't instantiate lazy
|
an application component that depends on it. In other words, angular won't instantiate lazy
|
||||||
services unless they are requested directly or indirectly by the application.
|
services unless they are requested directly or indirectly by the application.
|
||||||
|
|
||||||
|
|
||||||
Eager services on the other hand, are instantiated right after the injector itself is created,
|
Eager services on the other hand, are instantiated right after the injector itself is created,
|
||||||
which happens when the angular {@link dev_guide.bootstrap application initializes}.
|
which happens when the angular {@link dev_guide.bootstrap application initializes}.
|
||||||
|
|
||||||
|
|
||||||
To override the default, you can request that a service is eagerly instantiated as follows:
|
To override the default, you can request that a service is eagerly instantiated as follows:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.service('service id', function() {
|
angular.service('service id', function() {
|
||||||
var shinyNewServiceInstance;
|
var shinyNewServiceInstance;
|
||||||
|
|
@ -46,12 +38,10 @@ angular.service('service id', function() {
|
||||||
}, {$eager: true});
|
}, {$eager: true});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
While it is tempting to declare services as eager, only in few cases it is actually useful. If you
|
While it is tempting to declare services as eager, only in few cases it is actually useful. If you
|
||||||
are unsure whether to make a service eager, it likely doesn't need to be. To be more specific, a
|
are unsure whether to make a service eager, it likely doesn't need to be. To be more specific, a
|
||||||
service should be declared as eager only if it fits one of these scenarios:
|
service should be declared as eager only if it fits one of these scenarios:
|
||||||
|
|
||||||
|
|
||||||
* Nothing in your application declares this service as its dependency, and this service affects the
|
* Nothing in your application declares this service as its dependency, and this service affects the
|
||||||
state or configuration of the application (e.g. a service that configures `$route` or `$resource`
|
state or configuration of the application (e.g. a service that configures `$route` or `$resource`
|
||||||
services)
|
services)
|
||||||
|
|
@ -60,7 +50,6 @@ because the service passively observes the application and it is optional for ot
|
||||||
components to depend on it. An example of this scenario is a service that monitors and logs
|
components to depend on it. An example of this scenario is a service that monitors and logs
|
||||||
application memory usage.
|
application memory usage.
|
||||||
|
|
||||||
|
|
||||||
Lastly, it is important to realize that all angular services are applicaiton singletons. This means
|
Lastly, it is important to realize that all angular services are applicaiton singletons. This means
|
||||||
that there is only one instance of a given service per injector. Since angular is lethally allergic
|
that there is only one instance of a given service per injector. Since angular is lethally allergic
|
||||||
to the global state, it is possible to create multiple injectors, each with its own instance of a
|
to the global state, it is possible to create multiple injectors, each with its own instance of a
|
||||||
|
|
@ -68,19 +57,14 @@ given service, but that is rarely needed, except in tests where this property is
|
||||||
important.
|
important.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Angular Service API}
|
* {@link api/angular.service Angular Service API}
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,24 @@
|
||||||
@name Developer Guide: Angular Services: Testing Angular Services
|
@name Developer Guide: Angular Services: Testing Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Following is a unit test for the service in the example in {@link
|
Following is a unit test for the service in the example in {@link
|
||||||
dev_guide.services.registering_services Registering Angular Services}. The unit test example uses
|
dev_guide.services.registering_services Registering Angular Services}. The unit test example uses
|
||||||
Jasmine spy (mock) instead of a real browser alert.
|
Jasmine spy (mock) instead of a real browser alert.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var mock, notify;
|
var mock, notify;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
mock = {alert: jasmine.createSpy()};
|
mock = {alert: jasmine.createSpy()};
|
||||||
notify = angular.service('notify')(mock);
|
notify = angular.service('notify')(mock);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should not alert first two notifications', function() {
|
it('should not alert first two notifications', function() {
|
||||||
notify('one');
|
notify('one');
|
||||||
notify('two');
|
notify('two');
|
||||||
expect(mock.alert).not.toHaveBeenCalled();
|
expect(mock.alert).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should alert all after third notification', function() {
|
it('should alert all after third notification', function() {
|
||||||
notify('one');
|
notify('one');
|
||||||
notify('two');
|
notify('two');
|
||||||
|
|
@ -33,7 +28,6 @@ notify('three');
|
||||||
expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
|
expect(mock.alert).toHaveBeenCalledWith("one\ntwo\nthree");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should clear messages after alert', function() {
|
it('should clear messages after alert', function() {
|
||||||
notify('one');
|
notify('one');
|
||||||
notify('two');
|
notify('two');
|
||||||
|
|
@ -47,24 +41,16 @@ expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.registering_services Registering Angular Services}
|
* {@link dev_guide.services.registering_services Registering Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Angular Service API}
|
* {@link api/angular.service Angular Service API}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,46 +3,36 @@
|
||||||
@name Developer Guide: Angular Services: Understanding Angular Services
|
@name Developer Guide: Angular Services: Understanding Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular services are singletons that carry out specific tasks common to web apps, such as the
|
Angular services are singletons that carry out specific tasks common to web apps, such as the
|
||||||
{@link api/angular.service.$xhr $xhr service} that provides low level access to the browser's
|
{@link api/angular.service.$xhr $xhr service} that provides low level access to the browser's
|
||||||
`XMLHttpRequest` object.
|
`XMLHttpRequest` object.
|
||||||
|
|
||||||
|
|
||||||
To use an angular service, you identify it as a dependency for the dependent (a controller, or
|
To use an angular service, you identify it as a dependency for the dependent (a controller, or
|
||||||
another service) that depends on the service. Angular's dependency injection subsystem takes care
|
another service) that depends on the service. Angular's dependency injection subsystem takes care
|
||||||
of the rest. The angular injector subsystem is in charge of service instantiation, resolution of
|
of the rest. The angular injector subsystem is in charge of service instantiation, resolution of
|
||||||
dependencies, and provision of dependencies to factory functions as requested.
|
dependencies, and provision of dependencies to factory functions as requested.
|
||||||
|
|
||||||
|
|
||||||
Angular injects dependencies using "constructor" injection (the service is passed in via a factory
|
Angular injects dependencies using "constructor" injection (the service is passed in via a factory
|
||||||
function). Because JavaScript is a dynamically typed language, angular's dependency injection
|
function). Because JavaScript is a dynamically typed language, angular's dependency injection
|
||||||
subsystem cannot use static types to identify service dependencies. For this reason a dependent
|
subsystem cannot use static types to identify service dependencies. For this reason a dependent
|
||||||
must explicitly define its dependencies by using the `$inject` property. For example:
|
must explicitly define its dependencies by using the `$inject` property. For example:
|
||||||
|
|
||||||
|
|
||||||
myController.$inject = ['$location'];
|
myController.$inject = ['$location'];
|
||||||
|
|
||||||
|
|
||||||
The angular web framework provides a set of services for common operations. Like other core angular
|
The angular web framework provides a set of services for common operations. Like other core angular
|
||||||
variables and identifiers, the built-in services always start with `$` (such as `$xhr` mentioned
|
variables and identifiers, the built-in services always start with `$` (such as `$xhr` mentioned
|
||||||
above). You can also create your own custom services.
|
above). You can also create your own custom services.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.di About Angular Dependency Injection}
|
* {@link dev_guide.di About Angular Dependency Injection}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.registering_services Registering Angular Services}
|
* {@link dev_guide.services.registering_services Registering Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.service Angular Service API}
|
* {@link api/angular.service Angular Service API}
|
||||||
* {@link api/angular.injector Injector API}
|
* {@link api/angular.injector Injector API}
|
||||||
|
|
|
||||||
|
|
@ -4,66 +4,48 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Angular includes built-in CSS classes, which in turn have predefined CSS styles.
|
Angular includes built-in CSS classes, which in turn have predefined CSS styles.
|
||||||
|
|
||||||
|
|
||||||
# Built-in CSS classes
|
# Built-in CSS classes
|
||||||
|
|
||||||
|
|
||||||
* `ng-exception`
|
* `ng-exception`
|
||||||
|
|
||||||
|
|
||||||
**Usage:** angular applies this class to a DOM element if that element contains an Expression that
|
**Usage:** angular applies this class to a DOM element if that element contains an Expression that
|
||||||
threw an exception when evaluated.
|
threw an exception when evaluated.
|
||||||
|
|
||||||
|
|
||||||
**Styling:** The built-in styling of the ng-exception class displays an error message surrounded
|
**Styling:** The built-in styling of the ng-exception class displays an error message surrounded
|
||||||
by a solid red border, for example:
|
by a solid red border, for example:
|
||||||
|
|
||||||
|
|
||||||
<div class="ng-exception">Error message</div>
|
<div class="ng-exception">Error message</div>
|
||||||
|
|
||||||
|
|
||||||
You can try to evaluate malformed expressions in {@link dev_guide.expressions expressions} to see
|
You can try to evaluate malformed expressions in {@link dev_guide.expressions expressions} to see
|
||||||
the `ng-exception` class' styling.
|
the `ng-exception` class' styling.
|
||||||
|
|
||||||
|
|
||||||
* `ng-validation-error`
|
* `ng-validation-error`
|
||||||
|
|
||||||
|
|
||||||
**Usage:** angular applies this class to an input widget element if that element's input does not
|
**Usage:** angular applies this class to an input widget element if that element's input does not
|
||||||
pass validation. Note that you set the validation criteria on the input widget element using the
|
pass validation. Note that you set the validation criteria on the input widget element using the
|
||||||
Ng:validate or Ng:required directives.
|
Ng:validate or Ng:required directives.
|
||||||
|
|
||||||
|
|
||||||
**Styling:** The built-in styling of the ng-validation-error class turns the border of the input
|
**Styling:** The built-in styling of the ng-validation-error class turns the border of the input
|
||||||
box red and includes a hovering UI element that includes more details of the validation error. You
|
box red and includes a hovering UI element that includes more details of the validation error. You
|
||||||
can see an example in {@link api/angular.widget.@ng:validate ng:validate example}.
|
can see an example in {@link api/angular.widget.@ng:validate ng:validate example}.
|
||||||
|
|
||||||
|
|
||||||
## Overriding Styles for Angular CSS Classes
|
## Overriding Styles for Angular CSS Classes
|
||||||
|
|
||||||
|
|
||||||
To override the styles for angular's built-in CSS classes, you can do any of the following:
|
To override the styles for angular's built-in CSS classes, you can do any of the following:
|
||||||
|
|
||||||
|
|
||||||
* Download the source code, edit angular.css, and host the source on your own server.
|
* Download the source code, edit angular.css, and host the source on your own server.
|
||||||
* Create a local CSS file, overriding any styles that you'd like, and link to it from your HTML file
|
* Create a local CSS file, overriding any styles that you'd like, and link to it from your HTML file
|
||||||
as you normally would:
|
as you normally would:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<link href="yourfile.css" rel="stylesheet" type="text/css">
|
<link href="yourfile.css" rel="stylesheet" type="text/css">
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates Angular Templates}
|
* {@link dev_guide.templates Angular Templates}
|
||||||
* {@link dev_guide.templates.css Working With CSS in Angular}
|
* {@link dev_guide.templates.css Working With CSS in Angular}
|
||||||
* {@link dev_guide.templates.formatters Angular Formatters}
|
* {@link dev_guide.templates.formatters Angular Formatters}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,13 @@
|
||||||
@name Developer Guide: Templates: Data Binding in Angular
|
@name Developer Guide: Templates: Data Binding in Angular
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Data-binding in angular web apps is the automatic syncing of data between the model and view
|
Data-binding in angular web apps is the automatic syncing of data between the model and view
|
||||||
components. The way that angular implements data-binding lets you treat the model as the
|
components. The way that angular implements data-binding lets you treat the model as the
|
||||||
single-source-of-truth in your application. The view is a projection of the model at all times.
|
single-source-of-truth in your application. The view is a projection of the model at all times.
|
||||||
When the model changes, the view reflects the change, and vice versa.
|
When the model changes, the view reflects the change, and vice versa.
|
||||||
|
|
||||||
|
|
||||||
## Data Binding in Classical Template Systems
|
## Data Binding in Classical Template Systems
|
||||||
|
|
||||||
|
|
||||||
<img class="right" src="img/One_Way_Data_Binding.png"/>
|
<img class="right" src="img/One_Way_Data_Binding.png"/>
|
||||||
Most templating systems bind data in only one direction: they merge template and model components
|
Most templating systems bind data in only one direction: they merge template and model components
|
||||||
together into a view, as illustrated in the diagram. After the merge occurs, changes to the model
|
together into a view, as illustrated in the diagram. After the merge occurs, changes to the model
|
||||||
|
|
@ -20,10 +17,8 @@ or related sections of the view are NOT automatically reflected in the view. Wor
|
||||||
that the user makes to the view are not reflected in the model. This means that the developer has
|
that the user makes to the view are not reflected in the model. This means that the developer has
|
||||||
to write code that constantly syncs the view with the model and the model with the view.
|
to write code that constantly syncs the view with the model and the model with the view.
|
||||||
|
|
||||||
|
|
||||||
## Data Binding in Angular Templates
|
## Data Binding in Angular Templates
|
||||||
|
|
||||||
|
|
||||||
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
||||||
The way angular templates works is different, as illustrated in the diagram. They are different
|
The way angular templates works is different, as illustrated in the diagram. They are different
|
||||||
because first the template (which is the uncompiled HTML along with any additional markup or
|
because first the template (which is the uncompiled HTML along with any additional markup or
|
||||||
|
|
@ -33,16 +28,12 @@ the model are propagated to the view. This makes the model always the single-sou
|
||||||
the application state, greatly simplifying the programing model for the developer. You can think of
|
the application state, greatly simplifying the programing model for the developer. You can think of
|
||||||
the view as simply an instant projection of your model.
|
the view as simply an instant projection of your model.
|
||||||
|
|
||||||
|
|
||||||
Because the view is just a projection of the model, the controller is completely separated from the
|
Because the view is just a projection of the model, the controller is completely separated from the
|
||||||
view and unaware of it. This makes testing a snap because it is easy to test your controller in
|
view and unaware of it. This makes testing a snap because it is easy to test your controller in
|
||||||
isolation without the view and the related DOM/browser dependency.
|
isolation without the view and the related DOM/browser dependency.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes Angular Scopes}
|
* {@link dev_guide.scopes Angular Scopes}
|
||||||
* {@link dev_guide.templates Angular Templates}
|
* {@link dev_guide.templates Angular Templates}
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,20 @@
|
||||||
@name Developer Guide: Templates: Filters: Creating Angular Filters
|
@name Developer Guide: Templates: Filters: Creating Angular Filters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Writing your own filter is very easy: just define a JavaScript function on the `angular.filter`
|
Writing your own filter is very easy: just define a JavaScript function on the `angular.filter`
|
||||||
object.
|
object.
|
||||||
The framework passes in the input value as the first argument to your function. Any filter
|
The framework passes in the input value as the first argument to your function. Any filter
|
||||||
arguments are passed in as additional function arguments.
|
arguments are passed in as additional function arguments.
|
||||||
|
|
||||||
|
|
||||||
You can use these variables in the function:
|
You can use these variables in the function:
|
||||||
|
|
||||||
|
|
||||||
* `this` — The current scope.
|
* `this` — The current scope.
|
||||||
* `this.$element` — The DOM element containing the binding. The `$element` variable allows the
|
* `this.$element` — The DOM element containing the binding. The `$element` variable allows the
|
||||||
filter to manipulate the DOM.
|
filter to manipulate the DOM.
|
||||||
|
|
||||||
|
|
||||||
The following sample filter reverses a text string. In addition, it conditionally makes the
|
The following sample filter reverses a text string. In addition, it conditionally makes the
|
||||||
text upper-case and assigns color.
|
text upper-case and assigns color.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
@ -42,7 +37,6 @@ text upper-case and assigns color.
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<input name="text" type="text" value="hello" /><br>
|
<input name="text" type="text" value="hello" /><br>
|
||||||
No filter: {{text}}<br>
|
No filter: {{text}}<br>
|
||||||
Reverse: {{text|reverse}}<br>
|
Reverse: {{text|reverse}}<br>
|
||||||
|
|
@ -59,16 +53,11 @@ expect(binding('text|reverse')).toEqual('CBA');
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
||||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.filter Angular Filter API}
|
* {@link api/angular.filter Angular Filter API}
|
||||||
|
|
|
||||||
|
|
@ -3,36 +3,26 @@
|
||||||
@name Developer Guide: Templates: Understanding Angular Filters
|
@name Developer Guide: Templates: Understanding Angular Filters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular filters format data for display to the user. In addition to formatting data, filters can
|
Angular filters format data for display to the user. In addition to formatting data, filters can
|
||||||
also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles
|
also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles
|
||||||
to filtered output.
|
to filtered output.
|
||||||
|
|
||||||
|
|
||||||
For example, you might have a data object that needs to be formatted according to the locale before
|
For example, you might have a data object that needs to be formatted according to the locale before
|
||||||
displaying it to the user. You can pass expressions through a chain of filters like this:
|
displaying it to the user. You can pass expressions through a chain of filters like this:
|
||||||
|
|
||||||
|
|
||||||
name | uppercase
|
name | uppercase
|
||||||
|
|
||||||
|
|
||||||
The expression evaluator simply passes the value of name to `angular.filter.uppercase()`.
|
The expression evaluator simply passes the value of name to `angular.filter.uppercase()`.
|
||||||
|
|
||||||
|
|
||||||
In addition to formatting data, filters can also modify the DOM. This allows filters to handle
|
In addition to formatting data, filters can also modify the DOM. This allows filters to handle
|
||||||
tasks such as conditionally applying CSS styles to filtered output.
|
tasks such as conditionally applying CSS styles to filtered output.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters.using_filters Using Angular Filters}
|
* {@link dev_guide.templates.filters.using_filters Using Angular Filters}
|
||||||
* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters}
|
* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.filter Angular Filter API}
|
* {@link api/angular.filter Angular Filter API}
|
||||||
|
|
|
||||||
|
|
@ -3,35 +3,26 @@
|
||||||
@name Developer Guide: Templates: Filters: Using Angular Filters
|
@name Developer Guide: Templates: Filters: Using Angular Filters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Filters can be part of any {@link api/angular.scope} evaluation but are typically used to format
|
Filters can be part of any {@link api/angular.scope} evaluation but are typically used to format
|
||||||
expressions in bindings in your templates:
|
expressions in bindings in your templates:
|
||||||
|
|
||||||
|
|
||||||
{{ expression | filter }}
|
{{ expression | filter }}
|
||||||
|
|
||||||
|
|
||||||
Filters typically transform the data to a new data type, formatting the data in the process.
|
Filters typically transform the data to a new data type, formatting the data in the process.
|
||||||
Filters can also be chained, and can take optional arguments.
|
Filters can also be chained, and can take optional arguments.
|
||||||
|
|
||||||
|
|
||||||
You can chain filters using this syntax:
|
You can chain filters using this syntax:
|
||||||
|
|
||||||
|
|
||||||
{{ expression | filter1 | filter2 }}
|
{{ expression | filter1 | filter2 }}
|
||||||
|
|
||||||
|
|
||||||
You can also pass colon-delimited arguments to filters, for example, to display the number 123 with
|
You can also pass colon-delimited arguments to filters, for example, to display the number 123 with
|
||||||
2 decimal points:
|
2 decimal points:
|
||||||
|
|
||||||
|
|
||||||
123 | number:2
|
123 | number:2
|
||||||
|
|
||||||
|
|
||||||
Here are some examples that show values before and after applying different filters to an
|
Here are some examples that show values before and after applying different filters to an
|
||||||
expression in a binding:
|
expression in a binding:
|
||||||
|
|
||||||
|
|
||||||
* No filter: `{{1234.5678}}` => `1234.5678`
|
* No filter: `{{1234.5678}}` => `1234.5678`
|
||||||
* Number filter: `{{1234.5678|number}}` => `1,234.57`. Notice the "," and rounding to two
|
* Number filter: `{{1234.5678|number}}` => `1,234.57`. Notice the "," and rounding to two
|
||||||
significant digits.
|
significant digits.
|
||||||
|
|
@ -40,16 +31,11 @@ arguments, separated by colons in a binding. For example, the "number" filter ta
|
||||||
argument that specifies how many digits to display to the right of the decimal point.
|
argument that specifies how many digits to display to the right of the decimal point.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
||||||
* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters}
|
* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.filter Angular Filter API}
|
* {@link api/angular.filter Angular Filter API}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,16 @@
|
||||||
@name Developer Guide: Templates: Angular Formatters: Creating Angular Formatters
|
@name Developer Guide: Templates: Angular Formatters: Creating Angular Formatters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
To create your own formatter, you can simply register a pair of JavaScript functions with
|
To create your own formatter, you can simply register a pair of JavaScript functions with
|
||||||
`angular.formatter`. One of your functions is used to parse text from the input widget into the
|
`angular.formatter`. One of your functions is used to parse text from the input widget into the
|
||||||
data storage format; the other function is used to format stored data into user-readable text.
|
data storage format; the other function is used to format stored data into user-readable text.
|
||||||
|
|
||||||
|
|
||||||
The following example demonstrates a "reverse" formatter. Data is stored in uppercase and in
|
The following example demonstrates a "reverse" formatter. Data is stored in uppercase and in
|
||||||
reverse, but it is displayed in lower case and non-reversed. When a user edits the data model via
|
reverse, but it is displayed in lower case and non-reversed. When a user edits the data model via
|
||||||
the input widget, the input is automatically parsed into the internal data storage format, and when
|
the input widget, the input is automatically parsed into the internal data storage format, and when
|
||||||
the data changes in the model, it is automatically formatted to the user-readable form for display
|
the data changes in the model, it is automatically formatted to the user-readable form for display
|
||||||
in the view.
|
in the view.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function reverse(text) {
|
function reverse(text) {
|
||||||
var reversed = [];
|
var reversed = [];
|
||||||
|
|
@ -25,7 +22,6 @@ reversed.unshift(text.charAt(i));
|
||||||
return reversed.join('');
|
return reversed.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
angular.formatter('reverse', {
|
angular.formatter('reverse', {
|
||||||
parse: function(value){
|
parse: function(value){
|
||||||
return reverse(value||'').toUpperCase();
|
return reverse(value||'').toUpperCase();
|
||||||
|
|
@ -36,7 +32,6 @@ return reverse(value||'').toLowerCase();
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
@ -48,7 +43,6 @@ for (var i = 0; i < text.length; i++) {
|
||||||
return reversed.join('');
|
return reversed.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
angular.formatter('reverse', {
|
angular.formatter('reverse', {
|
||||||
parse: function(value){
|
parse: function(value){
|
||||||
return reverse(value||'').toUpperCase();
|
return reverse(value||'').toUpperCase();
|
||||||
|
|
@ -59,5 +53,3 @@ format: function(value){
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,18 @@
|
||||||
@name Developer Guide: Templates: Angular Formatters
|
@name Developer Guide: Templates: Angular Formatters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
In angular, formatters are responsible for translating user-readable text entered in an {@link
|
In angular, formatters are responsible for translating user-readable text entered in an {@link
|
||||||
api/angular.widget.HTML input widget} to a JavaScript object in the data model that the application
|
api/angular.widget.HTML input widget} to a JavaScript object in the data model that the application
|
||||||
can manipulate.
|
can manipulate.
|
||||||
|
|
||||||
|
|
||||||
You can use formatters in a template, and also in JavaScript. Angular provides built-in
|
You can use formatters in a template, and also in JavaScript. Angular provides built-in
|
||||||
formatters, and of course you can create your own formatters.
|
formatters, and of course you can create your own formatters.
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.formatters.using_formatters Using Angular Formatters}
|
* {@link dev_guide.templates.formatters.using_formatters Using Angular Formatters}
|
||||||
* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters}
|
* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.formatter Angular Formatter API}
|
* {@link api/angular.formatter Angular Formatter API}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,7 @@
|
||||||
@name Developer Guide: Templates: Angular Formatters: Using Angular Formatters
|
@name Developer Guide: Templates: Angular Formatters: Using Angular Formatters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
The following snippet shows how to use a formatter in a template. The formatter below is
|
The following snippet shows how to use a formatter in a template. The formatter below is
|
||||||
`ng:format="reverse"`, added as an attribute to an `<input>` tag.
|
`ng:format="reverse"`, added as an attribute to an `<input>` tag.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,14 @@
|
||||||
@name Developer Guide: Understanding Angular Templates
|
@name Developer Guide: Understanding Angular Templates
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
An angular template is the declarative specification that, along with information from the model
|
An angular template is the declarative specification that, along with information from the model
|
||||||
and controller, becomes the rendered view that a user sees in the browser. It is the static DOM,
|
and controller, becomes the rendered view that a user sees in the browser. It is the static DOM,
|
||||||
containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The
|
containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The
|
||||||
angular elements and attributes direct angular to add behavior and transform the template DOM into
|
angular elements and attributes direct angular to add behavior and transform the template DOM into
|
||||||
the dynamic view DOM.
|
the dynamic view DOM.
|
||||||
|
|
||||||
|
|
||||||
These are the types of angular elements and element attributes you can use in a template:
|
These are the types of angular elements and element attributes you can use in a template:
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler.directives Directive} — An attribute that augments an existing DOM
|
* {@link dev_guide.compiler.directives Directive} — An attribute that augments an existing DOM
|
||||||
element.
|
element.
|
||||||
* {@link dev_guide.compiler.widgets Widget} — A custom DOM element. An example of a built-in widget
|
* {@link dev_guide.compiler.widgets Widget} — A custom DOM element. An example of a built-in widget
|
||||||
|
|
@ -25,16 +22,13 @@ curly brace notation `{{ }}` to bind expressions to elements is built-in angular
|
||||||
* {@link dev_guide.templates.formatters Formatter} — Lets you format the input object into a user
|
* {@link dev_guide.templates.formatters Formatter} — Lets you format the input object into a user
|
||||||
readable view.
|
readable view.
|
||||||
|
|
||||||
|
|
||||||
Note: In addition to declaring the elements above in templates, you can also access these elements
|
Note: In addition to declaring the elements above in templates, you can also access these elements
|
||||||
in JavaScript code.
|
in JavaScript code.
|
||||||
|
|
||||||
|
|
||||||
The following code snippet shows a simple angular template made up of standard HTML tags along with
|
The following code snippet shows a simple angular template made up of standard HTML tags along with
|
||||||
angular {@link dev_guide.compiler.directives directives}, {@link dev_guide.compiler.markup markup},
|
angular {@link dev_guide.compiler.directives directives}, {@link dev_guide.compiler.markup markup},
|
||||||
and {@link dev_guide.expressions expressions}:
|
and {@link dev_guide.expressions expressions}:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<html>
|
<html>
|
||||||
<!-- Body tag augmented with ng:controller directive -->
|
<!-- Body tag augmented with ng:controller directive -->
|
||||||
|
|
@ -49,7 +43,6 @@ and {@link dev_guide.expressions expressions}:
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
In a simple single-page app, the template consists of HTML, CSS, and angular directives contained
|
In a simple single-page app, the template consists of HTML, CSS, and angular directives contained
|
||||||
in just one HTML file (usually `index.html`). In a more complex app, you can display multiple views
|
in just one HTML file (usually `index.html`). In a more complex app, you can display multiple views
|
||||||
within one main page using "partials", which are segments of template located in separate HTML
|
within one main page using "partials", which are segments of template located in separate HTML
|
||||||
|
|
@ -59,17 +52,12 @@ example of this technique is shown in the {@link tutorial/ angular tutorial}, in
|
||||||
eight.
|
eight.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters Angular Filters}
|
* {@link dev_guide.templates.filters Angular Filters}
|
||||||
* {@link dev_guide.templates.formatters Angular Formatters}
|
* {@link dev_guide.templates.formatters Angular Formatters}
|
||||||
* {@link dev_guide.templates.validators Angular Validators}
|
* {@link dev_guide.templates.validators Angular Validators}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/index API Reference}
|
* {@link api/index API Reference}
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,13 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
To create a custom validator, you simply add your validator code as a method onto the
|
To create a custom validator, you simply add your validator code as a method onto the
|
||||||
`angular.validator` object and provide input(s) for the validator function. Each input provided is
|
`angular.validator` object and provide input(s) for the validator function. Each input provided is
|
||||||
treated as an argument to the validator function. Any additional inputs should be separated by
|
treated as an argument to the validator function. Any additional inputs should be separated by
|
||||||
commas.
|
commas.
|
||||||
|
|
||||||
|
|
||||||
The following bit of pseudo-code shows how to set up a custom validator:
|
The following bit of pseudo-code shows how to set up a custom validator:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.validator('your_validator', function(input [,additional params]) {
|
angular.validator('your_validator', function(input [,additional params]) {
|
||||||
[your validation code];
|
[your validation code];
|
||||||
|
|
@ -26,22 +22,17 @@ angular.validator('your_validator', function(input [,additional params]) {
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true,
|
Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true,
|
||||||
there was a problem with that input". If you prefer to provide more information when a validator
|
there was a problem with that input". If you prefer to provide more information when a validator
|
||||||
detects a problem with input, you can specify an error message in the validator that angular will
|
detects a problem with input, you can specify an error message in the validator that angular will
|
||||||
display when the user hovers over the input widget.
|
display when the user hovers over the input widget.
|
||||||
|
|
||||||
|
|
||||||
To specify an error message, replace "`return true;`" with an error string, for example:
|
To specify an error message, replace "`return true;`" with an error string, for example:
|
||||||
|
|
||||||
|
|
||||||
return "Must be a value between 1 and 5!";
|
return "Must be a value between 1 and 5!";
|
||||||
|
|
||||||
|
|
||||||
Following is a sample UPS Tracking Number validator:
|
Following is a sample UPS Tracking Number validator:
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -60,7 +51,6 @@ expect(element('input[name=trackNo]').attr('class')).
|
||||||
not().toMatch(/ng-validation-error/);
|
not().toMatch(/ng-validation-error/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should not validate in correct UPS tracking number', function() {
|
it('should not validate in correct UPS tracking number', function() {
|
||||||
input('trackNo').enter('foo');
|
input('trackNo').enter('foo');
|
||||||
expect(element('input[name=trackNo]').attr('class')).
|
expect(element('input[name=trackNo]').attr('class')).
|
||||||
|
|
@ -69,32 +59,24 @@ expect(element('input[name=trackNo]').attr('class')).
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
In this sample validator, we specify a regular expression against which to test the user's input.
|
In this sample validator, we specify a regular expression against which to test the user's input.
|
||||||
Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it
|
Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it
|
||||||
returns the specified error message ("true").
|
returns the specified error message ("true").
|
||||||
|
|
||||||
|
|
||||||
Note: you can also access the current angular scope and DOM element objects in your validator
|
Note: you can also access the current angular scope and DOM element objects in your validator
|
||||||
functions as follows:
|
functions as follows:
|
||||||
|
|
||||||
|
|
||||||
* `this` === The current angular scope.
|
* `this` === The current angular scope.
|
||||||
* `this.$element` === The DOM element that contains the binding. This allows the filter to
|
* `this.$element` === The DOM element that contains the binding. This allows the filter to
|
||||||
manipulate the DOM in addition to transforming the input.
|
manipulate the DOM in addition to transforming the input.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates Angular Templates}
|
* {@link dev_guide.templates Angular Templates}
|
||||||
* {@link dev_guide.templates.filters Angular Filters}
|
* {@link dev_guide.templates.filters Angular Filters}
|
||||||
* {@link dev_guide.templates.formatters Angular Formatters}
|
* {@link dev_guide.templates.formatters Angular Formatters}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.validator API Validator Reference}
|
* {@link api/angular.validator API Validator Reference}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
@name Developer Guide: Templates: Understanding Angular Validators
|
@name Developer Guide: Templates: Understanding Angular Validators
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Angular validators are attributes that test the validity of different types of user input. Angular
|
Angular validators are attributes that test the validity of different types of user input. Angular
|
||||||
provides a set of built-in input validators:
|
provides a set of built-in input validators:
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.validator.phone phone number}
|
* {@link api/angular.validator.phone phone number}
|
||||||
* {@link api/angular.validator.number number}
|
* {@link api/angular.validator.number number}
|
||||||
* {@link api/angular.validator.integer integer}
|
* {@link api/angular.validator.integer integer}
|
||||||
|
|
@ -18,35 +16,26 @@ provides a set of built-in input validators:
|
||||||
* {@link api/angular.validator.url URLs}
|
* {@link api/angular.validator.url URLs}
|
||||||
* {@link api/angular.validator.asynchronous asynchronous}
|
* {@link api/angular.validator.asynchronous asynchronous}
|
||||||
|
|
||||||
|
|
||||||
You can also create your own custom validators.
|
You can also create your own custom validators.
|
||||||
|
|
||||||
|
|
||||||
# Using Angular Validators
|
# Using Angular Validators
|
||||||
|
|
||||||
|
|
||||||
You can use angular validators in HTML template bindings, and in JavaScript:
|
You can use angular validators in HTML template bindings, and in JavaScript:
|
||||||
|
|
||||||
|
|
||||||
* Validators in HTML Template Bindings
|
* Validators in HTML Template Bindings
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<input ng:validator="validator_type:parameters" [...]>
|
<input ng:validator="validator_type:parameters" [...]>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
* Validators in JavaScript
|
* Validators in JavaScript
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.validator.[validator_type](parameters)
|
angular.validator.[validator_type](parameters)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The following example shows how to use the built-in angular integer validator:
|
The following example shows how to use the built-in angular integer validator:
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
Change me: <input type="text" name="number" ng:validate="integer" value="123">
|
Change me: <input type="text" name="number" ng:validate="integer" value="123">
|
||||||
|
|
@ -64,19 +53,15 @@ The following example shows how to use the built-in angular integer validator:
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
# Creating an Angular Validator
|
# Creating an Angular Validator
|
||||||
|
|
||||||
|
|
||||||
To create a custom validator, you simply add your validator code as a method onto the
|
To create a custom validator, you simply add your validator code as a method onto the
|
||||||
`angular.validator` object and provide input(s) for the validator function. Each input provided is
|
`angular.validator` object and provide input(s) for the validator function. Each input provided is
|
||||||
treated as an argument to the validator function. Any additional inputs should be separated by
|
treated as an argument to the validator function. Any additional inputs should be separated by
|
||||||
commas.
|
commas.
|
||||||
|
|
||||||
|
|
||||||
The following bit of pseudo-code shows how to set up a custom validator:
|
The following bit of pseudo-code shows how to set up a custom validator:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.validator('your_validator', function(input [,additional params]) {
|
angular.validator('your_validator', function(input [,additional params]) {
|
||||||
[your validation code];
|
[your validation code];
|
||||||
|
|
@ -88,22 +73,17 @@ angular.validator('your_validator', function(input [,additional params]) {
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true,
|
Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true,
|
||||||
there was a problem with that input". If you prefer to provide more information when a validator
|
there was a problem with that input". If you prefer to provide more information when a validator
|
||||||
detects a problem with input, you can specify an error message in the validator that angular will
|
detects a problem with input, you can specify an error message in the validator that angular will
|
||||||
display when the user hovers over the input widget.
|
display when the user hovers over the input widget.
|
||||||
|
|
||||||
|
|
||||||
To specify an error message, replace "`return true;`" with an error string, for example:
|
To specify an error message, replace "`return true;`" with an error string, for example:
|
||||||
|
|
||||||
|
|
||||||
return "Must be a value between 1 and 5!";
|
return "Must be a value between 1 and 5!";
|
||||||
|
|
||||||
|
|
||||||
Following is a sample UPS Tracking Number validator:
|
Following is a sample UPS Tracking Number validator:
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -122,7 +102,6 @@ it('should validate correct UPS tracking number', function() {
|
||||||
not().toMatch(/ng-validation-error/);
|
not().toMatch(/ng-validation-error/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should not validate in correct UPS tracking number', function() {
|
it('should not validate in correct UPS tracking number', function() {
|
||||||
input('trackNo').enter('foo');
|
input('trackNo').enter('foo');
|
||||||
expect(element('input[name=trackNo]').attr('class')).
|
expect(element('input[name=trackNo]').attr('class')).
|
||||||
|
|
@ -131,30 +110,22 @@ it('should not validate in correct UPS tracking number', function() {
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
In this sample validator, we specify a regular expression against which to test the user's input.
|
In this sample validator, we specify a regular expression against which to test the user's input.
|
||||||
Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it
|
Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it
|
||||||
returns the specified error message ("true").
|
returns the specified error message ("true").
|
||||||
|
|
||||||
|
|
||||||
Note: you can also access the current angular scope and DOM element objects in your validator
|
Note: you can also access the current angular scope and DOM element objects in your validator
|
||||||
functions as follows:
|
functions as follows:
|
||||||
|
|
||||||
|
|
||||||
* `this` === The current angular scope.
|
* `this` === The current angular scope.
|
||||||
* `this.$element` === The DOM element that contains the binding. This allows the filter to
|
* `this.$element` === The DOM element that contains the binding. This allows the filter to
|
||||||
manipulate the DOM in addition to transforming the input.
|
manipulate the DOM in addition to transforming the input.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates Angular Templates}
|
* {@link dev_guide.templates Angular Templates}
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
||||||
* {@link api/angular.validator Validator API}
|
* {@link api/angular.validator Validator API}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
@name Developer Guide: Unit Testing
|
@name Developer Guide: Unit Testing
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
||||||
come with almost no-help from the compiler. For this reason we feel very strongly that any code
|
come with almost no-help from the compiler. For this reason we feel very strongly that any code
|
||||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||||
|
|
@ -27,7 +26,6 @@ DOM in the right way. Angular is written with testability in mind, but it still
|
||||||
do the right thing. We tried to make the right thing easy, but angular is not magic, which means if
|
do the right thing. We tried to make the right thing easy, but angular is not magic, which means if
|
||||||
you don't follow these, you may very well end up with an untestable application.
|
you don't follow these, you may very well end up with an untestable application.
|
||||||
|
|
||||||
|
|
||||||
## Dependency Inject
|
## Dependency Inject
|
||||||
There are several ways in which you can get a hold of a dependency:
|
There are several ways in which you can get a hold of a dependency:
|
||||||
1. You could create it using the `new` operator.
|
1. You could create it using the `new` operator.
|
||||||
|
|
@ -36,18 +34,14 @@ There are several ways in which you can get a hold of a dependency:
|
||||||
the registry? Must likely by looking it up in a well know place. See #2)
|
the registry? Must likely by looking it up in a well know place. See #2)
|
||||||
4. You could expect that the it be handed to you.
|
4. You could expect that the it be handed to you.
|
||||||
|
|
||||||
|
|
||||||
Out of the list above only the last of is testable. Lets look at why:
|
Out of the list above only the last of is testable. Lets look at why:
|
||||||
|
|
||||||
|
|
||||||
### Using the `new` operator
|
### Using the `new` operator
|
||||||
|
|
||||||
|
|
||||||
While there is nothing wrong with the `new` operator fundamentally the issue is that calling a new
|
While there is nothing wrong with the `new` operator fundamentally the issue is that calling a new
|
||||||
on a constructor permanently binds the call site to the type. For example lets say that we are
|
on a constructor permanently binds the call site to the type. For example lets say that we are
|
||||||
trying to instantiate an `XHR` so that we can get some data from the server.
|
trying to instantiate an `XHR` so that we can get some data from the server.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function MyClass(){
|
function MyClass(){
|
||||||
this.doWork = function(){
|
this.doWork = function(){
|
||||||
|
|
@ -59,13 +53,11 @@ function MyClass(){
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The issue becomes, that in tests, we would very much like to instantiate a `MockXHR` which would
|
The issue becomes, that in tests, we would very much like to instantiate a `MockXHR` which would
|
||||||
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
|
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
|
||||||
permanently bound to the actual one, and there is no good way to replace it. Yes there is monkey
|
permanently bound to the actual one, and there is no good way to replace it. Yes there is monkey
|
||||||
patching, that is a bad idea for many reasons, which is outside the scope of this document.
|
patching, that is a bad idea for many reasons, which is outside the scope of this document.
|
||||||
|
|
||||||
|
|
||||||
The class above is hard to test since we have to resort to monkey patching:
|
The class above is hard to test since we have to resort to monkey patching:
|
||||||
<pre>
|
<pre>
|
||||||
var oldXHR = XHR;
|
var oldXHR = XHR;
|
||||||
|
|
@ -77,12 +69,9 @@ XHR = oldXHR; // if you forget this bad things will happen
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Global look-up:
|
### Global look-up:
|
||||||
Another way to approach the problem is look for the service in a well known location.
|
Another way to approach the problem is look for the service in a well known location.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function MyClass(){
|
function MyClass(){
|
||||||
this.doWork = function(){
|
this.doWork = function(){
|
||||||
|
|
@ -95,7 +84,6 @@ function MyClass(){
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
While no new instance of dependency is being created, it is fundamentally the same as `new`, in
|
While no new instance of dependency is being created, it is fundamentally the same as `new`, in
|
||||||
that there is no good way to intercept the call to `global.xhr` for testing purposes, other then
|
that there is no good way to intercept the call to `global.xhr` for testing purposes, other then
|
||||||
through monkey patching. The basic issue for testing is that global variable needs to be mutated in
|
through monkey patching. The basic issue for testing is that global variable needs to be mutated in
|
||||||
|
|
@ -103,7 +91,6 @@ order to replace it with call to a mock method. For further explanation why this
|
||||||
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global
|
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global
|
||||||
State & Singletons}
|
State & Singletons}
|
||||||
|
|
||||||
|
|
||||||
The class above is hard to test since we have to change global state:
|
The class above is hard to test since we have to change global state:
|
||||||
<pre>
|
<pre>
|
||||||
var oldXHR = glabal.xhr;
|
var oldXHR = glabal.xhr;
|
||||||
|
|
@ -115,15 +102,11 @@ global.xhr = oldXHR; // if you forget this bad things will happen
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Service Registry:
|
### Service Registry:
|
||||||
|
|
||||||
|
|
||||||
It may seem as that this can be solved by having a registry for all of the services, and then
|
It may seem as that this can be solved by having a registry for all of the services, and then
|
||||||
having the tests replace the services as needed.
|
having the tests replace the services as needed.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function MyClass() {
|
function MyClass() {
|
||||||
var serviceRegistry = ????;
|
var serviceRegistry = ????;
|
||||||
|
|
@ -137,13 +120,11 @@ function MyClass() {
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
However, where dose the serviceRegistry come from? if it is:
|
However, where dose the serviceRegistry come from? if it is:
|
||||||
* `new`-ed up, the the test has no chance to reset the services for testing
|
* `new`-ed up, the the test has no chance to reset the services for testing
|
||||||
* global look-up, then the service returned is global as well (but resetting is easier, since
|
* global look-up, then the service returned is global as well (but resetting is easier, since
|
||||||
there is only one global variable to be reset).
|
there is only one global variable to be reset).
|
||||||
|
|
||||||
|
|
||||||
The class above is hard to test since we have to change global state:
|
The class above is hard to test since we have to change global state:
|
||||||
<pre>
|
<pre>
|
||||||
var oldServiceLocator = glabal.serviceLocator;
|
var oldServiceLocator = glabal.serviceLocator;
|
||||||
|
|
@ -155,12 +136,9 @@ glabal.serviceLocator = oldServiceLocator; // if you forget this bad things will
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Passing in Dependencies:
|
### Passing in Dependencies:
|
||||||
Lastly the dependency can be passed in.
|
Lastly the dependency can be passed in.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function MyClass(xhr) {
|
function MyClass(xhr) {
|
||||||
this.doWork = function(){
|
this.doWork = function(){
|
||||||
|
|
@ -227,11 +205,9 @@ function PasswordController(){
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The code above is problematic from testability, since it requires your test to have the right kind
|
The code above is problematic from testability, since it requires your test to have the right kind
|
||||||
of DOM present when the code executes. The test would look like this:
|
of DOM present when the code executes. The test would look like this:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var input = $('<input type="text"/>');
|
var input = $('<input type="text"/>');
|
||||||
var span = $('<span>');
|
var span = $('<span>');
|
||||||
|
|
@ -246,11 +222,9 @@ expect(span.text()).toEqual('weak');
|
||||||
$('body').html('');
|
$('body').html('');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
In angular the controllers are strictly separated from the DOM manipulation logic which results in
|
In angular the controllers are strictly separated from the DOM manipulation logic which results in
|
||||||
a much easier testability story as can be seen in this example:
|
a much easier testability story as can be seen in this example:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function PasswordCntrl(){
|
function PasswordCntrl(){
|
||||||
this.password = '';
|
this.password = '';
|
||||||
|
|
@ -267,10 +241,8 @@ function PasswordCntrl(){
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
and the tests is straight forward
|
and the tests is straight forward
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var pc = new PasswordController();
|
var pc = new PasswordController();
|
||||||
pc.password('abc');
|
pc.password('abc');
|
||||||
|
|
@ -278,37 +250,29 @@ pc.grade();
|
||||||
expect(span.strength).toEqual('weak');
|
expect(span.strength).toEqual('weak');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
|
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
|
||||||
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
{@link api/angular.filter Filters} are functions which transform the data into user readable
|
{@link api/angular.filter Filters} are functions which transform the data into user readable
|
||||||
format. They are important because they remove the formatting responsibility from the application
|
format. They are important because they remove the formatting responsibility from the application
|
||||||
logic, further simplifying the application logic.
|
logic, further simplifying the application logic.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angular.filter('length', function(text){
|
angular.filter('length', function(text){
|
||||||
return (''+(text||'')).length;
|
return (''+(text||'')).length;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var length = angular.filter('length');
|
var length = angular.filter('length');
|
||||||
expect(length(null)).toEqual(0);
|
expect(length(null)).toEqual(0);
|
||||||
expect(length('abc')).toEqual(3);
|
expect(length('abc')).toEqual(3);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Directives
|
## Directives
|
||||||
Directives in angular are responsible for updating the DOM when the state of the model changes.
|
Directives in angular are responsible for updating the DOM when the state of the model changes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Mocks
|
## Mocks
|
||||||
oue
|
oue
|
||||||
## Global State Isolation
|
## Global State Isolation
|
||||||
|
|
|
||||||
|
|
@ -3,78 +3,59 @@
|
||||||
@name Developer Guide
|
@name Developer Guide
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Welcome to the angular Developer Guide. If you are here to learn the details of how to use angular
|
Welcome to the angular Developer Guide. If you are here to learn the details of how to use angular
|
||||||
to develop web apps, you've come to the right place.
|
to develop web apps, you've come to the right place.
|
||||||
|
|
||||||
|
|
||||||
If you are completely or relatively unfamiliar with angular, you may want to check out one or both
|
If you are completely or relatively unfamiliar with angular, you may want to check out one or both
|
||||||
of the following documents before returning here to the Developer Guide:
|
of the following documents before returning here to the Developer Guide:
|
||||||
|
|
||||||
|
|
||||||
* {@link misc/started Getting Started}
|
* {@link misc/started Getting Started}
|
||||||
* {@link tutorial/index Angular Tutorial}
|
* {@link tutorial/index Angular Tutorial}
|
||||||
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.overview Overview of Angular}
|
## {@link dev_guide.overview Overview of Angular}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.bootstrap Initializing Angular}
|
## {@link dev_guide.bootstrap Initializing Angular}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.bootstrap.auto_bootstrap Understanding Automatic Initialization}
|
* {@link dev_guide.bootstrap.auto_bootstrap Understanding Automatic Initialization}
|
||||||
* {@link dev_guide.bootstrap.manual_bootstrap Understanding Manual Initialization}
|
* {@link dev_guide.bootstrap.manual_bootstrap Understanding Manual Initialization}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.mvc About MVC in Angular}
|
## {@link dev_guide.mvc About MVC in Angular}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.scopes Angular Scope Objects}
|
## {@link dev_guide.scopes Angular Scope Objects}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects}
|
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects}
|
||||||
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
|
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
|
||||||
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
|
||||||
* {@link dev_guide.scopes.updating_scopes Updating Scope Properties}
|
* {@link dev_guide.scopes.updating_scopes Updating Scope Properties}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.compiler Angular HTML Compiler}
|
## {@link dev_guide.compiler Angular HTML Compiler}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||||
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
||||||
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
||||||
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.templates Angular Templates}
|
## {@link dev_guide.templates Angular Templates}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
||||||
* {@link dev_guide.templates.formatters Understanding Angular Formatters}
|
* {@link dev_guide.templates.formatters Understanding Angular Formatters}
|
||||||
* {@link dev_guide.templates.validators Understanding Angular Validators}
|
* {@link dev_guide.templates.validators Understanding Angular Validators}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.services Angular Services}
|
## {@link dev_guide.services Angular Services}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.registering_services Registering Angular Services}
|
* {@link dev_guide.services.registering_services Registering Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
|
|
||||||
## {@link dev_guide.di About Dependency Injection}
|
## {@link dev_guide.di About Dependency Injection}
|
||||||
|
|
||||||
|
|
||||||
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
|
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
|
||||||
* {@link dev_guide.di.using_di_controllers Using DI in Controllers}
|
* {@link dev_guide.di.using_di_controllers Using DI in Controllers}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* <a href="#H1_1">License</a>
|
* <a href="#H1_1">License</a>
|
||||||
* <a href="#H1_2">Contributing to Source Code</a>
|
* <a href="#H1_2">Contributing to Source Code</a>
|
||||||
* <a href="#H1_3">Applying Code Standards</a>
|
* <a href="#H1_3">Applying Code Standards</a>
|
||||||
|
|
@ -12,349 +10,243 @@
|
||||||
* <a href="#H1_5">Submitting Your Changes</a>
|
* <a href="#H1_5">Submitting Your Changes</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_1"></a>
|
<a name="H1_1"></a>
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|
||||||
`Angular` is an open source project licensed under the {@link
|
`Angular` is an open source project licensed under the {@link
|
||||||
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
|
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
|
||||||
always welcome. When working with `angular` source base, please follow the guidelines provided on
|
always welcome. When working with `angular` source base, please follow the guidelines provided on
|
||||||
this page.
|
this page.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_2"></a>
|
<a name="H1_2"></a>
|
||||||
# Contributing to Source Code
|
# Contributing to Source Code
|
||||||
|
|
||||||
|
|
||||||
We'd love for you to contribute to our source code and to make `angular` even better than it is
|
We'd love for you to contribute to our source code and to make `angular` even better than it is
|
||||||
today! Here are the guidelines we'd like you to use:
|
today! Here are the guidelines we'd like you to use:
|
||||||
|
|
||||||
|
|
||||||
* Major changes that you intend to contribute to the project must be discussed first on our {@link
|
* Major changes that you intend to contribute to the project must be discussed first on our {@link
|
||||||
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
|
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
|
||||||
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
|
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
|
||||||
is successfully accepted upstream.
|
is successfully accepted upstream.
|
||||||
|
|
||||||
|
|
||||||
* Small changes and bug fixes can be crafted and submitted to Github as a <a href="#H1_5">pull
|
* Small changes and bug fixes can be crafted and submitted to Github as a <a href="#H1_5">pull
|
||||||
request</a>.
|
request</a>.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_3"></a>
|
<a name="H1_3"></a>
|
||||||
# Applying Code Standards
|
# Applying Code Standards
|
||||||
|
|
||||||
|
|
||||||
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
||||||
|
|
||||||
|
|
||||||
* All features or bug fixes must be tested by one or more <a href="#unit-tests">specs</a>.
|
* All features or bug fixes must be tested by one or more <a href="#unit-tests">specs</a>.
|
||||||
|
|
||||||
|
|
||||||
* All public API methods must be documented with ngdoc, an extended version of jsdoc (we added
|
* All public API methods must be documented with ngdoc, an extended version of jsdoc (we added
|
||||||
support for markdown and templating via `@ngdoc` tag). To see how we document our APIs, please
|
support for markdown and templating via `@ngdoc` tag). To see how we document our APIs, please
|
||||||
check out the existing ngdocs.
|
check out the existing ngdocs.
|
||||||
|
|
||||||
|
|
||||||
* With the exceptions listed below, we follow the rules contained in {@link
|
* With the exceptions listed below, we follow the rules contained in {@link
|
||||||
http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml Google's JavaScript Style
|
http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml Google's JavaScript Style
|
||||||
Guide}:
|
Guide}:
|
||||||
|
|
||||||
|
|
||||||
* Do not use namespaces: Instead, we wrap the entire `angular` code base in an anonymous closure
|
* Do not use namespaces: Instead, we wrap the entire `angular` code base in an anonymous closure
|
||||||
and export our API explicitly rather than implicitly.
|
and export our API explicitly rather than implicitly.
|
||||||
|
|
||||||
|
|
||||||
* Wrap all code at 100 characters.
|
* Wrap all code at 100 characters.
|
||||||
|
|
||||||
|
|
||||||
* Instead of complex inheritance hierarchies, we prefer simple objects. We use prototypical
|
* Instead of complex inheritance hierarchies, we prefer simple objects. We use prototypical
|
||||||
inheritance only when absolutely necessary.
|
inheritance only when absolutely necessary.
|
||||||
|
|
||||||
|
|
||||||
* We love functions and closures and, whenever possible, prefer them over objects.
|
* We love functions and closures and, whenever possible, prefer them over objects.
|
||||||
|
|
||||||
|
|
||||||
* To write concise code that can be better minified, internally we use aliases that map to the
|
* To write concise code that can be better minified, internally we use aliases that map to the
|
||||||
external API. See our existing code to see what we mean.
|
external API. See our existing code to see what we mean.
|
||||||
|
|
||||||
|
|
||||||
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
|
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
|
||||||
that is used throughout `angular`. The best guidance is to do what makes the most sense.
|
that is used throughout `angular`. The best guidance is to do what makes the most sense.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_4"></a>
|
<a name="H1_4"></a>
|
||||||
# Checking Out and Building Angular
|
# Checking Out and Building Angular
|
||||||
|
|
||||||
|
|
||||||
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
|
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
|
||||||
accept code contributions. Several steps are needed to check out and build `angular`:
|
accept code contributions. Several steps are needed to check out and build `angular`:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Installation Dependencies
|
## Installation Dependencies
|
||||||
|
|
||||||
|
|
||||||
Before you can build `angular`, you must install or configure the following dependencies on your
|
Before you can build `angular`, you must install or configure the following dependencies on your
|
||||||
machine:
|
machine:
|
||||||
|
|
||||||
|
|
||||||
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
|
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
|
||||||
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
|
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
|
||||||
Rake website.
|
Rake website.
|
||||||
|
|
||||||
|
|
||||||
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
|
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
|
||||||
development web server. Depending on your system, you can install Node either from source or as a
|
development web server. Depending on your system, you can install Node either from source or as a
|
||||||
pre-packaged bundle.
|
pre-packaged bundle.
|
||||||
|
|
||||||
|
|
||||||
* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
|
* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
|
||||||
JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
|
JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
|
||||||
`angular` source base, which means there is no need to install or configure it separately.
|
`angular` source base, which means there is no need to install or configure it separately.
|
||||||
|
|
||||||
|
|
||||||
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
|
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
|
||||||
quite a good source for information on Git.
|
quite a good source for information on Git.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Creating a Github Account and Forking Angular
|
## Creating a Github Account and Forking Angular
|
||||||
|
|
||||||
|
|
||||||
To create a Github account, follow the instructions {@link https://github.com/signup/free here}.
|
To create a Github account, follow the instructions {@link https://github.com/signup/free here}.
|
||||||
Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
|
Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
|
||||||
https://github.com/angular/angular.js main angular repository}.
|
https://github.com/angular/angular.js main angular repository}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Building `Angular`
|
## Building `Angular`
|
||||||
|
|
||||||
|
|
||||||
To build `angular`, you check out the source code and use Rake to generate the non-minified and
|
To build `angular`, you check out the source code and use Rake to generate the non-minified and
|
||||||
minified `angular` files:
|
minified `angular` files:
|
||||||
|
|
||||||
|
|
||||||
1. To clone your Github repository, run:
|
1. To clone your Github repository, run:
|
||||||
|
|
||||||
|
|
||||||
git clone git@github.com:<github username>/angular.js.git
|
git clone git@github.com:<github username>/angular.js.git
|
||||||
|
|
||||||
|
|
||||||
2. To go to the `angular` directory, run:
|
2. To go to the `angular` directory, run:
|
||||||
|
|
||||||
|
|
||||||
cd angular.js
|
cd angular.js
|
||||||
|
|
||||||
|
|
||||||
3. To add the main `angular` repository as an upstream remote to your repository, run:
|
3. To add the main `angular` repository as an upstream remote to your repository, run:
|
||||||
|
|
||||||
|
|
||||||
git remote add upstream https://github.com/angular/angular.js.git
|
git remote add upstream https://github.com/angular/angular.js.git
|
||||||
|
|
||||||
|
|
||||||
4. To build `angular`, run:
|
4. To build `angular`, run:
|
||||||
|
|
||||||
|
|
||||||
rake package
|
rake package
|
||||||
|
|
||||||
|
|
||||||
The build output can be located under the `build` directory. It consists of the following files and
|
The build output can be located under the `build` directory. It consists of the following files and
|
||||||
directories:
|
directories:
|
||||||
|
|
||||||
|
|
||||||
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build
|
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build
|
||||||
artifacts.
|
artifacts.
|
||||||
|
|
||||||
|
|
||||||
* `angular.js` — The non-minified `angular` script.
|
* `angular.js` — The non-minified `angular` script.
|
||||||
|
|
||||||
|
|
||||||
* `angular.min.js` — The minified `angular` script.
|
* `angular.min.js` — The minified `angular` script.
|
||||||
|
|
||||||
|
|
||||||
* `angular-scenario.js` — The `angular` End2End test runner.
|
* `angular-scenario.js` — The `angular` End2End test runner.
|
||||||
|
|
||||||
|
|
||||||
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
|
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
|
||||||
|
|
||||||
|
|
||||||
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
|
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
|
||||||
|
|
||||||
|
|
||||||
* `docs/index.html` — The main page for the documentation.
|
* `docs/index.html` — The main page for the documentation.
|
||||||
|
|
||||||
|
|
||||||
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
|
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Running a Local Development Web Server
|
## Running a Local Development Web Server
|
||||||
|
|
||||||
|
|
||||||
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
|
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
|
||||||
made available a local web server based on Node.js.
|
made available a local web server based on Node.js.
|
||||||
|
|
||||||
|
|
||||||
1. To start the web server, run:
|
1. To start the web server, run:
|
||||||
|
|
||||||
|
|
||||||
./nodeserver.sh
|
./nodeserver.sh
|
||||||
|
|
||||||
|
|
||||||
2. To access the local server, go to this website:
|
2. To access the local server, go to this website:
|
||||||
|
|
||||||
|
|
||||||
http://localhost:8000/
|
http://localhost:8000/
|
||||||
|
|
||||||
|
|
||||||
By default, it serves the contents of the `angular` project directory.
|
By default, it serves the contents of the `angular` project directory.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="unit-tests"></a>
|
<a name="unit-tests"></a>
|
||||||
## Running the Unit Test Suite
|
## Running the Unit Test Suite
|
||||||
|
|
||||||
|
|
||||||
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
|
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
|
||||||
tests:
|
tests:
|
||||||
|
|
||||||
|
|
||||||
1. To start the JSTD server, run:
|
1. To start the JSTD server, run:
|
||||||
|
|
||||||
|
|
||||||
./server.sh
|
./server.sh
|
||||||
|
|
||||||
|
|
||||||
2. To capture one or more browsers, go to this website:
|
2. To capture one or more browsers, go to this website:
|
||||||
|
|
||||||
|
|
||||||
http://localhost:9876/
|
http://localhost:9876/
|
||||||
|
|
||||||
|
|
||||||
3. To trigger a test execution, run:
|
3. To trigger a test execution, run:
|
||||||
|
|
||||||
|
|
||||||
./test.sh
|
./test.sh
|
||||||
|
|
||||||
|
|
||||||
4. To automatically run the test suite each time one or more of the files in the project directory
|
4. To automatically run the test suite each time one or more of the files in the project directory
|
||||||
is changed, you can install `watchr` and then run:
|
is changed, you can install `watchr` and then run:
|
||||||
|
|
||||||
|
|
||||||
watchr watchr.rb
|
watchr watchr.rb
|
||||||
|
|
||||||
|
|
||||||
5. To view the output of each test run, you can tail this log file:
|
5. To view the output of each test run, you can tail this log file:
|
||||||
|
|
||||||
|
|
||||||
./logs/jstd.log
|
./logs/jstd.log
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Running the End2End Test Suite
|
## Running the End2End Test Suite
|
||||||
|
|
||||||
|
|
||||||
To run the End2End test suite:
|
To run the End2End test suite:
|
||||||
|
|
||||||
|
|
||||||
1. Start the local web server.
|
1. Start the local web server.
|
||||||
2. In a browser, go to:
|
2. In a browser, go to:
|
||||||
|
|
||||||
|
|
||||||
http://localhost:8000/build/docs/docs-scenario.html
|
http://localhost:8000/build/docs/docs-scenario.html
|
||||||
|
|
||||||
|
|
||||||
The tests are executed automatically.
|
The tests are executed automatically.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_5"></a>
|
<a name="H1_5"></a>
|
||||||
# Submitting Your Changes
|
# Submitting Your Changes
|
||||||
|
|
||||||
|
|
||||||
To create and submit a change:
|
To create and submit a change:
|
||||||
|
|
||||||
|
|
||||||
1. Create a new branch off the master for your changes:
|
1. Create a new branch off the master for your changes:
|
||||||
|
|
||||||
|
|
||||||
git branch my-fix-branch
|
git branch my-fix-branch
|
||||||
|
|
||||||
|
|
||||||
2. Check out the branch:
|
2. Check out the branch:
|
||||||
|
|
||||||
|
|
||||||
git checkout my-fix-branch
|
git checkout my-fix-branch
|
||||||
|
|
||||||
|
|
||||||
3. Create your patch, make sure to have plenty of tests (that pass).
|
3. Create your patch, make sure to have plenty of tests (that pass).
|
||||||
|
|
||||||
|
|
||||||
4. Commit your changes:
|
4. Commit your changes:
|
||||||
|
|
||||||
|
|
||||||
git commit -a
|
git commit -a
|
||||||
|
|
||||||
|
|
||||||
5. Run JavaScript Lint and be sure to address all new warnings and errors:
|
5. Run JavaScript Lint and be sure to address all new warnings and errors:
|
||||||
|
|
||||||
|
|
||||||
rake lint
|
rake lint
|
||||||
|
|
||||||
|
|
||||||
6. Push your branch to Github:
|
6. Push your branch to Github:
|
||||||
|
|
||||||
|
|
||||||
git push origin my-fix-branch
|
git push origin my-fix-branch
|
||||||
|
|
||||||
|
|
||||||
7. In Github, send a pull request to `angular:master`.
|
7. In Github, send a pull request to `angular:master`.
|
||||||
|
|
||||||
|
|
||||||
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
|
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
|
||||||
from the main (upstream) repository:
|
from the main (upstream) repository:
|
||||||
|
|
||||||
1. To delete the branch in Github, run:
|
1. To delete the branch in Github, run:
|
||||||
|
|
||||||
|
|
||||||
git push origin :my-fix-branch
|
git push origin :my-fix-branch
|
||||||
|
|
||||||
|
|
||||||
2. To check out the master branch, run:
|
2. To check out the master branch, run:
|
||||||
|
|
||||||
|
|
||||||
git checkout master
|
git checkout master
|
||||||
|
|
||||||
|
|
||||||
3. To delete a local branch, run:
|
3. To delete a local branch, run:
|
||||||
|
|
||||||
|
|
||||||
git branch -D my-fix-branch
|
git branch -D my-fix-branch
|
||||||
|
|
||||||
|
|
||||||
4. To update your master with the latest upstream version, run:
|
4. To update your master with the latest upstream version, run:
|
||||||
|
|
||||||
|
|
||||||
git pull --ff upstream master
|
git pull --ff upstream master
|
||||||
|
|
||||||
|
|
||||||
That's it! Thank you for your contribution!
|
That's it! Thank you for your contribution!
|
||||||
|
|
|
||||||
|
|
@ -3,27 +3,22 @@
|
||||||
@name Downloading
|
@name Downloading
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
# Including angular scripts from the angular server
|
# Including angular scripts from the angular server
|
||||||
The quickest way to get started is to point your html `<script>` tag to a
|
The quickest way to get started is to point your html `<script>` tag to a
|
||||||
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
|
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
|
||||||
local copy.
|
local copy.
|
||||||
|
|
||||||
|
|
||||||
There are two types of angular script URLs you can point to, one for development and one for
|
There are two types of angular script URLs you can point to, one for development and one for
|
||||||
production:
|
production:
|
||||||
|
|
||||||
|
|
||||||
* __angular-<version>.js__ — This is the human-readable, non-minified version, suitable for web
|
* __angular-<version>.js__ — This is the human-readable, non-minified version, suitable for web
|
||||||
development.
|
development.
|
||||||
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
||||||
production.
|
production.
|
||||||
|
|
||||||
|
|
||||||
To point your code to an angular script on the angular server, use the following template. This
|
To point your code to an angular script on the angular server, use the following template. This
|
||||||
example points to (non-minified) version 0.9.12:
|
example points to (non-minified) version 0.9.12:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
@ -37,51 +32,40 @@ example points to (non-minified) version 0.9.12:
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Downloading and hosting angular files locally
|
# Downloading and hosting angular files locally
|
||||||
This option is for those who want to work with angular offline, or those who want to host the
|
This option is for those who want to work with angular offline, or those who want to host the
|
||||||
angular files on their own servers.
|
angular files on their own servers.
|
||||||
|
|
||||||
|
|
||||||
If you navigate to <http://code.angularjs.org/>, you'll see a directory listing with all of the
|
If you navigate to <http://code.angularjs.org/>, you'll see a directory listing with all of the
|
||||||
angular versions since we started releasing versioned build artifacts (quite late in the project
|
angular versions since we started releasing versioned build artifacts (quite late in the project
|
||||||
lifetime). Each directory contains all artifacts that we released for a particular version.
|
lifetime). Each directory contains all artifacts that we released for a particular version.
|
||||||
Download the version you want and have fun.
|
Download the version you want and have fun.
|
||||||
|
|
||||||
|
|
||||||
Each directory under <http://code.angularjs.org/> includes the following set of files:
|
Each directory under <http://code.angularjs.org/> includes the following set of files:
|
||||||
|
|
||||||
|
|
||||||
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by
|
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by
|
||||||
opening it it any editor or browser. In order to get better error messages during development, you
|
opening it it any editor or browser. In order to get better error messages during development, you
|
||||||
should always use this non-minified angular script.
|
should always use this non-minified angular script.
|
||||||
|
|
||||||
|
|
||||||
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of
|
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of
|
||||||
`angular-<version>.js` created with the Closure compiler. Use this version for production in order
|
`angular-<version>.js` created with the Closure compiler. Use this version for production in order
|
||||||
to minimize the size of the application that is downloaded by your user's browser.
|
to minimize the size of the application that is downloaded by your user's browser.
|
||||||
|
|
||||||
|
|
||||||
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released
|
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released
|
||||||
for this angular version. Use this file to get everything in a single download.
|
for this angular version. Use this file to get everything in a single download.
|
||||||
|
|
||||||
|
|
||||||
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
|
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
|
||||||
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
|
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
|
||||||
of angular files, make sure that this file is available for download, and that it resides under the
|
of angular files, make sure that this file is available for download, and that it resides under the
|
||||||
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
|
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
|
||||||
|
|
||||||
|
|
||||||
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
|
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
|
||||||
testing angular apps even easier. Your unit/integration test harness should load this file after
|
testing angular apps even easier. Your unit/integration test harness should load this file after
|
||||||
`angular-<version>.js` is loaded.
|
`angular-<version>.js` is loaded.
|
||||||
|
|
||||||
|
|
||||||
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you
|
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you
|
||||||
to write and execute end-to-end tests for angular applications.
|
to write and execute end-to-end tests for angular applications.
|
||||||
|
|
||||||
|
|
||||||
* __`docs-<version>`__ — this directory contains all the files that compose the
|
* __`docs-<version>`__ — this directory contains all the files that compose the
|
||||||
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
|
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
|
||||||
our docs, or even more importantly, view the docs offline.
|
our docs, or even more importantly, view the docs offline.
|
||||||
|
|
|
||||||
|
|
@ -3,49 +3,36 @@
|
||||||
@name FAQ
|
@name FAQ
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
#FAQ
|
#FAQ
|
||||||
|
|
||||||
|
|
||||||
### Why is this project called "angular"? Why is the namespace called "ng"?
|
### Why is this project called "angular"? Why is the namespace called "ng"?
|
||||||
|
|
||||||
|
|
||||||
Because HTML has angular brackets and "ng" sounds like "angular".
|
Because HTML has angular brackets and "ng" sounds like "angular".
|
||||||
|
|
||||||
|
|
||||||
### Is <angular/> an HTML5 tag?
|
### Is <angular/> an HTML5 tag?
|
||||||
|
|
||||||
|
|
||||||
No, <angular/> is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two
|
No, <angular/> is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two
|
||||||
together.
|
together.
|
||||||
|
|
||||||
|
|
||||||
### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}?
|
### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}?
|
||||||
|
|
||||||
|
|
||||||
No, angular is none of these. You don't call its functions, it does not call your functions,
|
No, angular is none of these. You don't call its functions, it does not call your functions,
|
||||||
it does not provide a way to manipulate DOM, but does provide primitives to create UI projections
|
it does not provide a way to manipulate DOM, but does provide primitives to create UI projections
|
||||||
of your data. There are lots of existing widget libraries which you can integrate with angular.
|
of your data. There are lots of existing widget libraries which you can integrate with angular.
|
||||||
It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
||||||
|
|
||||||
|
|
||||||
### Do I need to worry about security holes in angular?
|
### Do I need to worry about security holes in angular?
|
||||||
|
|
||||||
|
|
||||||
Like with any technology, angular is not impervious to attack. angular does, however, provide
|
Like with any technology, angular is not impervious to attack. angular does, however, provide
|
||||||
built-in protection from basic security holes including cross-site scripting and HTML injection
|
built-in protection from basic security holes including cross-site scripting and HTML injection
|
||||||
attacks. angular does round-trip escaping on all strings for you.
|
attacks. angular does round-trip escaping on all strings for you.
|
||||||
|
|
||||||
|
|
||||||
### Can I download the source, build, and host the angular environment locally?
|
### Can I download the source, build, and host the angular environment locally?
|
||||||
|
|
||||||
|
|
||||||
Yes. See instructions in {@link downloading}.
|
Yes. See instructions in {@link downloading}.
|
||||||
|
|
||||||
|
|
||||||
### Is angular a templating system?
|
### Is angular a templating system?
|
||||||
|
|
||||||
|
|
||||||
At the highest level, angular does look like a just another templating system. But there is one
|
At the highest level, angular does look like a just another templating system. But there is one
|
||||||
important reason why angular templating system is different and makes it very good fit for
|
important reason why angular templating system is different and makes it very good fit for
|
||||||
application development: bidirectional data binding. The template is compiled on the browser and
|
application development: bidirectional data binding. The template is compiled on the browser and
|
||||||
|
|
@ -53,59 +40,43 @@ the compilation step produces a live view. This means you, the developer, don't
|
||||||
code to constantly sync the view with the model and the model with the view as in other
|
code to constantly sync the view with the model and the model with the view as in other
|
||||||
templating systems.
|
templating systems.
|
||||||
|
|
||||||
|
|
||||||
### What browsers does angular work with?
|
### What browsers does angular work with?
|
||||||
|
|
||||||
|
|
||||||
Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and
|
Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and
|
||||||
above. Note that CSS only works on IE7 and above.
|
above. Note that CSS only works on IE7 and above.
|
||||||
|
|
||||||
|
|
||||||
### What's angular's performance like?
|
### What's angular's performance like?
|
||||||
|
|
||||||
|
|
||||||
angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your
|
angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your
|
||||||
app's performance will vary depending on how many bindings you use.
|
app's performance will vary depending on how many bindings you use.
|
||||||
|
|
||||||
|
|
||||||
### How big is the angular bootstrap JS file that I need to include?
|
### How big is the angular bootstrap JS file that I need to include?
|
||||||
|
|
||||||
|
|
||||||
The size of the library itself is < 50KB compressed and obfuscated.
|
The size of the library itself is < 50KB compressed and obfuscated.
|
||||||
|
|
||||||
|
|
||||||
### Can I use the open-source Closure Library with angular?
|
### Can I use the open-source Closure Library with angular?
|
||||||
|
|
||||||
|
|
||||||
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
|
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
|
||||||
in angular.
|
in angular.
|
||||||
|
|
||||||
|
|
||||||
### Does angular use the jQuery library?
|
### Does angular use the jQuery library?
|
||||||
|
|
||||||
|
|
||||||
Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library.
|
Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library.
|
||||||
If jQuery is not present in your script path, angular falls back on its own implementation of
|
If jQuery is not present in your script path, angular falls back on its own implementation of
|
||||||
{@link api/angular.element jQuery lite}. If jQuery is present in the path, angular uses it to
|
{@link api/angular.element jQuery lite}. If jQuery is present in the path, angular uses it to
|
||||||
manipulate the DOM.
|
manipulate the DOM.
|
||||||
|
|
||||||
|
|
||||||
### What is testability like in angular?
|
### What is testability like in angular?
|
||||||
|
|
||||||
|
|
||||||
Very testable. It has an integrated dependency injection framework. See
|
Very testable. It has an integrated dependency injection framework. See
|
||||||
{@link api/angular.service service} for details.
|
{@link api/angular.service service} for details.
|
||||||
|
|
||||||
|
|
||||||
### How can I learn more about angular?
|
### How can I learn more about angular?
|
||||||
|
|
||||||
|
|
||||||
Watch the July 28, 2010 talk
|
Watch the July 28, 2010 talk
|
||||||
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
||||||
AJAX Apps}".
|
AJAX Apps}".
|
||||||
|
|
||||||
|
|
||||||
### How is angular licensed?
|
### How is angular licensed?
|
||||||
|
|
||||||
|
|
||||||
The MIT License.
|
The MIT License.
|
||||||
|
|
|
||||||
|
|
@ -2,89 +2,69 @@
|
||||||
@name Getting Started
|
@name Getting Started
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
# Hello World!
|
# Hello World!
|
||||||
|
|
||||||
|
|
||||||
A great way for you to get started with `angular` is to create the tradtional
|
A great way for you to get started with `angular` is to create the tradtional
|
||||||
"Hello World!" app:
|
"Hello World!" app:
|
||||||
|
|
||||||
|
|
||||||
1. In your favorite text editor, create an HTML file
|
1. In your favorite text editor, create an HTML file
|
||||||
(for example, `helloworld.html`).
|
(for example, `helloworld.html`).
|
||||||
2. From the __Source__ box below, copy and paste the code into your HTML file.
|
2. From the __Source__ box below, copy and paste the code into your HTML file.
|
||||||
(Double-click on the source to easily select all.)
|
(Double-click on the source to easily select all.)
|
||||||
3. Open the file in your web browser.
|
3. Open the file in your web browser.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
Hello {{'World'}}!
|
Hello {{'World'}}!
|
||||||
</doc:source>
|
</doc:source>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
The resulting web page should look something like the following:
|
The resulting web page should look something like the following:
|
||||||
|
|
||||||
|
|
||||||
<img class="center" src="img/helloworld.png" border="1" />
|
<img class="center" src="img/helloworld.png" border="1" />
|
||||||
|
|
||||||
|
|
||||||
Now let's take a closer look at that code, and see what is going on behind
|
Now let's take a closer look at that code, and see what is going on behind
|
||||||
the scenes.
|
the scenes.
|
||||||
|
|
||||||
|
|
||||||
The first line of interest defines the `ng` namespace, which makes
|
The first line of interest defines the `ng` namespace, which makes
|
||||||
`angular` work across all browsers (especially important for IE):
|
`angular` work across all browsers (especially important for IE):
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The next line downloads the `angular` script, and instructs `angular` to process
|
The next line downloads the `angular` script, and instructs `angular` to process
|
||||||
the entire HTML page when it is loaded:
|
the entire HTML page when it is loaded:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<script type="text/javascript" src="http://code.angularjs.org/angular-?.?.?.min.js"
|
<script type="text/javascript" src="http://code.angularjs.org/angular-?.?.?.min.js"
|
||||||
ng:autobind></script>
|
ng:autobind></script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
(For details on what happens when `angular` processes an HTML page,
|
(For details on what happens when `angular` processes an HTML page,
|
||||||
see {@link guide/dev_guide.bootstrap Bootstrap}.)
|
see {@link guide/dev_guide.bootstrap Bootstrap}.)
|
||||||
|
|
||||||
|
|
||||||
Finally, this line in the `<body>` of the page is the template that describes
|
Finally, this line in the `<body>` of the page is the template that describes
|
||||||
how to display our greeting in the UI:
|
how to display our greeting in the UI:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
Hello {{'World'}}!
|
Hello {{'World'}}!
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Note the use of the double curly brace markup (`{{ }}`) to bind the expression to
|
Note the use of the double curly brace markup (`{{ }}`) to bind the expression to
|
||||||
the greeting text. Here the expression is the string literal 'World'.
|
the greeting text. Here the expression is the string literal 'World'.
|
||||||
|
|
||||||
|
|
||||||
Next let's look at a more interesting example, that uses `angular` to
|
Next let's look at a more interesting example, that uses `angular` to
|
||||||
bind a dynamic expression to our greeting text.
|
bind a dynamic expression to our greeting text.
|
||||||
|
|
||||||
|
|
||||||
# Hello <angular/> World!
|
# Hello <angular/> World!
|
||||||
|
|
||||||
|
|
||||||
This example demonstrates `angular`'s two-way data binding:
|
This example demonstrates `angular`'s two-way data binding:
|
||||||
|
|
||||||
|
|
||||||
1. Edit the HTML file you created in the "Hello World!" example above.
|
1. Edit the HTML file you created in the "Hello World!" example above.
|
||||||
2. Replace the contents of `<body>` with the code from the __Source__ box below.
|
2. Replace the contents of `<body>` with the code from the __Source__ box below.
|
||||||
3. Refresh your browswer window.
|
3. Refresh your browswer window.
|
||||||
|
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
Your name: <input type="text" name="yourname" value="World"/>
|
Your name: <input type="text" name="yourname" value="World"/>
|
||||||
|
|
@ -93,24 +73,18 @@ This example demonstrates `angular`'s two-way data binding:
|
||||||
</doc:source>
|
</doc:source>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
After the refresh, the page should look something like this:
|
After the refresh, the page should look something like this:
|
||||||
|
|
||||||
|
|
||||||
<img class="left" src="img/helloworld_2way.png" border="1" />
|
<img class="left" src="img/helloworld_2way.png" border="1" />
|
||||||
|
|
||||||
|
|
||||||
These are some of the important points to note from this example:
|
These are some of the important points to note from this example:
|
||||||
|
|
||||||
|
|
||||||
* The text input {@link api/angular.widget widget} called `yourname` is bound to a model variable
|
* The text input {@link api/angular.widget widget} called `yourname` is bound to a model variable
|
||||||
called `yourname`.
|
called `yourname`.
|
||||||
* The double curly braces notation binds the `yourname` model to the greeting text.
|
* The double curly braces notation binds the `yourname` model to the greeting text.
|
||||||
|
|
||||||
|
|
||||||
* You did not need to explicitly register an event listener or define an event handler for events!
|
* You did not need to explicitly register an event listener or define an event handler for events!
|
||||||
|
|
||||||
|
|
||||||
Now try typing your name into the input box, and notice the immediate change to
|
Now try typing your name into the input box, and notice the immediate change to
|
||||||
the displayed greeting. This demonstrates the concept of `angular`'s
|
the displayed greeting. This demonstrates the concept of `angular`'s
|
||||||
{@link guide/dev_guide.templates.databinding bi-directional data binding}. Any changes to the input
|
{@link guide/dev_guide.templates.databinding bi-directional data binding}. Any changes to the input
|
||||||
|
|
@ -119,70 +93,50 @@ reflected in the model (one direction), and any changes to the model are
|
||||||
reflected in the greeting text (the other direction).
|
reflected in the greeting text (the other direction).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Anatomy Of An Angular App
|
# Anatomy Of An Angular App
|
||||||
|
|
||||||
|
|
||||||
This section describes the 3 parts of an angular app, and explains how they map to the
|
This section describes the 3 parts of an angular app, and explains how they map to the
|
||||||
Model-View-Controller design pattern:
|
Model-View-Controller design pattern:
|
||||||
|
|
||||||
|
|
||||||
## Templates
|
## Templates
|
||||||
|
|
||||||
|
|
||||||
Templates, which you write in HTML and CSS, serve as the View. You add elements, attributes, and
|
Templates, which you write in HTML and CSS, serve as the View. You add elements, attributes, and
|
||||||
markup to HTML, which serve as instructions to the angular compiler. The angular compiler is fully
|
markup to HTML, which serve as instructions to the angular compiler. The angular compiler is fully
|
||||||
extensible, meaning that with angular you can build your own declarative language on top of HTML!
|
extensible, meaning that with angular you can build your own declarative language on top of HTML!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Application Logic and Behavior
|
## Application Logic and Behavior
|
||||||
|
|
||||||
|
|
||||||
Application Logic and Behavior, which you define in JavaScript, serve as the Controller. With
|
Application Logic and Behavior, which you define in JavaScript, serve as the Controller. With
|
||||||
angular (unlike with standard AJAX applications) you don't need to write additional listeners or
|
angular (unlike with standard AJAX applications) you don't need to write additional listeners or
|
||||||
DOM manipulators, because they are built-in. This feature makes your application logic very easy to
|
DOM manipulators, because they are built-in. This feature makes your application logic very easy to
|
||||||
write, test, maintain, and understand.
|
write, test, maintain, and understand.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
|
|
||||||
|
|
||||||
The Model is referenced from properties on {@link guide/dev_guide.scopes angular scope objects}.
|
The Model is referenced from properties on {@link guide/dev_guide.scopes angular scope objects}.
|
||||||
The data in your model could be Javascript objects, arrays, or primitives, it doesn't matter. What
|
The data in your model could be Javascript objects, arrays, or primitives, it doesn't matter. What
|
||||||
matters is that these are all referenced by the scope object.
|
matters is that these are all referenced by the scope object.
|
||||||
|
|
||||||
|
|
||||||
Angular employs scopes to keep your data model and your UI in sync. Whenever something occurs to
|
Angular employs scopes to keep your data model and your UI in sync. Whenever something occurs to
|
||||||
change the state of the model, angular immediately reflects that change in the UI, and vice versa.
|
change the state of the model, angular immediately reflects that change in the UI, and vice versa.
|
||||||
|
|
||||||
|
|
||||||
The following illustration shows the parts of an angular application and how they work together:
|
The following illustration shows the parts of an angular application and how they work together:
|
||||||
|
|
||||||
|
|
||||||
<img class="left" src="img/angular_parts.png" border="0" />
|
<img class="left" src="img/angular_parts.png" border="0" />
|
||||||
|
|
||||||
|
|
||||||
In addition, angular comes with a set of Services, which have the following properties:
|
In addition, angular comes with a set of Services, which have the following properties:
|
||||||
|
|
||||||
|
|
||||||
* The services provided are very useful for building web applications.
|
* The services provided are very useful for building web applications.
|
||||||
* You can extend and add application-specific behavior to services.
|
* You can extend and add application-specific behavior to services.
|
||||||
* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction.
|
* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Where To Go Next
|
# Where To Go Next
|
||||||
|
|
||||||
|
|
||||||
* For explanations and examples of the angular concepts presented on this page, see the {@link
|
* For explanations and examples of the angular concepts presented on this page, see the {@link
|
||||||
guide/index Developer Guide}.
|
guide/index Developer Guide}.
|
||||||
|
|
||||||
|
|
||||||
* For additional hands-on examples of using `angular`, including more source code that you can
|
* For additional hands-on examples of using `angular`, including more source code that you can
|
||||||
copy and paste into your own pages, take a look through the `angular` {@link cookbook/ Cookbook}.
|
copy and paste into your own pages, take a look through the `angular` {@link cookbook/ Cookbook}.
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,16 @@
|
||||||
@name Tutorial
|
@name Tutorial
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
A great way to get introduced to angular is to work through this tutorial, which walks you through
|
A great way to get introduced to angular is to work through this tutorial, which walks you through
|
||||||
the construction of an angular web app. The app you will build is a catalog that displays a list of
|
the construction of an angular web app. The app you will build is a catalog that displays a list of
|
||||||
Android devices, lets you filter the list to see only devices that interest you, and then view
|
Android devices, lets you filter the list to see only devices that interest you, and then view
|
||||||
details for any device.
|
details for any device.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/catalog_screen.png">
|
<img src="img/tutorial/catalog_screen.png">
|
||||||
|
|
||||||
|
|
||||||
As you work through this tutorial, you will learn how angular makes browsers smarter — without the
|
As you work through this tutorial, you will learn how angular makes browsers smarter — without the
|
||||||
use of extensions or plugins.
|
use of extensions or plugins.
|
||||||
|
|
||||||
|
|
||||||
* You will see examples of how to use client-side data binding and dependency injection to build
|
* You will see examples of how to use client-side data binding and dependency injection to build
|
||||||
dynamic views of data that change immediately in response to user actions.
|
dynamic views of data that change immediately in response to user actions.
|
||||||
* You will see how angular creates listeners on your data without the need for DOM manipulation.
|
* You will see how angular creates listeners on your data without the need for DOM manipulation.
|
||||||
|
|
@ -23,13 +19,10 @@ dynamic views of data that change immediately in response to user actions.
|
||||||
* You will learn how to use angular services to make common web tasks, such as getting data into
|
* You will learn how to use angular services to make common web tasks, such as getting data into
|
||||||
your app, easier.
|
your app, easier.
|
||||||
|
|
||||||
|
|
||||||
And all of this works in any browser without modifications!
|
And all of this works in any browser without modifications!
|
||||||
|
|
||||||
|
|
||||||
When you finish the tutorial you will be able to:
|
When you finish the tutorial you will be able to:
|
||||||
|
|
||||||
|
|
||||||
* Create a dynamic application that works in any browser
|
* Create a dynamic application that works in any browser
|
||||||
* Define the differences between angular and common JavaScript frameworks
|
* Define the differences between angular and common JavaScript frameworks
|
||||||
* Understand how data binding works in angular
|
* Understand how data binding works in angular
|
||||||
|
|
@ -37,12 +30,10 @@ When you finish the tutorial you will be able to:
|
||||||
* Create and run tests
|
* Create and run tests
|
||||||
* Identify resources for learning more about angular
|
* Identify resources for learning more about angular
|
||||||
|
|
||||||
|
|
||||||
The tutorial is will guide you through the process of building a simple application, including
|
The tutorial is will guide you through the process of building a simple application, including
|
||||||
writing and running unit and end-to-end tests, and will allow you to experiment with angular and
|
writing and running unit and end-to-end tests, and will allow you to experiment with angular and
|
||||||
the application through experiments suggested at the end of each step.
|
the application through experiments suggested at the end of each step.
|
||||||
|
|
||||||
|
|
||||||
You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
|
You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
|
||||||
really digging into it. If you're looking for a shorter introduction to angular, check out the
|
really digging into it. If you're looking for a shorter introduction to angular, check out the
|
||||||
{@link misc/started Getting Started} document.
|
{@link misc/started Getting Started} document.
|
||||||
|
|
@ -53,23 +44,14 @@ really digging into it. If you're looking for a shorter introduction to angular,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Working with the code
|
# Working with the code
|
||||||
|
|
||||||
|
|
||||||
There are two ways that you can you follow this tutorial and hack on the code, both available on
|
There are two ways that you can you follow this tutorial and hack on the code, both available on
|
||||||
Mac/Linux or Windows environment. The first work flow uses Git versioning system for source code
|
Mac/Linux or Windows environment. The first work flow uses Git versioning system for source code
|
||||||
management, the second work flow doesn't depend on any source control system and instead uses
|
management, the second work flow doesn't depend on any source control system and instead uses
|
||||||
scripts to copy snapshots of project files into your workspace (`sandbox`) directory. Choose the
|
scripts to copy snapshots of project files into your workspace (`sandbox`) directory. Choose the
|
||||||
one you prefer:
|
one you prefer:
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions show="true">
|
<doc:tutorial-instructions show="true">
|
||||||
<doc:tutorial-instruction id="git-mac" title="Git on Mac/Linux">
|
<doc:tutorial-instruction id="git-mac" title="Git on Mac/Linux">
|
||||||
<ol>
|
<ol>
|
||||||
|
|
@ -95,7 +77,6 @@ server.</p></li>
|
||||||
</ol>
|
</ol>
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instruction id="git-win" title="Git on Windows">
|
<doc:tutorial-instruction id="git-win" title="Git on Windows">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
|
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
|
||||||
|
|
@ -123,7 +104,6 @@ href="http://node-js.prcn.co.cc/">pre-compiled binaries</a>, unzip them and add
|
||||||
</ol>
|
</ol>
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instruction id="ss-mac" title="Snapshots on Mac/Linux">
|
<doc:tutorial-instruction id="ss-mac" title="Snapshots on Mac/Linux">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the
|
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the
|
||||||
|
|
@ -144,7 +124,6 @@ server.</p></li>
|
||||||
</ol>
|
</ol>
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instruction id="ss-win" title="Snapshots on Windows">
|
<doc:tutorial-instruction id="ss-win" title="Snapshots on Windows">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
|
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
|
||||||
|
|
@ -167,9 +146,6 @@ href="http://node-js.prcn.co.cc/">pre-compiled binaries</a>, unzip them and add
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
</doc:tutorial-instructions>
|
</doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
For either work flow you'll also need a web browser and your favorite text editor.
|
For either work flow you'll also need a web browser and your favorite text editor.
|
||||||
|
|
||||||
|
|
||||||
Let's get going with {@link step_00 step 0}.
|
Let's get going with {@link step_00 step 0}.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,14 @@
|
||||||
@name Tutorial: 0 - angular-seed
|
@name Tutorial: 0 - angular-seed
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="0"></ul>
|
<ul doc:tutorial-nav="0"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You are now ready to build the phonecat application. In this step, you will become familiar with
|
You are now ready to build the phonecat application. In this step, you will become familiar with
|
||||||
the most important source code files, learn how to start the development servers bundled with
|
the most important source code files, learn how to start the development servers bundled with
|
||||||
angular-seed, and run the application in the browser.
|
angular-seed, and run the application in the browser.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions show="true">
|
<doc:tutorial-instructions show="true">
|
||||||
<doc:tutorial-instruction id="git-mac" title="Git on Mac/Linux">
|
<doc:tutorial-instruction id="git-mac" title="Git on Mac/Linux">
|
||||||
<ol>
|
<ol>
|
||||||
|
|
@ -25,7 +20,6 @@ angular-seed, and run the application in the browser.
|
||||||
the number of the step you are on. This will cause any changes you made within
|
the number of the step you are on. This will cause any changes you made within
|
||||||
your working directory to be lost.</p></li>
|
your working directory to be lost.</p></li>
|
||||||
|
|
||||||
|
|
||||||
<li>To see the app running in a browser, do one of the following:
|
<li>To see the app running in a browser, do one of the following:
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>For node.js users:</b>
|
<li><b>For node.js users:</b>
|
||||||
|
|
@ -50,8 +44,6 @@ directory.</li>
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instruction id="git-win" title="Git on Windows">
|
<doc:tutorial-instruction id="git-win" title="Git on Windows">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p>
|
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p>
|
||||||
|
|
@ -84,8 +76,6 @@ directory.</li>
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instruction id="ss-mac" title="Snapshots on Mac/Linux">
|
<doc:tutorial-instruction id="ss-mac" title="Snapshots on Mac/Linux">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>In angular-phonecat directory, run this command:</p>
|
<li><p>In angular-phonecat directory, run this command:</p>
|
||||||
|
|
@ -118,8 +108,6 @@ href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html
|
||||||
</doc:tutorial-instruction>
|
</doc:tutorial-instruction>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instruction id="ss-win" title="Snapshots on Windows">
|
<doc:tutorial-instruction id="ss-win" title="Snapshots on Windows">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Open windows command line and run this command (in angular-phonecat directory):</p>
|
<li><p>Open windows command line and run this command (in angular-phonecat directory):</p>
|
||||||
|
|
@ -153,15 +141,11 @@ href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html
|
||||||
</doc:tutorial-instructions>
|
</doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You can now see the page in your browser. It's not very exciting, but that's OK.
|
You can now see the page in your browser. It's not very exciting, but that's OK.
|
||||||
|
|
||||||
|
|
||||||
The static HTML page that displays "Nothing here yet!" was constructed with the HTML code shown
|
The static HTML page that displays "Nothing here yet!" was constructed with the HTML code shown
|
||||||
below. The code contains some key angular elements that we will need going forward.
|
below. The code contains some key angular elements that we will need going forward.
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
@ -173,10 +157,8 @@ __`app/index.html`:__
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
||||||
Nothing here yet!
|
Nothing here yet!
|
||||||
|
|
||||||
|
|
||||||
<script src="lib/angular/angular.js" ng:autobind></script>
|
<script src="lib/angular/angular.js" ng:autobind></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -184,73 +166,51 @@ __`app/index.html`:__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## What is the code doing?
|
## What is the code doing?
|
||||||
|
|
||||||
|
|
||||||
* xmlns declaration
|
* xmlns declaration
|
||||||
|
|
||||||
|
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
||||||
|
|
||||||
This `xmlns` declaration for the `ng` namespace must be specified in all angular applications in
|
This `xmlns` declaration for the `ng` namespace must be specified in all angular applications in
|
||||||
order to make angular work with XHTML and IE versions older than 9 (regardless of whether you are
|
order to make angular work with XHTML and IE versions older than 9 (regardless of whether you are
|
||||||
using XHTML or HTML).
|
using XHTML or HTML).
|
||||||
|
|
||||||
|
|
||||||
* angular script tag
|
* angular script tag
|
||||||
|
|
||||||
|
|
||||||
<script src="lib/angular/angular.js" ng:autobind>
|
<script src="lib/angular/angular.js" ng:autobind>
|
||||||
|
|
||||||
|
|
||||||
This single line of code is all that is needed to bootstrap an angular application.
|
This single line of code is all that is needed to bootstrap an angular application.
|
||||||
|
|
||||||
|
|
||||||
The code downloads the `angular.js` script and registers a callback that will be executed by the
|
The code downloads the `angular.js` script and registers a callback that will be executed by the
|
||||||
browser when the containing HTML page is fully downloaded. When the callback is executed, angular
|
browser when the containing HTML page is fully downloaded. When the callback is executed, angular
|
||||||
looks for the {@link api/angular.directive.ng:autobind ng:autobind} attribute. If angular finds
|
looks for the {@link api/angular.directive.ng:autobind ng:autobind} attribute. If angular finds
|
||||||
`ng:autobind`, it creates a root scope for the application and associates it with the `<html>`
|
`ng:autobind`, it creates a root scope for the application and associates it with the `<html>`
|
||||||
element of the template:
|
element of the template:
|
||||||
|
|
||||||
|
<img src="img/tutorial/tutorial_00_final.png">
|
||||||
<img src="img/tutorial/tutorial_00_final.png"/>
|
|
||||||
|
|
||||||
|
|
||||||
As you will see shortly, everything in angular is evaluated within a scope. We'll learn more
|
As you will see shortly, everything in angular is evaluated within a scope. We'll learn more
|
||||||
about this in the next steps.
|
about this in the next steps.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## What are all these files in my working directory?
|
## What are all these files in my working directory?
|
||||||
|
|
||||||
|
|
||||||
Most of the files in your working directory come from the {@link
|
Most of the files in your working directory come from the {@link
|
||||||
https://github.com/angular/angular-seed angular-seed project} which is typically used to bootstrap
|
https://github.com/angular/angular-seed angular-seed project} which is typically used to bootstrap
|
||||||
new angular projects. The seed project includes the latest angular libraries, test libraries,
|
new angular projects. The seed project includes the latest angular libraries, test libraries,
|
||||||
scripts and a simple example app, all pre-configured for developing a typical web app.
|
scripts and a simple example app, all pre-configured for developing a typical web app.
|
||||||
|
|
||||||
|
|
||||||
For the purposes of this tutorial, we modified the angular-seed with the following changes:
|
For the purposes of this tutorial, we modified the angular-seed with the following changes:
|
||||||
|
|
||||||
|
|
||||||
* Removed the example app
|
* Removed the example app
|
||||||
* Added phone images to `app/img/phones`
|
* Added phone images to `app/img/phones`
|
||||||
* Added phone data files (JSON) to `app/phones`
|
* Added phone data files (JSON) to `app/phones`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
Now let's go to step 1 and add some content to the web app.
|
Now let's go to step 1 and add some content to the web app.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="0"></ul>
|
<ul doc:tutorial-nav="0"></ul>
|
||||||
|
|
|
||||||
|
|
@ -2,34 +2,24 @@
|
||||||
@name Tutorial: 1 - Static Template
|
@name Tutorial: 1 - Static Template
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="1"></ul>
|
<ul doc:tutorial-nav="1"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
|
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
|
||||||
page and then examine how we can turn this HTML code into a template that angular will use to
|
page and then examine how we can turn this HTML code into a template that angular will use to
|
||||||
dynamically display the same result with any set of data.
|
dynamically display the same result with any set of data.
|
||||||
|
|
||||||
|
|
||||||
In this step you will add some basic information about two cell phones to an HTML page.
|
In this step you will add some basic information about two cell phones to an HTML page.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="1" show="true"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="1" show="true"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The page now contains a list with information about two phones.
|
The page now contains a list with information about two phones.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-0...step-1 GitHub}:
|
https://github.com/angular/angular-phonecat/compare/step-0...step-1 GitHub}:
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -51,27 +41,17 @@ __`app/index.html`:__
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Try adding more static HTML to `index.html`. For example:
|
* Try adding more static HTML to `index.html`. For example:
|
||||||
|
|
||||||
|
|
||||||
<p>Total number of phones: 2</p>
|
<p>Total number of phones: 2</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
This addition to your app uses static HTML to display the list. Now, let's go to step 2 to learn
|
This addition to your app uses static HTML to display the list. Now, let's go to step 2 to learn
|
||||||
how to use angular to dynamically generate the same list.
|
how to use angular to dynamically generate the same list.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="1"></ul>
|
<ul doc:tutorial-nav="1"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,50 +2,36 @@
|
||||||
@name Tutorial: 2 - Angular Template
|
@name Tutorial: 2 - Angular Template
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="2"></ul>
|
<ul doc:tutorial-nav="2"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Now it's time to make this web page dynamic with angular. We'll also add a test that verifies the
|
Now it's time to make this web page dynamic with angular. We'll also add a test that verifies the
|
||||||
code for the controller we are going to add.
|
code for the controller we are going to add.
|
||||||
|
|
||||||
|
|
||||||
There are many ways to structure the code for an application. With angular, we encourage the use of
|
There are many ways to structure the code for an application. With angular, we encourage the use of
|
||||||
{@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design pattern} to decouple the
|
{@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design pattern} to decouple the
|
||||||
code and separate concerns. With that in mind, let's use a little angular and JavaScript to add
|
code and separate concerns. With that in mind, let's use a little angular and JavaScript to add
|
||||||
model, view, and controller components to our app.
|
model, view, and controller components to our app.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="2"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="2"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The app now contains a list with 3 phones.
|
The app now contains a list with 3 phones.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-1...step-2 GitHub}:
|
https://github.com/angular/angular-phonecat/compare/step-1...step-2 GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template for the View
|
## Template for the View
|
||||||
|
|
||||||
|
|
||||||
The __view__ component is constructed by angular from this template:
|
The __view__ component is constructed by angular from this template:
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
<body ng:controller="PhoneListCtrl">
|
<body ng:controller="PhoneListCtrl">
|
||||||
|
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li ng:repeat="phone in phones">
|
<li ng:repeat="phone in phones">
|
||||||
{{phone.name}}
|
{{phone.name}}
|
||||||
|
|
@ -53,27 +39,22 @@ __`app/index.html`:__
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<script src="lib/angular/angular.js" ng:autobind></script>
|
<script src="lib/angular/angular.js" ng:autobind></script>
|
||||||
<script src="js/controllers.js"></script>
|
<script src="js/controllers.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We replaced the hard-coded phone list with the {@link api/angular.widget.@ng:repeat ng:repeat
|
We replaced the hard-coded phone list with the {@link api/angular.widget.@ng:repeat ng:repeat
|
||||||
widget} and two {@link guide/dev_guide.expressions angular expressions} enclosed in curly braces:
|
widget} and two {@link guide/dev_guide.expressions angular expressions} enclosed in curly braces:
|
||||||
`{{phone.name}}` and `{{phone.snippet}}`:
|
`{{phone.name}}` and `{{phone.snippet}}`:
|
||||||
|
|
||||||
|
|
||||||
* The `ng:repeat="phone in phones"` statement in the `<li>` tag is an angular repeater. It tells
|
* The `ng:repeat="phone in phones"` statement in the `<li>` tag is an angular repeater. It tells
|
||||||
angular to create a `<li>` element for each phone in the phones list, using the first `<li>` tag as
|
angular to create a `<li>` element for each phone in the phones list, using the first `<li>` tag as
|
||||||
the template.
|
the template.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/tutorial_02_final.png">
|
<img src="img/tutorial/tutorial_02_final.png">
|
||||||
|
|
||||||
|
|
||||||
* The curly braces around `phone.name` and `phone.snippet` are an example of {@link
|
* The curly braces around `phone.name` and `phone.snippet` are an example of {@link
|
||||||
guide/dev_guide.compiler.markup angular markup}. The curly markup is shorthand for the angular
|
guide/dev_guide.compiler.markup angular markup}. The curly markup is shorthand for the angular
|
||||||
directive {@link api/angular.directive.ng:bind ng:bind}. The `ng:bind` directives indicate to
|
directive {@link api/angular.directive.ng:bind ng:bind}. The `ng:bind` directives indicate to
|
||||||
|
|
@ -83,15 +64,11 @@ of the model through the HTML template. This means that whenever the model chang
|
||||||
refreshes the appropriate binding points, which updates the view.
|
refreshes the appropriate binding points, which updates the view.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Model and Controller
|
## Model and Controller
|
||||||
|
|
||||||
|
|
||||||
The data __model__ (a simple array of phones in object literal notation) is instantiated within
|
The data __model__ (a simple array of phones in object literal notation) is instantiated within
|
||||||
the __controller__ function (`PhoneListCtrl`):
|
the __controller__ function (`PhoneListCtrl`):
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneListCtrl() {
|
function PhoneListCtrl() {
|
||||||
|
|
@ -107,22 +84,16 @@ function PhoneListCtrl() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Although the controller is not yet doing very much controlling, it is playing a crucial role. By
|
Although the controller is not yet doing very much controlling, it is playing a crucial role. By
|
||||||
providing context for our data model, the controller allows us to establish data-binding between
|
providing context for our data model, the controller allows us to establish data-binding between
|
||||||
the model and the view. Note in the following how we connected the dots between our presentation,
|
the model and the view. Note in the following how we connected the dots between our presentation,
|
||||||
data, and logic components:
|
data, and logic components:
|
||||||
|
|
||||||
|
|
||||||
* The name of our controller function (in the JavaScript file `controllers.js`) matches the {@link
|
* The name of our controller function (in the JavaScript file `controllers.js`) matches the {@link
|
||||||
api/angular.directive.ng:controller ng:controller} directive in the `<body>` tag (`PhoneListCtrl`).
|
api/angular.directive.ng:controller ng:controller} directive in the `<body>` tag (`PhoneListCtrl`).
|
||||||
* We instantiated our data within the scope of our controller function, and our template binding
|
* We instantiated our data within the scope of our controller function, and our template binding
|
||||||
points are located within the block bounded by the `<body ng:controller="PhoneListCtrl">` tag.
|
points are located within the block bounded by the `<body ng:controller="PhoneListCtrl">` tag.
|
||||||
|
|
||||||
|
|
||||||
Angular scopes are a crucial concept in angular; you can think of scopes as the glue that makes the
|
Angular scopes are a crucial concept in angular; you can think of scopes as the glue that makes the
|
||||||
template, model and controller all work together. Angular uses scopes, along with the information
|
template, model and controller all work together. Angular uses scopes, along with the information
|
||||||
contained in the template, data model, and controller, to keep the model and view separated but in
|
contained in the template, data model, and controller, to keep the model and view separated but in
|
||||||
|
|
@ -131,23 +102,17 @@ reflected in the model. To learn more about angular scopes, see the {@link api/a
|
||||||
angular scope documentation}.
|
angular scope documentation}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
|
|
||||||
The "Angular way" makes it easy for us to test as we develop; the unit test for your newly created
|
The "Angular way" makes it easy for us to test as we develop; the unit test for your newly created
|
||||||
controller looks as follows:
|
controller looks as follows:
|
||||||
|
|
||||||
|
|
||||||
__`test/unit/controllersSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat controllers', function() {
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('PhoneListCtrl', function() {
|
describe('PhoneListCtrl', function() {
|
||||||
|
|
||||||
|
|
||||||
it('should create "phones" model with 3 phones', function() {
|
it('should create "phones" model with 3 phones', function() {
|
||||||
var ctrl = new PhoneListCtrl();
|
var ctrl = new PhoneListCtrl();
|
||||||
expect(ctrl.phones.length).toBe(3);
|
expect(ctrl.phones.length).toBe(3);
|
||||||
|
|
@ -156,105 +121,76 @@ describe('PhoneCat controllers', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Ease of testing is another cornerstone of angular's design philosophy. All we are doing here is
|
Ease of testing is another cornerstone of angular's design philosophy. All we are doing here is
|
||||||
showing how easy it is to create a unit test. The test verifies that we have 3 records in the
|
showing how easy it is to create a unit test. The test verifies that we have 3 records in the
|
||||||
phones array.
|
phones array.
|
||||||
|
|
||||||
|
|
||||||
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
||||||
writing tests. Although Jasmine is not required by angular, we used it to write all tests in this
|
writing tests. Although Jasmine is not required by angular, we used it to write all tests in this
|
||||||
tutorial. You can learn about Jasmine on the {@link http://pivotal.github.com/jasmine/ Jasmine home
|
tutorial. You can learn about Jasmine on the {@link http://pivotal.github.com/jasmine/ Jasmine home
|
||||||
page} and on the {@link https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
|
page} and on the {@link https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
|
||||||
|
|
||||||
|
|
||||||
The angular-seed project is pre-configured to run all unit tests using {@link
|
The angular-seed project is pre-configured to run all unit tests using {@link
|
||||||
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
|
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
|
||||||
|
|
||||||
|
|
||||||
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
|
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
|
||||||
`./scripts/test-server.sh` to start the test web server.
|
`./scripts/test-server.sh` to start the test web server.
|
||||||
|
|
||||||
|
|
||||||
2. Open a new browser tab or window and navigate to {@link http://localhost:9876}.
|
2. Open a new browser tab or window and navigate to {@link http://localhost:9876}.
|
||||||
|
|
||||||
|
|
||||||
3. Choose "Capture this browser in strict mode".
|
3. Choose "Capture this browser in strict mode".
|
||||||
|
|
||||||
|
|
||||||
At this point, you can leave this tab open and forget about it. JsTestDriver will use it to
|
At this point, you can leave this tab open and forget about it. JsTestDriver will use it to
|
||||||
execute the tests and report the results in the terminal.
|
execute the tests and report the results in the terminal.
|
||||||
|
|
||||||
|
|
||||||
4. Execute the test by running `./scripts/test.sh`
|
4. Execute the test by running `./scripts/test.sh`
|
||||||
|
|
||||||
|
|
||||||
You should see the following or similar output:
|
You should see the following or similar output:
|
||||||
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome: Runner reset.
|
||||||
.
|
.
|
||||||
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
|
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
|
||||||
Chrome 11.0.696.57 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
|
Chrome 11.0.696.57 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
|
||||||
|
|
||||||
|
|
||||||
Yay! The test passed! Or not...
|
Yay! The test passed! Or not...
|
||||||
|
|
||||||
|
|
||||||
Note: If you see errors after you run the test, close the browser tab and go back to the terminal
|
Note: If you see errors after you run the test, close the browser tab and go back to the terminal
|
||||||
and kill the script, then repeat the procedure above.
|
and kill the script, then repeat the procedure above.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Add another binding to `index.html`. For example:
|
* Add another binding to `index.html`. For example:
|
||||||
|
|
||||||
|
|
||||||
<p>Total number of phones: {{phones.length}}</p>
|
<p>Total number of phones: {{phones.length}}</p>
|
||||||
|
|
||||||
|
|
||||||
* Create a new model property in the controller and bind to it from the template. For example:
|
* Create a new model property in the controller and bind to it from the template. For example:
|
||||||
|
|
||||||
|
|
||||||
this.hello = "Hello, World!"
|
this.hello = "Hello, World!"
|
||||||
|
|
||||||
|
|
||||||
Refresh your browser to make sure it says, "Hello, World!"
|
Refresh your browser to make sure it says, "Hello, World!"
|
||||||
|
|
||||||
|
|
||||||
* Create a repeater that constructs a simple table:
|
* Create a repeater that constructs a simple table:
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr><th>row number</th></tr>
|
<tr><th>row number</th></tr>
|
||||||
<tr ng:repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i}}</td></tr>
|
<tr ng:repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i}}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
Now, make the list 1-based by incrementing `i` by one in the binding:
|
Now, make the list 1-based by incrementing `i` by one in the binding:
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr><th>row number</th></tr>
|
<tr><th>row number</th></tr>
|
||||||
<tr ng:repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
<tr ng:repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
|
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
|
||||||
`./scripts/test.sh` script.
|
`./scripts/test.sh` script.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
You now have a dynamic app that features separate model, view, and controller components, and
|
You now have a dynamic app that features separate model, view, and controller components, and
|
||||||
you're testing as you go. Now, let's go to step 3 to learn how to add full text search to the app.
|
you're testing as you go. Now, let's go to step 3 to learn how to add full text search to the app.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="2"></ul>
|
<ul doc:tutorial-nav="2"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,53 +2,38 @@
|
||||||
@name Tutorial: 3 - Filtering Repeaters
|
@name Tutorial: 3 - Filtering Repeaters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="3"></ul>
|
<ul doc:tutorial-nav="3"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
We did a lot of work in laying a foundation for the app in the last step, so now we'll do something
|
We did a lot of work in laying a foundation for the app in the last step, so now we'll do something
|
||||||
simple, and add full text search (yes, it will be simple!). We will also write an end-to-end test,
|
simple, and add full text search (yes, it will be simple!). 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
|
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.
|
quickly detects regressions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="3"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="3"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The app now has a search box. The phone list on the page changes depending on what a user types
|
The app now has a search box. The phone list on the page changes depending on what a user types
|
||||||
into the search box.
|
into the search box.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-2...step-3
|
https://github.com/angular/angular-phonecat/compare/step-2...step-3
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
|
|
||||||
We made no changes to the controller.
|
We made no changes to the controller.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
Fulltext Search: <input name="query"/>
|
Fulltext Search: <input name="query"/>
|
||||||
|
|
||||||
|
|
||||||
<ul class="phones">
|
<ul class="phones">
|
||||||
<li ng:repeat="phone in phones.$filter(query)">
|
<li ng:repeat="phone in phones.$filter(query)">
|
||||||
{{phone.name}}
|
{{phone.name}}
|
||||||
|
|
@ -58,70 +43,54 @@ __`app/index.html`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We added a standard HTML `<input>` tag and use angular's {@link api/angular.Array.filter $filter}
|
We added a standard HTML `<input>` tag and use angular's {@link api/angular.Array.filter $filter}
|
||||||
function to process the input for the `ng:repeater`.
|
function to process the input for the `ng:repeater`.
|
||||||
|
|
||||||
|
|
||||||
This lets a user enter search criteria and immediately see the effects of their search on the phone
|
This lets a user enter search criteria and immediately see the effects of their search on the phone
|
||||||
list. This new code demonstrates the following:
|
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
|
* 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.
|
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
|
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
|
available as a filter input in the list repeater (`phone in phones.$filter(`__`query`__`)`). When
|
||||||
changes to the data model cause the repeater's input to change, the repeater efficiently updates
|
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.
|
the DOM to reflect the current state of the model.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/tutorial_03_final.png">
|
<img src="img/tutorial/tutorial_03_final.png">
|
||||||
|
|
||||||
|
|
||||||
* Use of `$filter`. The {@link api/angular.Array.filter $filter} method, uses the `query` value, to
|
* Use of `$filter`. The {@link api/angular.Array.filter $filter} method, uses the `query` value, to
|
||||||
create a new array that contains only those records that match the `query`.
|
create a new array that contains only those records that match the `query`.
|
||||||
|
|
||||||
|
|
||||||
`ng:repeat` automatically updates the view in response to the changing number of phones returned
|
`ng:repeat` automatically updates the view in response to the changing number of phones returned
|
||||||
by the `$filter`. The process is completely transparent to the developer.
|
by the `$filter`. The process is completely transparent to the developer.
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
In step 2, we learned how to write and run unit tests. Unit tests are perfect for testing
|
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 components 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
|
test DOM manipulation or the wiring of our application. For these, an end-to-end test is a much
|
||||||
better choice.
|
better choice.
|
||||||
|
|
||||||
|
|
||||||
The search feature was fully implemented via templates and data-binding, so we'll write our first
|
The search feature was fully implemented via templates and data-binding, so we'll write our first
|
||||||
end-to-end test, to verify that the feature works.
|
end-to-end test, to verify that the feature works.
|
||||||
|
|
||||||
|
|
||||||
__`test/e2e/scenarios.js`:__
|
__`test/e2e/scenarios.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat App', function() {
|
describe('PhoneCat App', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('Phone list view', function() {
|
describe('Phone list view', function() {
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser().navigateTo('../../app/index.html');
|
browser().navigateTo('../../app/index.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should filter the phone list as user types into the search box', function() {
|
it('should filter the phone list as user types into the search box', function() {
|
||||||
expect(repeater('.phones li').count()).toBe(3);
|
expect(repeater('.phones li').count()).toBe(3);
|
||||||
|
|
||||||
|
|
||||||
input('query').enter('nexus');
|
input('query').enter('nexus');
|
||||||
expect(repeater('.phones li').count()).toBe(1);
|
expect(repeater('.phones li').count()).toBe(1);
|
||||||
|
|
||||||
|
|
||||||
input('query').enter('motorola');
|
input('query').enter('motorola');
|
||||||
expect(repeater('.phones li').count()).toBe(2);
|
expect(repeater('.phones li').count()).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
@ -129,64 +98,48 @@ describe('PhoneCat App', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Even though the syntax of this test looks very much like our controller unit test written with
|
Even though the syntax of this test looks very much like our controller unit test written with
|
||||||
Jasmine, the end-to-end test uses APIs of {@link
|
Jasmine, the end-to-end test uses APIs of {@link
|
||||||
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en&pli=1#
|
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en&pli=1#
|
||||||
angular's end-to-end test runner}.
|
angular's end-to-end test runner}.
|
||||||
|
|
||||||
|
|
||||||
To run the end-to-end test, open the following in a new browser tab:
|
To run the end-to-end test, open the following in a new browser tab:
|
||||||
|
|
||||||
|
|
||||||
* node.js users: {@link http://localhost:8000/test/e2e/runner.html}
|
* node.js users: {@link http://localhost:8000/test/e2e/runner.html}
|
||||||
* users with other http servers:
|
* users with other http servers:
|
||||||
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
|
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
|
||||||
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
|
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
|
||||||
|
|
||||||
|
|
||||||
This test verifies that the search box and the repeater are correctly wired together. Notice how
|
This test verifies that the search box and the repeater are correctly wired together. Notice how
|
||||||
easy it is to write end-to-end tests in angular. Although this example is for a simple test, it
|
easy it is to write end-to-end tests in angular. Although this example is for a simple test, it
|
||||||
really is that easy to set up any functional, readable, end-to-end test.
|
really is that easy to set up any functional, readable, end-to-end test.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Display the current value of the `query` model by adding a `{{query}}` binding into the
|
* 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.
|
`index.html` template, and see how it changes when you type in the input box.
|
||||||
|
|
||||||
|
|
||||||
* Let's see how we can get the current value of the `query` model to appear in the HTML page title.
|
* Let's see how we can get the current value of the `query` model to appear in the HTML page title.
|
||||||
|
|
||||||
|
|
||||||
You might think you could just add the {{query}} to the title tag element as follows:
|
You might think you could just add the {{query}} to the title tag element as follows:
|
||||||
|
|
||||||
|
|
||||||
<title>Google Phone Gallery: {{query}}</title>
|
<title>Google Phone Gallery: {{query}}</title>
|
||||||
|
|
||||||
|
|
||||||
However, when you reload the page, you won't see the expected result. This is because the "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 body element:
|
model lives in the scope defined by the body element:
|
||||||
|
|
||||||
|
|
||||||
<body ng:controller="PhoneListCtrl">
|
<body ng:controller="PhoneListCtrl">
|
||||||
|
|
||||||
|
|
||||||
If you want to bind to the query model from the `<title>` element, you must __move__ the
|
If you want to bind to the query model from the `<title>` element, you must __move__ the
|
||||||
`ng:controller` declaration to the HTML element because it is the common parent of both the body
|
`ng:controller` declaration to the HTML element because it is the common parent of both the body
|
||||||
and title elements:
|
and title elements:
|
||||||
|
|
||||||
|
|
||||||
<html ng:controller="PhoneListCtrl">
|
<html ng:controller="PhoneListCtrl">
|
||||||
|
|
||||||
|
|
||||||
Be sure to *remove* the `ng:controller` declaration from the body element.
|
Be sure to *remove* the `ng:controller` declaration from the body element.
|
||||||
|
|
||||||
|
|
||||||
* Add the following end-to-end test into the `describe` block within `test/e2e/scenarios.js`:
|
* Add the following end-to-end test into the `describe` block within `test/e2e/scenarios.js`:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
it('should display the current filter value within an element with id "status"',
|
it('should display the current filter value within an element with id "status"',
|
||||||
function() {
|
function() {
|
||||||
|
|
@ -201,30 +154,21 @@ and title elements:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Refresh the browser tab with end-to-end test runner to see the test fail. Now add a `div` or `p`
|
Refresh the browser tab with end-to-end test runner to see the test fail. Now add a `div` or `p`
|
||||||
element with `id` `"status"` and content with the `query` binding into the `index.html` template to
|
element with `id` `"status"` and content with the `query` binding into the `index.html` template to
|
||||||
make the test pass.
|
make the test pass.
|
||||||
|
|
||||||
|
|
||||||
* Add a `pause()` statement into an end-to-end test and rerun it. You'll see the runner pausing,
|
* Add a `pause()` statement into an end-to-end test and rerun it. You'll see the runner pausing,
|
||||||
giving you the opportunity to explore the state of your application displayed in the browser. The
|
giving you the opportunity to explore the state of your application displayed in the browser. The
|
||||||
app is live! Change the search query to prove it. This is great for troubleshooting end-to-end
|
app is live! Change the search query to prove it. This is great for troubleshooting end-to-end
|
||||||
tests.
|
tests.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
With full text search under our belt and a test to verify it, let's go to step 4 to learn how to
|
With full text search under our belt and a test to verify it, let's go to step 4 to learn how to
|
||||||
add sorting capability to the phone app.
|
add sorting capability to the phone app.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="3"></ul>
|
<ul doc:tutorial-nav="3"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,38 +2,27 @@
|
||||||
@name Tutorial: 4 - Two-way Data Binding
|
@name Tutorial: 4 - Two-way Data Binding
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="4"></ul>
|
<ul doc:tutorial-nav="4"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In this step, you will add a feature to let your users control the order of the items in the phone
|
In this step, you will add a feature to let your users control the order of the items in the phone
|
||||||
list. The dynamic ordering is implemented by creating a new model property, wiring it together with
|
list. The dynamic ordering is implemented by creating a new model property, wiring it together with
|
||||||
the repeater, and letting the data binding magic do the rest of the work.
|
the repeater, and letting the data binding magic do the rest of the work.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="4"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="4"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You should see that in addition to the search box, the app displays a drop down menu that allows
|
You should see that in addition to the search box, the app displays a drop down menu that allows
|
||||||
users to control the order in which the phones are listed.
|
users to control the order in which the phones are listed.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-3...step-4
|
https://github.com/angular/angular-phonecat/compare/step-3...step-4
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -50,7 +39,6 @@ __`app/index.html`:__
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<ul class="phones">
|
<ul class="phones">
|
||||||
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
|
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
|
||||||
{{phone.name}}
|
{{phone.name}}
|
||||||
|
|
@ -60,26 +48,20 @@ __`app/index.html`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
In the `index.html` template we made the following changes:
|
In the `index.html` template we made the following changes:
|
||||||
|
|
||||||
|
|
||||||
* First, we added a `<select>` html element named `orderProp`, so that our users can pick from the
|
* First, we added a `<select>` html element named `orderProp`, so that our users can pick from the
|
||||||
two provided sorting options.
|
two provided sorting options.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/tutorial_04-06_final.png">
|
<img src="img/tutorial/tutorial_04-06_final.png">
|
||||||
|
|
||||||
|
|
||||||
* We then chained the `$filter` method with {@link api/angular.Array.orderBy `$orderBy`} method to
|
* We then chained the `$filter` method with {@link api/angular.Array.orderBy `$orderBy`} method to
|
||||||
further process the input into the repeater. `$orderBy` is a utility method similar to {@link
|
further process the input into the repeater. `$orderBy` is a utility method similar to {@link
|
||||||
api/angular.Array.filter `$filter`}, but instead of filtering an array, it reorders it.
|
api/angular.Array.filter `$filter`}, but instead of filtering an array, it reorders it.
|
||||||
|
|
||||||
|
|
||||||
Angular creates a two way data-binding between the select element and the `orderProp` model.
|
Angular creates a two way data-binding between the select element and the `orderProp` model.
|
||||||
`orderProp` is then used as the input for the `$orderBy` method.
|
`orderProp` is then used as the input for the `$orderBy` method.
|
||||||
|
|
||||||
|
|
||||||
As we discussed in the section about data-binding and the repeater in step 3, whenever the model
|
As we discussed in the section about data-binding and the repeater in step 3, whenever the model
|
||||||
changes (for example because a user changes the order with the select drop down menu), angular's
|
changes (for example because a user changes the order with the select drop down menu), angular's
|
||||||
data-binding will cause the view to automatically update. No bloated DOM manipulation code is
|
data-binding will cause the view to automatically update. No bloated DOM manipulation code is
|
||||||
|
|
@ -87,17 +69,12 @@ necessary!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controller.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
/* App Controllers */
|
/* App Controllers */
|
||||||
|
|
||||||
|
|
||||||
function PhoneListCtrl() {
|
function PhoneListCtrl() {
|
||||||
this.phones = [{"name": "Nexus S",
|
this.phones = [{"name": "Nexus S",
|
||||||
"snippet": "Fast just got faster with Nexus S.",
|
"snippet": "Fast just got faster with Nexus S.",
|
||||||
|
|
@ -109,21 +86,17 @@ function PhoneListCtrl() {
|
||||||
"snippet": "The Next, Next Generation tablet.",
|
"snippet": "The Next, Next Generation tablet.",
|
||||||
"age": 2}];
|
"age": 2}];
|
||||||
|
|
||||||
|
|
||||||
this.orderProp = 'age';
|
this.orderProp = 'age';
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
* We modified the `phones` model - the array of phones - and added an `age` property to each phone
|
* We modified the `phones` model - the array of phones - and added an `age` property to each phone
|
||||||
record. This property is used to order phones by age.
|
record. This property is used to order phones by age.
|
||||||
|
|
||||||
|
|
||||||
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
|
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
|
||||||
not set the default value here, angular would have used the value of the first `<option>` element
|
not set the default value here, angular would have used the value of the first `<option>` element
|
||||||
(`'name'`) when it initialized the data model.
|
(`'name'`) when it initialized the data model.
|
||||||
|
|
||||||
|
|
||||||
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
||||||
browser, "Newest" is selected in the drop down menu. This is because we set `orderProp` to `'age'`
|
browser, "Newest" is selected in the drop down menu. This is because we set `orderProp` to `'age'`
|
||||||
in the controller. So the binding works in the direction from our model to the UI. Now if you
|
in the controller. So the binding works in the direction from our model to the UI. Now if you
|
||||||
|
|
@ -133,39 +106,28 @@ to the model.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
||||||
the unit test first.
|
the unit test first.
|
||||||
|
|
||||||
|
|
||||||
__`test/unit/controllerSpec.js`:__
|
__`test/unit/controllerSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat controllers', function() {
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('PhoneListCtrl', function(){
|
describe('PhoneListCtrl', function(){
|
||||||
var scope, $browser, ctrl;
|
var scope, $browser, ctrl;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
ctrl = new PhoneListCtrl();
|
ctrl = new PhoneListCtrl();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should create "phones" model with 3 phones', function() {
|
it('should create "phones" model with 3 phones', function() {
|
||||||
expect(ctrl.phones.length).toBe(3);
|
expect(ctrl.phones.length).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should set the default value of orderProp model', function() {
|
it('should set the default value of orderProp model', function() {
|
||||||
expect(ctrl.orderProp).toBe('age');
|
expect(ctrl.orderProp).toBe('age');
|
||||||
});
|
});
|
||||||
|
|
@ -174,49 +136,37 @@ describe('PhoneCat controllers', function() {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The unit test now verifies that the default ordering property is set.
|
The unit test now verifies that the default ordering property is set.
|
||||||
|
|
||||||
|
|
||||||
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
|
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
|
||||||
shared by all tests in the parent `describe` block.
|
shared by all tests in the parent `describe` block.
|
||||||
|
|
||||||
|
|
||||||
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
|
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
|
||||||
following output.
|
following output.
|
||||||
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome: Runner reset.
|
||||||
..
|
..
|
||||||
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
|
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
|
||||||
Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
|
Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Let's turn our attention to the end-to-end test.
|
Let's turn our attention to the end-to-end test.
|
||||||
|
|
||||||
|
|
||||||
__`test/e2e/scenarios.js`:__
|
__`test/e2e/scenarios.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
it('should be possible to control phone order via the drop down select box',
|
it('should be possible to control phone order via the drop down select box',
|
||||||
function() {
|
function() {
|
||||||
|
|
||||||
|
|
||||||
// narrow the dataset to make the test assertions shorter
|
// narrow the dataset to make the test assertions shorter
|
||||||
input('query').enter('tablet');
|
input('query').enter('tablet');
|
||||||
|
|
||||||
|
|
||||||
expect(repeater('.phones li', 'Phone List').column('a')).
|
expect(repeater('.phones li', 'Phone List').column('a')).
|
||||||
toEqual(["Motorola XOOM\u2122 with Wi-Fi",
|
toEqual(["Motorola XOOM\u2122 with Wi-Fi",
|
||||||
"MOTOROLA XOOM\u2122"]);
|
"MOTOROLA XOOM\u2122"]);
|
||||||
|
|
||||||
|
|
||||||
select('orderProp').option('alphabetical');
|
select('orderProp').option('alphabetical');
|
||||||
|
|
||||||
|
|
||||||
expect(repeater('.phones li', 'Phone List').column('a')).
|
expect(repeater('.phones li', 'Phone List').column('a')).
|
||||||
toEqual(["MOTOROLA XOOM\u2122",
|
toEqual(["MOTOROLA XOOM\u2122",
|
||||||
"Motorola XOOM\u2122 with Wi-Fi"]);
|
"Motorola XOOM\u2122 with Wi-Fi"]);
|
||||||
|
|
@ -224,36 +174,26 @@ __`test/e2e/scenarios.js`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
|
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
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
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
|
||||||
angular's server}.
|
angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* In the `PhoneListCtrl` controller, remove the statement that sets the `orderProp` value and
|
* In the `PhoneListCtrl` controller, remove the statement that sets the `orderProp` value and
|
||||||
you'll see that the ordering as well as the current selection in the dropdown menu will default to
|
you'll see that the ordering as well as the current selection in the dropdown menu will default to
|
||||||
"Alphabetical".
|
"Alphabetical".
|
||||||
|
|
||||||
|
|
||||||
* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
|
* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
|
||||||
text.
|
text.
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
Now that you have added list sorting and tested the app, go to step 5 to learn about angular
|
Now that you have added list sorting and tested the app, go to step 5 to learn about angular
|
||||||
services and how angular uses dependency injection.
|
services and how angular uses dependency injection.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="4"></ul>
|
<ul doc:tutorial-nav="4"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,40 +2,29 @@
|
||||||
@name Tutorial: 5 - XHRs & Dependency Injection
|
@name Tutorial: 5 - XHRs & Dependency Injection
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="5"></ul>
|
<ul doc:tutorial-nav="5"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
|
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
|
||||||
from our server using one of angular's built-in {@link api/angular.service services} called {@link
|
from our server using one of angular's built-in {@link api/angular.service services} called {@link
|
||||||
api/angular.service.$xhr $xhr}. We will use angular's {@link guide/dev_guide.di dependency
|
api/angular.service.$xhr $xhr}. We will use angular's {@link guide/dev_guide.di dependency
|
||||||
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
|
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="5"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="5"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You should now see a list of 20 phones.
|
You should now see a list of 20 phones.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-4...step-5
|
https://github.com/angular/angular-phonecat/compare/step-4...step-5
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
|
|
||||||
|
|
||||||
The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones
|
The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones
|
||||||
stored in the JSON format.
|
stored in the JSON format.
|
||||||
|
|
||||||
|
|
||||||
Following is a sample of the file:
|
Following is a sample of the file:
|
||||||
<pre>
|
<pre>
|
||||||
[
|
[
|
||||||
|
|
@ -51,125 +40,96 @@ Following is a sample of the file:
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
|
|
||||||
We'll use angular's {@link api/angular.service.$xhr $xhr} service in our controller to make an HTTP
|
We'll use angular's {@link api/angular.service.$xhr $xhr} service in our controller to make an HTTP
|
||||||
request to your web server to fetch the data in the `app/phones/phones.json` file. `$xhr` is just
|
request to your web server to fetch the data in the `app/phones/phones.json` file. `$xhr` is just
|
||||||
one of several built-in {@link api/angular.service angular services} that handle common operations
|
one of several built-in {@link api/angular.service angular services} that handle common operations
|
||||||
in web apps. Angular injects these services for you where you need them.
|
in web apps. Angular injects these services for you where you need them.
|
||||||
|
|
||||||
|
|
||||||
Services are managed by angular's {@link guide/dev_guide.di DI subsystem}. Dependency injection
|
Services are managed by angular's {@link guide/dev_guide.di DI subsystem}. Dependency injection
|
||||||
helps to make your web apps both well-structured (e.g., separate components for presentation, data,
|
helps to make your web apps both well-structured (e.g., separate components for presentation, data,
|
||||||
and control) and loosely coupled (dependencies between components are not resolved by the
|
and control) and loosely coupled (dependencies between components are not resolved by the
|
||||||
components themselves, but by the DI subsystem).
|
components themselves, but by the DI subsystem).
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controllers.js:`__
|
__`app/js/controllers.js:`__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneListCtrl($xhr) {
|
function PhoneListCtrl($xhr) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
$xhr('GET', 'phones/phones.json', function(code, response) {
|
$xhr('GET', 'phones/phones.json', function(code, response) {
|
||||||
self.phones = response;
|
self.phones = response;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
self.orderProp = 'age';
|
self.orderProp = 'age';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//PhoneListCtrl.$inject = ['$xhr'];
|
//PhoneListCtrl.$inject = ['$xhr'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
`$xhr` makes an HTTP GET request to our web server, asking for `phone/phones.json` (the url is
|
`$xhr` makes an HTTP GET request to our web server, asking for `phone/phones.json` (the url is
|
||||||
relative to our `index.html` file). The server responds by providing the data in the json file.
|
relative to our `index.html` file). The server responds by providing the data in the json file.
|
||||||
(The response might just as well have been dynamically generated by a backend server. To the
|
(The response might just as well have been dynamically generated by a backend server. To the
|
||||||
browser and our app they both look the same. For the sake of simplicity we used a json file in this
|
browser and our app they both look the same. For the sake of simplicity we used a json file in this
|
||||||
tutorial.)
|
tutorial.)
|
||||||
|
|
||||||
|
|
||||||
The `$xhr` service takes a callback as the last argument. This callback is used to process the
|
The `$xhr` service takes a callback as the last argument. This callback is used to process the
|
||||||
response. We assign the response to the scope controlled by the controller, as a model called
|
response. We assign the response to the scope controlled by the controller, as a model called
|
||||||
`phones`. Notice that angular detected the json response and parsed it for us!
|
`phones`. Notice that angular detected the json response and parsed it for us!
|
||||||
|
|
||||||
|
|
||||||
To use a service in angular, you simply declare the names of the services you need as arguments to
|
To use a service in angular, you simply declare the names of the services you need as arguments to
|
||||||
the controller's constructor function, as follows:
|
the controller's constructor function, as follows:
|
||||||
|
|
||||||
|
|
||||||
function PhoneListCtrl($xhr) {...}
|
function PhoneListCtrl($xhr) {...}
|
||||||
|
|
||||||
|
|
||||||
Angular's dependency injector provides services to your controller when the controller is being
|
Angular's dependency injector provides services to your controller when the controller is being
|
||||||
constructed. The dependency injector also takes care of creating any transitive dependencies the
|
constructed. The dependency injector also takes care of creating any transitive dependencies the
|
||||||
service may have (services often depend upon other services).
|
service may have (services often depend upon other services).
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/xhr_service_final.png">
|
<img src="img/tutorial/xhr_service_final.png">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### '$' Prefix Naming Convention
|
### '$' Prefix Naming Convention
|
||||||
|
|
||||||
|
|
||||||
You can create your own services, and in fact we will do exactly that in step 11. As a naming
|
You can create your own services, and in fact we will do exactly that in step 11. As a naming
|
||||||
convention, angular's built-in services, Scope methods and a few other angular APIs have a '$'
|
convention, angular's built-in services, Scope methods and a few other angular APIs have a '$'
|
||||||
prefix in front of the name. Don't use a '$' prefix when naming your services and models, in order
|
prefix in front of the name. Don't use a '$' prefix when naming your services and models, in order
|
||||||
to avoid any possible naming collisions.
|
to avoid any possible naming collisions.
|
||||||
|
|
||||||
|
|
||||||
### A Note on Minification
|
### A Note on Minification
|
||||||
|
|
||||||
|
|
||||||
Since angular infers the controller's dependencies from the names of arguments to the controller's
|
Since angular infers the controller's dependencies from the names of arguments to the controller's
|
||||||
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
|
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
|
||||||
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
||||||
minified as well, and the dependency injector would not being able to identify services correctly.
|
minified as well, and the dependency injector would not being able to identify services correctly.
|
||||||
|
|
||||||
|
|
||||||
To overcome issues caused by minification, just assign an array with service identifier strings
|
To overcome issues caused by minification, just assign an array with service identifier strings
|
||||||
into the `$inject` property of the controller function, just like the last line in the snippet
|
into the `$inject` property of the controller function, just like the last line in the snippet
|
||||||
(commented out) suggests:
|
(commented out) suggests:
|
||||||
|
|
||||||
|
|
||||||
PhoneListCtrl.$inject = ['$xhr'];
|
PhoneListCtrl.$inject = ['$xhr'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
__`test/unit/controllersSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
|
|
||||||
|
|
||||||
Because we started using dependency injection and our controller has dependencies, constructing the
|
Because we started using dependency injection and our controller has dependencies, constructing the
|
||||||
controller in our tests is a bit more complicated. We could use the `new` operator and provide the
|
controller in our tests is a bit more complicated. We could use the `new` operator and provide the
|
||||||
constructor with some kind of fake `$xhr` implementation. However, the recommended (and easier) way
|
constructor with some kind of fake `$xhr` implementation. However, the recommended (and easier) way
|
||||||
is to create a controller in the test environment in the same way that angular does it in the
|
is to create a controller in the test environment in the same way that angular does it in the
|
||||||
production code behind the scenes, as follows:
|
production code behind the scenes, as follows:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat controllers', function() {
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('PhoneListCtrl', function() {
|
describe('PhoneListCtrl', function() {
|
||||||
var scope, $browser, ctrl;
|
var scope, $browser, ctrl;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
scope = angular.scope();
|
scope = angular.scope();
|
||||||
$browser = scope.$service('$browser');
|
$browser = scope.$service('$browser');
|
||||||
|
|
||||||
|
|
||||||
$browser.xhr.expectGET('phones/phones.json')
|
$browser.xhr.expectGET('phones/phones.json')
|
||||||
.respond([{name: 'Nexus S'},
|
.respond([{name: 'Nexus S'},
|
||||||
{name: 'Motorola DROID'}]);
|
{name: 'Motorola DROID'}]);
|
||||||
|
|
@ -178,59 +138,46 @@ describe('PhoneCat controllers', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We created the controller in the test environment, as follows:
|
We created the controller in the test environment, as follows:
|
||||||
|
|
||||||
|
|
||||||
* We created a root scope object by calling `angular.scope()`
|
* We created a root scope object by calling `angular.scope()`
|
||||||
|
|
||||||
|
|
||||||
* We called `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with
|
* We called `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with
|
||||||
the `PhoneListCtrl` controller
|
the `PhoneListCtrl` controller
|
||||||
|
|
||||||
|
|
||||||
Because our code now uses the `$xhr` service to fetch the phone list data in our controller, before
|
Because our code now uses the `$xhr` service to fetch the phone list data in our controller, before
|
||||||
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
||||||
incoming request from the controller. To do this we:
|
incoming request from the controller. To do this we:
|
||||||
|
|
||||||
|
|
||||||
* Use the {@link api/angular.scope.$service `$service`} method to retrieve the `$browser` service,
|
* Use the {@link api/angular.scope.$service `$service`} method to retrieve the `$browser` service,
|
||||||
a service that angular uses to represent various browser APIs. In tests, angular automatically uses
|
a service that angular uses to represent various browser APIs. In tests, angular automatically uses
|
||||||
a mock version of this service that allows you to write tests without having to deal with these
|
a mock version of this service that allows you to write tests without having to deal with these
|
||||||
native APIs and the global state associated with them.
|
native APIs and the global state associated with them.
|
||||||
|
|
||||||
|
|
||||||
* Use the `$browser.xhr.expectGET` method to train the `$browser` object to expect an incoming HTTP
|
* Use the `$browser.xhr.expectGET` method to train the `$browser` object to expect an incoming HTTP
|
||||||
request and tell it what to respond with. Note that the responses are not returned before we call
|
request and tell it what to respond with. Note that the responses are not returned before we call
|
||||||
the `$browser.xhr.flush` method.
|
the `$browser.xhr.flush` method.
|
||||||
|
|
||||||
|
|
||||||
Now, we will make assertions to verify that the `phones` model doesn't exist on the scope, before
|
Now, we will make assertions to verify that the `phones` model doesn't exist on the scope, before
|
||||||
the response is received:
|
the response is received:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
it('should create "phones" model with 2 phones fetched from xhr', function() {
|
it('should create "phones" model with 2 phones fetched from xhr', function() {
|
||||||
expect(ctrl.phones).toBeUndefined();
|
expect(ctrl.phones).toBeUndefined();
|
||||||
$browser.xhr.flush();
|
$browser.xhr.flush();
|
||||||
|
|
||||||
|
|
||||||
expect(ctrl.phones).toEqual([{name: 'Nexus S'},
|
expect(ctrl.phones).toEqual([{name: 'Nexus S'},
|
||||||
{name: 'Motorola DROID'}]);
|
{name: 'Motorola DROID'}]);
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
* We flush the xhr queue in the browser by calling `$browser.xhr.flush()`. This causes the callback
|
* We flush the xhr queue in the browser by calling `$browser.xhr.flush()`. This causes the callback
|
||||||
we passed into the `$xhr` service to be executed with the trained response.
|
we passed into the `$xhr` service to be executed with the trained response.
|
||||||
|
|
||||||
|
|
||||||
* We make the assertions, verifying that the phone model now exists on the scope.
|
* We make the assertions, verifying that the phone model now exists on the scope.
|
||||||
|
|
||||||
|
|
||||||
Finally, we verify that the default value of `orderProp` is set correctly:
|
Finally, we verify that the default value of `orderProp` is set correctly:
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
it('should set the default value of orderProp model', function() {
|
it('should set the default value of orderProp model', function() {
|
||||||
expect(ctrl.orderProp).toBe('age');
|
expect(ctrl.orderProp).toBe('age');
|
||||||
|
|
@ -239,44 +186,31 @@ Finally, we verify that the default value of `orderProp` is set correctly:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||||
output.
|
output.
|
||||||
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome: Runner reset.
|
||||||
..
|
..
|
||||||
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
|
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
|
||||||
Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
|
Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* At the bottom of `index.html`, add a `{{phones}}` binding to see the list of phones displayed in
|
* At the bottom of `index.html`, add a `{{phones}}` binding to see the list of phones displayed in
|
||||||
json format.
|
json format.
|
||||||
|
|
||||||
|
|
||||||
* In the `PhoneListCtrl` controller, pre-process the xhr response by limiting the number of phones
|
* In the `PhoneListCtrl` controller, pre-process the xhr response by limiting the number of phones
|
||||||
to the first 5 in the list. Use the following code in the xhr callback:
|
to the first 5 in the list. Use the following code in the xhr callback:
|
||||||
|
|
||||||
|
|
||||||
self.phones = response.splice(0, 5);
|
self.phones = response.splice(0, 5);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
Now that you have learned how easy it is to use angular services (thanks to angular's
|
Now that you have learned how easy it is to use angular services (thanks to angular's
|
||||||
implementation of dependency injection), go to step 6, where you will add some thumbnail images of
|
implementation of dependency injection), go to step 6, where you will add some thumbnail images of
|
||||||
phones and some links.
|
phones and some links.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="5"></ul>
|
<ul doc:tutorial-nav="5"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,29 @@
|
||||||
@name Tutorial: 6 - Templating Links & Images
|
@name Tutorial: 6 - Templating Links & Images
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="6"></ul>
|
<ul doc:tutorial-nav="6"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In this step, you will add thumbnail images for the phones in the phone list, and links that, for
|
In this step, you will add thumbnail images for the phones in the phone list, and links that, for
|
||||||
now, will go nowhere. In subsequent steps you will use the links to display additional information
|
now, will go nowhere. In subsequent steps you will use the links to display additional information
|
||||||
about the phones in the catalog.
|
about the phones in the catalog.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="6"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="6"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You should now see links and images of the phones in the list.
|
You should now see links and images of the phones in the list.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-5...step-6
|
https://github.com/angular/angular-phonecat/compare/step-5...step-6
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
|
|
||||||
|
|
||||||
Note that the `phones.json` file contains unique ids and image urls for each of the phones. The
|
Note that the `phones.json` file contains unique ids and image urls for each of the phones. The
|
||||||
urls point to the `app/img/phones/` directory.
|
urls point to the `app/img/phones/` directory.
|
||||||
|
|
||||||
|
|
||||||
__`app/phones/phones.json`__ (sample snippet):
|
__`app/phones/phones.json`__ (sample snippet):
|
||||||
<pre>
|
<pre>
|
||||||
[
|
[
|
||||||
|
|
@ -52,11 +40,8 @@ __`app/phones/phones.json`__ (sample snippet):
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -70,13 +55,11 @@ __`app/index.html`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
To dynamically generate links that will in the future lead to phone detail pages, we used the
|
To dynamically generate links that will in the future lead to phone detail pages, we used the
|
||||||
now-familiar {@link guide/dev_guide.compiler.markup double-curly brace markup} in the `href`
|
now-familiar {@link guide/dev_guide.compiler.markup double-curly brace markup} in the `href`
|
||||||
attribute values. In step 2, we added the `{{phone.name}}` binding as the element content. In this
|
attribute values. In step 2, we added the `{{phone.name}}` binding as the element content. In this
|
||||||
step the '{{phone.id}}' binding is used in the element attribute.
|
step the '{{phone.id}}' binding is used in the element attribute.
|
||||||
|
|
||||||
|
|
||||||
We also added phone images next to each record using an image tag with the {@link
|
We also added phone images next to each record using an image tag with the {@link
|
||||||
api/angular.directive.ng:src ng:src} directive. That directive prevents the browser from treating
|
api/angular.directive.ng:src ng:src} directive. That directive prevents the browser from treating
|
||||||
the angular `{{ exppression }}` markup literally, which it would have done if we had only specified
|
the angular `{{ exppression }}` markup literally, which it would have done if we had only specified
|
||||||
|
|
@ -84,11 +67,8 @@ an attribute binding in a regular `src` attribute (`<img src="{{phone.imageUrl}}
|
||||||
`ng:src` prevents the browser from making an http request to an invalid location.
|
`ng:src` prevents the browser from making an http request to an invalid location.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
__`test/e2e/scenarios.js`__:
|
__`test/e2e/scenarios.js`__:
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -100,36 +80,26 @@ __`test/e2e/scenarios.js`__:
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We added a new end-to-end test to verify that the app is generating correct links to the phone
|
We added a new end-to-end test to verify that the app is generating correct links to the phone
|
||||||
views that we will implement in the upcoming steps.
|
views that we will implement in the upcoming steps.
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
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
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
|
||||||
angular's server}.
|
angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Replace the `ng:src` directive with a plain old `<src>` attribute. Using tools such as Firebug,
|
* Replace the `ng:src` directive with a plain old `<src>` attribute. Using tools such as Firebug,
|
||||||
or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that the app is indeed
|
or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that the app is indeed
|
||||||
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
|
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
|
||||||
`/app/index.html/{{phone.imageUrl}}`).
|
`/app/index.html/{{phone.imageUrl}}`).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
Now that you have added phone images and links, go to step 7 to learn about angular layout
|
Now that you have added phone images and links, go to step 7 to learn about angular layout
|
||||||
templates and how angular makes it easy to create applications that have multiple views.
|
templates and how angular makes it easy to create applications that have multiple views.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="6"></ul>
|
<ul doc:tutorial-nav="6"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,52 +2,38 @@
|
||||||
@name Tutorial: 7 - Routing & Multiple Views
|
@name Tutorial: 7 - Routing & Multiple Views
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="7"></ul>
|
<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
|
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.
|
multiple views by adding routing.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="7"></doc:tutorial-instructions>
|
<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
|
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.
|
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
|
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
|
https://github.com/angular/angular-phonecat/compare/step-6...step-7
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Multiple Views, Routing and Layout Template
|
## Multiple Views, Routing and Layout Template
|
||||||
|
|
||||||
|
|
||||||
Our app is slowly growing and becoming more complex. Before step 7, the app provided our users with
|
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
|
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
|
`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.
|
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
|
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`
|
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
|
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
|
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.
|
the current "route" — the view that is currently displayed to the user.
|
||||||
|
|
||||||
|
|
||||||
Application routes in angular are declared via the {@link api/angular.service.$route $route}
|
Application routes in angular are declared via the {@link api/angular.service.$route $route}
|
||||||
service. This service makes it easy to wire together controllers, view templates, and the current
|
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
|
URL location in the browser. Using this feature we can implement {@link
|
||||||
|
|
@ -55,106 +41,83 @@ http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize t
|
||||||
history (back and forward navigation) and bookmarks.
|
history (back and forward navigation) and bookmarks.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controllers
|
## Controllers
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controller.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneCatCtrl($route) {
|
function PhoneCatCtrl($route) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
$route.when('/phones',
|
$route.when('/phones',
|
||||||
{template: 'partials/phone-list.html', controller: PhoneListCtrl});
|
{template: 'partials/phone-list.html', controller: PhoneListCtrl});
|
||||||
$route.when('/phones/:phoneId',
|
$route.when('/phones/:phoneId',
|
||||||
{template: 'partials/phone-detail.html', controller: PhoneDetailCtrl});
|
{template: 'partials/phone-detail.html', controller: PhoneDetailCtrl});
|
||||||
$route.otherwise({redirectTo: '/phones'});
|
$route.otherwise({redirectTo: '/phones'});
|
||||||
|
|
||||||
|
|
||||||
$route.onChange(function() {
|
$route.onChange(function() {
|
||||||
self.params = $route.current.params;
|
self.params = $route.current.params;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$route.parent(this);
|
$route.parent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//PhoneCatCtrl.$inject = ['$route'];
|
//PhoneCatCtrl.$inject = ['$route'];
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We created a new controller called `PhoneCatCtrl`. We declared its dependency on the `$route`
|
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:
|
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 `/phone`. To construct this view,
|
* The phone list view will be shown when the URL hash fragment is `/phone`. To construct this view,
|
||||||
angular will use the `phone-list.html` template and the `PhoneListCtrl` controller.
|
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
|
* 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
|
`: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.
|
`phone-detail.html` template and the `PhoneDetailCtrl` controller.
|
||||||
|
|
||||||
|
|
||||||
We reused the `PhoneListCtrl` controller that we constructed in previous steps and we added a new,
|
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.
|
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 statement `$route.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when
|
||||||
the browser address doesn't match either of our routes.
|
the browser address doesn't match either of our routes.
|
||||||
|
|
||||||
|
|
||||||
Thanks to the `$route.parent(this);` statement and `ng:controller="PhoneCatCtrl"` declaration in
|
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
|
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
|
"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
|
`PhoneDetailCtrl`). The sub-controllers inherit the model properties and behavior from the root
|
||||||
controller.
|
controller.
|
||||||
|
|
||||||
|
|
||||||
Note the use of the `:phoneId` parameter in the second route declaration. The `$route` service uses
|
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
|
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.
|
URL. All variables defined with the `:` notation are extracted into the `$route.current.params` map.
|
||||||
|
|
||||||
|
|
||||||
The `params` alias created in the {@link api/angular.service.$route `$route.onChange`} callback
|
The `params` alias created in the {@link api/angular.service.$route `$route.onChange`} callback
|
||||||
allows us to use the `phoneId` property of this map in the `phone-details.html` template.
|
allows us to use the `phoneId` property of this map in the `phone-details.html` template.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
The `$route` service is usually used in conjunction with the {@link api/angular.widget.ng:view
|
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
|
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.
|
route into the layout template, which makes it a perfect fit for our `index.html` template.
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
<body ng:controller="PhoneCatCtrl">
|
<body ng:controller="PhoneCatCtrl">
|
||||||
|
|
||||||
|
|
||||||
<ng:view></ng:view>
|
<ng:view></ng:view>
|
||||||
|
|
||||||
|
|
||||||
<script src="lib/angular/angular.js" ng:autobind></script>
|
<script src="lib/angular/angular.js" ng:autobind></script>
|
||||||
<script src="js/controllers.js"></script>
|
<script src="js/controllers.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Note that we removed most of the code in the `index.html` template and replaced it with a single
|
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`
|
line containing the `ng:view` tag. The code that we removed was placed into the `phone-list.html`
|
||||||
template:
|
template:
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-list.html`:__
|
__`app/partials/phone-list.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<ul class="predicates">
|
<ul class="predicates">
|
||||||
|
|
@ -170,7 +133,6 @@ __`app/partials/phone-list.html`:__
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<ul class="phones">
|
<ul class="phones">
|
||||||
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
|
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
|
||||||
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
|
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
|
||||||
|
|
@ -180,31 +142,23 @@ __`app/partials/phone-list.html`:__
|
||||||
</ul>
|
</ul>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/tutorial_07_final.png">
|
<img src="img/tutorial/tutorial_07_final.png">
|
||||||
|
|
||||||
|
|
||||||
We also added a placeholder template for the phone details view:
|
We also added a placeholder template for the phone details view:
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-list.html`:__
|
__`app/partials/phone-list.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
TBD: detail view for {{params.phoneId}}
|
TBD: detail view for {{params.phoneId}}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Note how we are using `params` model defined in the `PhoneCanCtrl` controller.
|
Note how we are using `params` model defined in the `PhoneCanCtrl` controller.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
To automatically verify that everything is wired properly, we wrote end-to-end tests that navigate
|
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.
|
to various URLs and verify that the correct view was rendered.
|
||||||
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
it('should redirect index.html to index.html#/phones', function() {
|
it('should redirect index.html to index.html#/phones', function() {
|
||||||
|
|
@ -213,17 +167,13 @@ to various URLs and verify that the correct view was rendered.
|
||||||
});
|
});
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
describe('Phone detail view', function() {
|
describe('Phone detail view', function() {
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should display placeholder page with phoneId', function() {
|
it('should display placeholder page with phoneId', function() {
|
||||||
expect(binding('params.phoneId')).toBe('nexus-s');
|
expect(binding('params.phoneId')).toBe('nexus-s');
|
||||||
});
|
});
|
||||||
|
|
@ -231,40 +181,29 @@ to various URLs and verify that the correct view was rendered.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
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
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
|
||||||
angular's server}.
|
angular's server}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Try to add an `{{orderProp}}` binding to `index.html`, and you'll see that nothing happens even
|
* 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
|
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
|
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.
|
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
|
* 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
|
`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
|
`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
|
(`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.
|
inheritance and model property shadowing do some wonders.
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
With the routing set up and the phone list view implemented, we're ready to go to step 8 to
|
With the routing set up and the phone list view implemented, we're ready to go to step 8 to
|
||||||
implement the phone details view.
|
implement the phone details view.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="7"></ul>
|
<ul doc:tutorial-nav="7"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,43 +2,31 @@
|
||||||
@name Tutorial: 8 - More Templating
|
@name Tutorial: 8 - More Templating
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="8"></ul>
|
<ul doc:tutorial-nav="8"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In this step, you will implement the phone details view, which is displayed when a user clicks on a
|
In this step, you will implement the phone details view, which is displayed when a user clicks on a
|
||||||
phone in the phone list.
|
phone in the phone list.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="8"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="8"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Now when you click on a phone on the list, the phone details page with phone-specific information
|
Now when you click on a phone on the list, the phone details page with phone-specific information
|
||||||
is displayed.
|
is displayed.
|
||||||
|
|
||||||
|
|
||||||
To implement the phone details view we will use {@link api/angular.service.$xhr $xhr} to fetch our
|
To implement the phone details view we will use {@link api/angular.service.$xhr $xhr} to fetch our
|
||||||
data, and we'll flesh out the `phone-details.html` view template.
|
data, and we'll flesh out the `phone-details.html` view template.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-7...step-8
|
https://github.com/angular/angular-phonecat/compare/step-7...step-8
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
|
|
||||||
|
|
||||||
In addition to `phones.json`, the `app/phones/` directory also contains one json file for each
|
In addition to `phones.json`, the `app/phones/` directory also contains one json file for each
|
||||||
phone:
|
phone:
|
||||||
|
|
||||||
|
|
||||||
__`app/phones/nexus-s.json`:__ (sample snippet)
|
__`app/phones/nexus-s.json`:__ (sample snippet)
|
||||||
<pre>
|
<pre>
|
||||||
{
|
{
|
||||||
|
|
@ -62,71 +50,53 @@ __`app/phones/nexus-s.json`:__ (sample snippet)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Each of these files describes various properties of the phone using the same data structure. We'll
|
Each of these files describes various properties of the phone using the same data structure. We'll
|
||||||
show this data in the phone detail view.
|
show this data in the phone detail view.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
|
|
||||||
We'll expand the `PhoneDetailCtrl` by using the `$xhr` service to fetch the json files. This works
|
We'll expand the `PhoneDetailCtrl` by using the `$xhr` service to fetch the json files. This works
|
||||||
the same way as the phone list controller.
|
the same way as the phone list controller.
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controller.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneDetailCtrl($xhr) {
|
function PhoneDetailCtrl($xhr) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
|
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
|
||||||
self.phone = response;
|
self.phone = response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//PhoneDetailCtrl.$inject = ['$xhr'];
|
//PhoneDetailCtrl.$inject = ['$xhr'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
To construct the URL for the HTTP request, we use `params.phoneId` extracted from the current route
|
To construct the URL for the HTTP request, we use `params.phoneId` extracted from the current route
|
||||||
in the `PhoneCatCtrl` controller.
|
in the `PhoneCatCtrl` controller.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
The TBD placeholder line has been replaced with lists and bindings that comprise the phone details.
|
The TBD placeholder line has been replaced with lists and bindings that comprise the phone details.
|
||||||
Note where we use the angular `{{expression}}` markup and `ng:repeater`s to project phone data from
|
Note where we use the angular `{{expression}}` markup and `ng:repeater`s to project phone data from
|
||||||
our model into the view.
|
our model into the view.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-details.html`:__
|
__`app/partials/phone-details.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<img ng:src="{{phone.images[0]}}" class="phone"/>
|
<img ng:src="{{phone.images[0]}}" class="phone"/>
|
||||||
|
|
||||||
|
|
||||||
<h1>{{phone.name}}</h1>
|
<h1>{{phone.name}}</h1>
|
||||||
|
|
||||||
|
|
||||||
<p>{{phone.description}}</p>
|
<p>{{phone.description}}</p>
|
||||||
|
|
||||||
|
|
||||||
<ul class="phone-thumbs">
|
<ul class="phone-thumbs">
|
||||||
<li ng:repeat="img in phone.images">
|
<li ng:repeat="img in phone.images">
|
||||||
<img ng:src="{{img}}"/>
|
<img ng:src="{{img}}"/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<ul class="specs">
|
<ul class="specs">
|
||||||
<li>
|
<li>
|
||||||
<span>Availability and Networks</span>
|
<span>Availability and Networks</span>
|
||||||
|
|
@ -143,17 +113,13 @@ __`app/partials/phone-details.html`:__
|
||||||
</ul>
|
</ul>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/tutorial_08-09_final.png">
|
<img src="img/tutorial/tutorial_08-09_final.png">
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
|
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
|
||||||
step 5.
|
step 5.
|
||||||
|
|
||||||
|
|
||||||
__`test/unit/controllerSpec.js`:__
|
__`test/unit/controllerSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -162,46 +128,36 @@ __`test/unit/controllerSpec.js`:__
|
||||||
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
|
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
|
||||||
ctrl = scope.$new(PhoneDetailCtrl);
|
ctrl = scope.$new(PhoneDetailCtrl);
|
||||||
|
|
||||||
|
|
||||||
expect(ctrl.phone).toBeUndefined();
|
expect(ctrl.phone).toBeUndefined();
|
||||||
$browser.xhr.flush();
|
$browser.xhr.flush();
|
||||||
|
|
||||||
|
|
||||||
expect(ctrl.phone).toEqual({name:'phone xyz'});
|
expect(ctrl.phone).toEqual({name:'phone xyz'});
|
||||||
});
|
});
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||||
output.
|
output.
|
||||||
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome: Runner reset.
|
||||||
...
|
...
|
||||||
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
|
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
|
||||||
Chrome 11.0.696.57 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
|
Chrome 11.0.696.57 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
|
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
|
||||||
heading on the page is "Nexus S".
|
heading on the page is "Nexus S".
|
||||||
|
|
||||||
|
|
||||||
__`test/e2e/scenarios.js`:__
|
__`test/e2e/scenarios.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
describe('Phone detail view', function() {
|
describe('Phone detail view', function() {
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should display nexus-s page', function() {
|
it('should display nexus-s page', function() {
|
||||||
expect(binding('phone.name')).toBe('Nexus S');
|
expect(binding('phone.name')).toBe('Nexus S');
|
||||||
});
|
});
|
||||||
|
|
@ -210,33 +166,23 @@ __`test/e2e/scenarios.js`:__
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
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
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||||
angular's server}.
|
angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Using the {@link
|
* Using the {@link
|
||||||
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en&pli=1#
|
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en&pli=1#
|
||||||
end-to-end test runner API}, write a test that verifies that we display 4 thumbnail images on the
|
end-to-end test runner API}, write a test that verifies that we display 4 thumbnail images on the
|
||||||
Nexus S details page.
|
Nexus S details page.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
Now that the phone details view is in place, proceed to step 9 to learn how to write your own
|
Now that the phone details view is in place, proceed to step 9 to learn how to write your own
|
||||||
custom display filter.
|
custom display filter.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="8"></ul>
|
<ul doc:tutorial-nav="8"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,44 +2,31 @@
|
||||||
@name Tutorial: 9 - Filters
|
@name Tutorial: 9 - Filters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="9"></ul>
|
<ul doc:tutorial-nav="9"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In this step you will learn how to create your own custom display filter.
|
In this step you will learn how to create your own custom display filter.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="9"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="9"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Navigate to one of the detail pages.
|
Navigate to one of the detail pages.
|
||||||
|
|
||||||
|
|
||||||
In the previous step, the details page displayed either "true" or "false" to indicate whether
|
In the previous step, the details page displayed either "true" or "false" to indicate whether
|
||||||
certain phone features were present or not. We have used a custom filter to convert those text
|
certain phone features were present or not. We have used a custom filter to convert those text
|
||||||
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see, what the filter code looks like.
|
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see, what the filter code looks like.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-8...step-9
|
https://github.com/angular/angular-phonecat/compare/step-8...step-9
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Custom Filter
|
## Custom Filter
|
||||||
|
|
||||||
|
|
||||||
In order to create a new filter, simply register your custom filter function with the {@link
|
In order to create a new filter, simply register your custom filter function with the {@link
|
||||||
api/angular.filter `angular.filter`} API.
|
api/angular.filter `angular.filter`} API.
|
||||||
|
|
||||||
|
|
||||||
__`app/js/filters.js`:__
|
__`app/js/filters.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
angular.filter('checkmark', function(input) {
|
angular.filter('checkmark', function(input) {
|
||||||
|
|
@ -47,21 +34,16 @@ angular.filter('checkmark', function(input) {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The name of our filter is "checkmark". The `input` evaluates to either `true` or `false`, and we
|
The name of our filter is "checkmark". The `input` evaluates to either `true` or `false`, and we
|
||||||
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
|
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
|
||||||
`\u2718`).
|
`\u2718`).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
Since the filter code lives in the `app/js/filters.js` file, we need to include this file in our
|
Since the filter code lives in the `app/js/filters.js` file, we need to include this file in our
|
||||||
layout template.
|
layout template.
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -70,19 +52,14 @@ __`app/index.html`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
The syntax for using filters in angular templates is as follows:
|
The syntax for using filters in angular templates is as follows:
|
||||||
|
|
||||||
|
|
||||||
{{ expression | filter }}
|
{{ expression | filter }}
|
||||||
|
|
||||||
|
|
||||||
Let's employ the filter in the phone details template:
|
Let's employ the filter in the phone details template:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-detail.html`:__
|
__`app/partials/phone-detail.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -96,19 +73,14 @@ __`app/partials/phone-detail.html`:__
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
Filters, like any other component, should be tested and these tests are very easy to write.
|
Filters, like any other component, should be tested and these tests are very easy to write.
|
||||||
|
|
||||||
|
|
||||||
__`test/unit/filtersSpec.js`:__
|
__`test/unit/filtersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('checkmark filter', function() {
|
describe('checkmark filter', function() {
|
||||||
|
|
||||||
|
|
||||||
it('should convert boolean values to unicode checkmark or cross', function() {
|
it('should convert boolean values to unicode checkmark or cross', function() {
|
||||||
expect(angular.filter.checkmark(true)).toBe('\u2713');
|
expect(angular.filter.checkmark(true)).toBe('\u2713');
|
||||||
expect(angular.filter.checkmark(false)).toBe('\u2718');
|
expect(angular.filter.checkmark(false)).toBe('\u2718');
|
||||||
|
|
|
||||||
|
|
@ -2,80 +2,59 @@
|
||||||
@name Tutorial: 10 - Event Handlers
|
@name Tutorial: 10 - Event Handlers
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="10"></ul>
|
<ul doc:tutorial-nav="10"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In this step, you will add a clickable phone image swapper to the phone details page.
|
In this step, you will add a clickable phone image swapper to the phone details page.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="10"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="10"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The phone details view displays one large image of the current phone and several smaller thumbnail
|
The phone details view displays one large image of the current phone and several smaller thumbnail
|
||||||
images. It would be great if we could replace the large image with any of the thumbnails just by
|
images. It would be great if we could replace the large image with any of the thumbnails just by
|
||||||
clicking on the desired thumbnail image. Let's have a look at how we can do this with angular.
|
clicking on the desired thumbnail image. Let's have a look at how we can do this with angular.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-9...step-10
|
https://github.com/angular/angular-phonecat/compare/step-9...step-10
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controllers.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
function PhoneDetailCtrl($xhr) {
|
function PhoneDetailCtrl($xhr) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
|
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
|
||||||
self.phone = response;
|
self.phone = response;
|
||||||
self.mainImageUrl = response.images[0];
|
self.mainImageUrl = response.images[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
self.setImage = function(imageUrl) {
|
self.setImage = function(imageUrl) {
|
||||||
self.mainImageUrl = imageUrl;
|
self.mainImageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//PhoneDetailCtrl.$inject = ['$xhr'];
|
//PhoneDetailCtrl.$inject = ['$xhr'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
In the `PhoneDetailCtrl` controller, we created the `mainImageUrl` model property and set its
|
In the `PhoneDetailCtrl` controller, we created the `mainImageUrl` model property and set its
|
||||||
default value to the first phone image url.
|
default value to the first phone image url.
|
||||||
|
|
||||||
|
|
||||||
We also created a `setImage` controller method to change the value of `mainImageUrl`.
|
We also created a `setImage` controller method to change the value of `mainImageUrl`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-detail.html`:__
|
__`app/partials/phone-detail.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<img ng:src="{{mainImageUrl}}" class="phone"/>
|
<img ng:src="{{mainImageUrl}}" class="phone"/>
|
||||||
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
<ul class="phone-thumbs">
|
<ul class="phone-thumbs">
|
||||||
<li ng:repeat="img in phone.images">
|
<li ng:repeat="img in phone.images">
|
||||||
<img ng:src="{{img}}" ng:click="setImage(img)">
|
<img ng:src="{{img}}" ng:click="setImage(img)">
|
||||||
|
|
@ -84,53 +63,40 @@ __`app/partials/phone-detail.html`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We bound the `ng:src` attribute of the large image to the `mainImageUrl` property.
|
We bound the `ng:src` attribute of the large image to the `mainImageUrl` property.
|
||||||
|
|
||||||
|
|
||||||
We also registered an {@link api/angular.directive.ng:click `ng:click`} handler with thumbnail
|
We also registered an {@link api/angular.directive.ng:click `ng:click`} handler with thumbnail
|
||||||
images. When a user clicks on one of the thumbnail images, the handler will use the `setImage`
|
images. When a user clicks on one of the thumbnail images, the handler will use the `setImage`
|
||||||
controller method to change the value of the `mainImageUrl` property to the url of the thumbnail
|
controller method to change the value of the `mainImageUrl` property to the url of the thumbnail
|
||||||
image.
|
image.
|
||||||
|
|
||||||
|
|
||||||
<img src="img/tutorial/tutorial_10-11_final.png">
|
<img src="img/tutorial/tutorial_10-11_final.png">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
To verify this new feature, we added two end-to-end tests. One verifies that the main image is set
|
To verify this new feature, we added two end-to-end tests. One verifies that the main image is set
|
||||||
to the first phone image by default. The second test clicks on several thumbnail images and
|
to the first phone image by default. The second test clicks on several thumbnail images and
|
||||||
verifies that the main image changed appropriately.
|
verifies that the main image changed appropriately.
|
||||||
|
|
||||||
|
|
||||||
__`test/e2e/scenarios.js`:__
|
__`test/e2e/scenarios.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
describe('Phone detail view', function() {
|
describe('Phone detail view', function() {
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should display the first phone image as the main phone image', function() {
|
it('should display the first phone image as the main phone image', function() {
|
||||||
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
|
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should swap main image if a thumbnail image is clicked on', function() {
|
it('should swap main image if a thumbnail image is clicked on', function() {
|
||||||
element('.phone-thumbs li:nth-child(3) img').click();
|
element('.phone-thumbs li:nth-child(3) img').click();
|
||||||
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
|
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
|
||||||
|
|
||||||
|
|
||||||
element('.phone-thumbs li:nth-child(1) img').click();
|
element('.phone-thumbs li:nth-child(1) img').click();
|
||||||
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
|
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
|
||||||
});
|
});
|
||||||
|
|
@ -138,51 +104,37 @@ __`test/e2e/scenarios.js`:__
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
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
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||||
angular's server}.
|
angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
||||||
* Let's add a new controller method to `PhoneCatCtrl`:
|
* Let's add a new controller method to `PhoneCatCtrl`:
|
||||||
|
|
||||||
|
|
||||||
this.hello(name) = function(name) {
|
this.hello(name) = function(name) {
|
||||||
alert('Hello ' + (name || 'world') + '!');
|
alert('Hello ' + (name || 'world') + '!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
and add:
|
and add:
|
||||||
|
|
||||||
|
|
||||||
<button ng:click="hello('Elmo')">Hello</button>
|
<button ng:click="hello('Elmo')">Hello</button>
|
||||||
|
|
||||||
|
|
||||||
to the `index.html` template.
|
to the `index.html` template.
|
||||||
|
|
||||||
|
|
||||||
The controller methods are inherited between controllers/scopes, so you can use the same snippet
|
The controller methods are inherited between controllers/scopes, so you can use the same snippet
|
||||||
in the `phone-list.html` template as well.
|
in the `phone-list.html` template as well.
|
||||||
|
|
||||||
|
|
||||||
* Move the `hello` method from `PhoneCatCtrl` to `PhoneListCtrl` and you'll see that the button
|
* Move the `hello` method from `PhoneCatCtrl` to `PhoneListCtrl` and you'll see that the button
|
||||||
declared in `index.html` will stop working, while the one declared in the `phone-list.html`
|
declared in `index.html` will stop working, while the one declared in the `phone-list.html`
|
||||||
template remains operational.
|
template remains operational.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
With the phone image swapper in place, we're ready for step 11 (the last step!) to learn an even
|
With the phone image swapper in place, we're ready for step 11 (the last step!) to learn an even
|
||||||
better way to fetch data.
|
better way to fetch data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="10"></ul>
|
<ul doc:tutorial-nav="10"></ul>
|
||||||
|
|
|
||||||
|
|
@ -2,42 +2,30 @@
|
||||||
@name Tutorial: 11 - REST and Custom Services
|
@name Tutorial: 11 - REST and Custom Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="11"></ul>
|
<ul doc:tutorial-nav="11"></ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In this step, you will improve the way our app fetches data.
|
In this step, you will improve the way our app fetches data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<doc:tutorial-instructions step="11"></doc:tutorial-instructions>
|
<doc:tutorial-instructions step="11"></doc:tutorial-instructions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||||
can make xhr requests for data in an easier way, without having to deal with the lower-level {@link
|
can make xhr requests for data in an easier way, without having to deal with the lower-level {@link
|
||||||
api/angular.service.$xhr $xhr} API, HTTP methods and URLs.
|
api/angular.service.$xhr $xhr} API, HTTP methods and URLs.
|
||||||
|
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-10...step-11
|
https://github.com/angular/angular-phonecat/compare/step-10...step-11
|
||||||
GitHub}:
|
GitHub}:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Template
|
## Template
|
||||||
|
|
||||||
|
|
||||||
The custom service is defined in `app/js/services.js` so we need to include this file in our layout
|
The custom service is defined in `app/js/services.js` so we need to include this file in our layout
|
||||||
template:
|
template:
|
||||||
|
|
||||||
|
|
||||||
__`app/index.html`.__
|
__`app/index.html`.__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
@ -45,10 +33,8 @@ __`app/index.html`.__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Service
|
## Service
|
||||||
|
|
||||||
|
|
||||||
__`app/js/services.js`.__
|
__`app/js/services.js`.__
|
||||||
<pre>
|
<pre>
|
||||||
angular.service('Phone', function($resource) {
|
angular.service('Phone', function($resource) {
|
||||||
|
|
@ -58,36 +44,29 @@ __`app/js/services.js`.__
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
We used the {@link api/angular.service} API to register a custom service. We passed in the name of
|
We used the {@link api/angular.service} API to register a custom service. We passed in the name of
|
||||||
the service - 'Phone' - and a factory function. The factory function is similar to a controller's
|
the service - 'Phone' - and a factory function. The factory function is similar to a controller's
|
||||||
constructor in that both can declare dependencies via function arguments. The Phone service
|
constructor in that both can declare dependencies via function arguments. The Phone service
|
||||||
declared a dependency on the `$resource` service.
|
declared a dependency on the `$resource` service.
|
||||||
|
|
||||||
|
|
||||||
The {@link api/angular.service.$resource `$resource`} service makes it easy to create a {@link
|
The {@link api/angular.service.$resource `$resource`} service makes it easy to create a {@link
|
||||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client with just a few lines
|
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client with just a few lines
|
||||||
of code. This client can then be used in our application, instead of the lower-level {@link
|
of code. This client can then be used in our application, instead of the lower-level {@link
|
||||||
api/angular.service.$xhr $xhr} service.
|
api/angular.service.$xhr $xhr} service.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
|
|
||||||
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
||||||
lower-level {@link api/angular.service.$xhr $xhr} service, replacing it with a new service called
|
lower-level {@link api/angular.service.$xhr $xhr} service, replacing it with a new service called
|
||||||
`Phone`. Angular's {@link api/angular.service.$resource `$resource`} service is easier to use than
|
`Phone`. Angular's {@link api/angular.service.$resource `$resource`} service is easier to use than
|
||||||
{@link api/angular.service.$xhr $xhr} for interacting with data sources exposed as RESTful
|
{@link api/angular.service.$xhr $xhr} for interacting with data sources exposed as RESTful
|
||||||
resources. It is also easier now to understand what the code in our controllers is doing.
|
resources. It is also easier now to understand what the code in our controllers is doing.
|
||||||
|
|
||||||
|
|
||||||
__`app/js/controllers.js`.__
|
__`app/js/controllers.js`.__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
function PhoneListCtrl(Phone_) {
|
function PhoneListCtrl(Phone_) {
|
||||||
this.orderProp = 'age';
|
this.orderProp = 'age';
|
||||||
this.phones = Phone_.query();
|
this.phones = Phone_.query();
|
||||||
|
|
@ -95,40 +74,30 @@ function PhoneListCtrl(Phone_) {
|
||||||
//PhoneListCtrl.$inject = ['Phone'];
|
//PhoneListCtrl.$inject = ['Phone'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function PhoneDetailCtrl(Phone_) {
|
function PhoneDetailCtrl(Phone_) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
self.phone = Phone_.get({phoneId: self.params.phoneId}, function(phone) {
|
self.phone = Phone_.get({phoneId: self.params.phoneId}, function(phone) {
|
||||||
self.mainImageUrl = phone.images[0];
|
self.mainImageUrl = phone.images[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
//PhoneDetailCtrl.$inject = ['Phone'];
|
//PhoneDetailCtrl.$inject = ['Phone'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Notice how in `PhoneListCtrl` we replaced:
|
Notice how in `PhoneListCtrl` we replaced:
|
||||||
|
|
||||||
|
|
||||||
$xhr('GET', 'phones/phones.json', function(code, response) {
|
$xhr('GET', 'phones/phones.json', function(code, response) {
|
||||||
self.phones = response;
|
self.phones = response;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
with:
|
with:
|
||||||
|
|
||||||
|
|
||||||
this.phones = Phone_.query();
|
this.phones = Phone_.query();
|
||||||
|
|
||||||
|
|
||||||
This is a simple statement that we want to query for all phones.
|
This is a simple statement that we want to query for all phones.
|
||||||
|
|
||||||
|
|
||||||
An important thing to notice in the code above is that we don't pass any callback functions when
|
An important thing to notice in the code above is that we don't pass any callback functions when
|
||||||
invoking methods of our Phone service. Although it looks as if the result were returned
|
invoking methods of our Phone service. Although it looks as if the result were returned
|
||||||
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
||||||
|
|
@ -136,22 +105,17 @@ object, which will be filled with data when the xhr response returns. Because of
|
||||||
in angular, we can use this future and bind it to our template. Then, when the data arrives, the
|
in angular, we can use this future and bind it to our template. Then, when the data arrives, the
|
||||||
view will automatically update.
|
view will automatically update.
|
||||||
|
|
||||||
|
|
||||||
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
||||||
we require, so in these cases, we can add a callback to process the server response. The
|
we require, so in these cases, we can add a callback to process the server response. The
|
||||||
`PhoneDetailCtrl` controller illustrates this by setting the `mainImageUrl` in a callback.
|
`PhoneDetailCtrl` controller illustrates this by setting the `mainImageUrl` in a callback.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
|
|
||||||
We have modified our unit tests to verify that our new service is issuing HTTP requests and
|
We have modified our unit tests to verify that our new service is issuing HTTP requests and
|
||||||
processing them as expected. The tests also check that our controllers are interacting with the
|
processing them as expected. The tests also check that our controllers are interacting with the
|
||||||
service correctly.
|
service correctly.
|
||||||
|
|
||||||
|
|
||||||
The {@link api/angular.service.$resource $resource} client augments the response object with
|
The {@link api/angular.service.$resource $resource} client augments the response object with
|
||||||
methods for updating and deleting the resource. If we were to use the standard `toEqual` matcher,
|
methods for updating and deleting the resource. If we were to use the standard `toEqual` matcher,
|
||||||
our tests would fail because the test values would not match the responses exactly. To solve the
|
our tests would fail because the test values would not match the responses exactly. To solve the
|
||||||
|
|
@ -161,13 +125,10 @@ http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine ma
|
||||||
ignores methods.
|
ignores methods.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__`test/unit/controllersSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat controllers', function() {
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function(){
|
beforeEach(function(){
|
||||||
this.addMatchers({
|
this.addMatchers({
|
||||||
toEqualData: function(expected) {
|
toEqualData: function(expected) {
|
||||||
|
|
@ -176,92 +137,71 @@ describe('PhoneCat controllers', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('PhoneListCtrl', function() {
|
describe('PhoneListCtrl', function() {
|
||||||
var scope, $browser, ctrl;
|
var scope, $browser, ctrl;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
scope = angular.scope();
|
scope = angular.scope();
|
||||||
$browser = scope.$service('$browser');
|
$browser = scope.$service('$browser');
|
||||||
|
|
||||||
|
|
||||||
$browser.xhr.expectGET('phones/phones.json')
|
$browser.xhr.expectGET('phones/phones.json')
|
||||||
.respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
|
.respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
|
||||||
ctrl = scope.$new(PhoneListCtrl);
|
ctrl = scope.$new(PhoneListCtrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should create "phones" model with 2 phones fetched from xhr', function() {
|
it('should create "phones" model with 2 phones fetched from xhr', function() {
|
||||||
expect(ctrl.phones).toEqual([]);
|
expect(ctrl.phones).toEqual([]);
|
||||||
$browser.xhr.flush();
|
$browser.xhr.flush();
|
||||||
|
|
||||||
|
|
||||||
expect(ctrl.phones).toEqualData([{name: 'Nexus S'},
|
expect(ctrl.phones).toEqualData([{name: 'Nexus S'},
|
||||||
{name: 'Motorola DROID'}]);
|
{name: 'Motorola DROID'}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should set the default value of orderProp model', function() {
|
it('should set the default value of orderProp model', function() {
|
||||||
expect(ctrl.orderProp).toBe('age');
|
expect(ctrl.orderProp).toBe('age');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
describe('PhoneDetailCtrl', function() {
|
describe('PhoneDetailCtrl', function() {
|
||||||
var scope, $browser, ctrl;
|
var scope, $browser, ctrl;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
scope = angular.scope();
|
scope = angular.scope();
|
||||||
$browser = scope.$service('$browser');
|
$browser = scope.$service('$browser');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
scope = angular.scope();
|
scope = angular.scope();
|
||||||
$browser = scope.$service('$browser');
|
$browser = scope.$service('$browser');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should fetch phone detail', function() {
|
it('should fetch phone detail', function() {
|
||||||
scope.params = {phoneId:'xyz'};
|
scope.params = {phoneId:'xyz'};
|
||||||
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
|
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
|
||||||
ctrl = scope.$new(PhoneDetailCtrl);
|
ctrl = scope.$new(PhoneDetailCtrl);
|
||||||
|
|
||||||
|
|
||||||
expect(ctrl.phone).toEqualData({});
|
expect(ctrl.phone).toEqualData({});
|
||||||
$browser.xhr.flush();
|
$browser.xhr.flush();
|
||||||
|
|
||||||
|
|
||||||
expect(ctrl.phone).toEqualData({name:'phone xyz'});
|
expect(ctrl.phone).toEqualData({name:'phone xyz'});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||||
output.
|
output.
|
||||||
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome: Runner reset.
|
||||||
....
|
....
|
||||||
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
|
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
|
||||||
Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
|
Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
|
|
||||||
There you have it! We have created a web app in a relatively short amount of time.
|
There you have it! We have created a web app in a relatively short amount of time.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ul doc:tutorial-nav="11"></ul>
|
<ul doc:tutorial-nav="11"></ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,20 @@
|
||||||
@name Tutorial: The End
|
@name Tutorial: The End
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
||||||
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||||
previous steps using the `git checkout` or `goto_step.sh` commands.
|
previous steps using the `git checkout` or `goto_step.sh` commands.
|
||||||
|
|
||||||
|
|
||||||
For more details and examples of the angular concepts we touched on in this tutorial, see the
|
For more details and examples of the angular concepts we touched on in this tutorial, see the
|
||||||
{@link guide/ Developer Guide}.
|
{@link guide/ Developer Guide}.
|
||||||
|
|
||||||
|
|
||||||
For several more examples of code, see the {@link cookbook/ Cookbook}.
|
For several more examples of code, see the {@link cookbook/ Cookbook}.
|
||||||
|
|
||||||
|
|
||||||
When you are ready to start developing a project using angular, we recommend that you bootstrap
|
When you are ready to start developing a project using angular, we recommend that you bootstrap
|
||||||
your development with the {@link https://github.com/angular/angular-seed angular seed} project.
|
your development with the {@link https://github.com/angular/angular-seed angular seed} project.
|
||||||
|
|
||||||
|
|
||||||
We hope this tutorial was useful to you and that you learned enough about angular to make you want
|
We hope this tutorial was useful to you and that you learned enough about angular to make you want
|
||||||
to learn more. We especially hope you are inspired to go out and develop angular web apps of your
|
to learn more. We especially hope you are inspired to go out and develop angular web apps of your
|
||||||
own, and that you might be interested in {@link misc/contribute contributing} to angular.
|
own, and that you might be interested in {@link misc/contribute contributing} to angular.
|
||||||
|
|
||||||
|
|
||||||
If you have questions or feedback or just want to say "hi", please post a message at {@link
|
If you have questions or feedback or just want to say "hi", please post a message at {@link
|
||||||
https://groups.google.com/forum/#!forum/angular}.
|
https://groups.google.com/forum/#!forum/angular}.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue