docs(guide/overview): Refactor overview and mvc docs
Before, there we multiple overview docs: - guide/overview - guide/introduction - guide/dev_guide.mvc - guide/dev_guide.mvc.understanding_model - guide/dev_guide.mvc.understanding_view - guide/concepts Now we have: - guide/introduction: High level description of Angular with the key benefits but without code or any concrete concepts - guide/concepts: explains all important concepts with a simple example and contains deep links to the other parts of the guide. All the old information was moved into existing documents or deleted when they were duplicates.
|
|
@ -169,21 +169,23 @@ directive.ngSetHtml = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
|
||||||
directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
|
directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
|
||||||
return {
|
return {
|
||||||
compile: function (element, attr) {
|
compile: function (element, attr) {
|
||||||
var script = getEmbeddedTemplate(attr.ngEvalJavascript);
|
var fileNames = attr.ngEvalJavascript.split(' ');
|
||||||
|
angular.forEach(fileNames, function(fileName) {
|
||||||
try {
|
var script = getEmbeddedTemplate(fileName);
|
||||||
if (window.execScript) { // IE
|
try {
|
||||||
window.execScript(script || '""'); // IE complains when evaling empty string
|
if (window.execScript) { // IE
|
||||||
} else {
|
window.execScript(script || '""'); // IE complains when evaling empty string
|
||||||
window.eval(script);
|
} else {
|
||||||
|
window.eval(script + '//@ sourceURL=' + fileName);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (window.console) {
|
||||||
|
window.console.log(script, '\n', e);
|
||||||
|
} else {
|
||||||
|
window.alert(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
});
|
||||||
if (window.console) {
|
|
||||||
window.console.log(script, '\n', e);
|
|
||||||
} else {
|
|
||||||
window.alert(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,17 @@ Welcome to the AngularJS API docs page. These pages contain the AngularJS refere
|
||||||
The documentation is organized into **modules** which contain various components of an AngularJS application.
|
The documentation is organized into **modules** which contain various components of an AngularJS application.
|
||||||
These components are directives, services, filters, providers, types, global APIs and testing mocks.
|
These components are directives, services, filters, providers, types, global APIs and testing mocks.
|
||||||
|
|
||||||
|
<div class="alert alert-info">
|
||||||
|
**Angular Namspaces `$` and `$$`**
|
||||||
|
|
||||||
|
To prevent accidental name collisions with your code,
|
||||||
|
Angular prefixes names of public objects with `$` and names of private objects with `$$`.
|
||||||
|
Please do not use the `$` or `$$` prefix in your code.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Angular Namespace
|
||||||
|
|
||||||
|
|
||||||
## {@link ng ng (core module)}
|
## {@link ng ng (core module)}
|
||||||
This module is provided by default and contains the core components of AngularJS.
|
This module is provided by default and contains the core components of AngularJS.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,6 @@ Take a look through the source and note:
|
||||||
* There is no need for listener registration and event firing on change events.
|
* There is no need for listener registration and event firing on change events.
|
||||||
* The implicit presence of the `name` variable which is in the root {@link api/ng.$rootScope.Scope scope}.
|
* The implicit presence of the `name` variable which is in the root {@link api/ng.$rootScope.Scope scope}.
|
||||||
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
|
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
|
||||||
* The concept of {@link guide/dev_guide.templates.databinding data binding}, which reflects any
|
* The concept of {@link guide/databinding data binding}, which reflects any
|
||||||
changes to the
|
changes to the
|
||||||
input field in the greeting text.
|
input field in the greeting text.
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ initialization.
|
||||||
|
|
||||||
## Automatic Initialization
|
## Automatic Initialization
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
|
||||||
|
|
||||||
Angular initializes automatically upon `DOMContentLoaded` event or when the `angular.js` script is
|
Angular initializes automatically upon `DOMContentLoaded` event or when the `angular.js` script is
|
||||||
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
|
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
|
||||||
for the {@link api/ng.directive:ngApp `ng-app`} directive which designates your application root.
|
for the {@link api/ng.directive:ngApp `ng-app`} directive which designates your application root.
|
||||||
|
|
|
||||||
|
|
@ -2,450 +2,383 @@
|
||||||
@name Conceptual Overview
|
@name Conceptual Overview
|
||||||
@description
|
@description
|
||||||
|
|
||||||
# Overview
|
There are some concepts within Angular that you should understand before creating your first application.
|
||||||
|
This section touches all important parts of Angular really quickly using a simple example.
|
||||||
|
However, it won't explain all details.
|
||||||
|
For a more in-depth explanation, have a look at the {@link tutorial/ tutorial}.
|
||||||
|
|
||||||
This document gives a quick overview of the main angular components and how they work together.
|
| Concept | Description |
|
||||||
These are:
|
|------------------|------------------------------------------|
|
||||||
|
|{@link concepts#template Template} | HTML with additional markup |
|
||||||
|
|{@link concepts#directive Directives} | extend HTML with custom attributes and elements |
|
||||||
|
|{@link concepts#model Model} | the data that is shown to the user and with which the user interacts |
|
||||||
|
|{@link concepts#scope Scope} | context where the model is stored so that directives and expressions can access it |
|
||||||
|
|{@link concepts#expression Expressions} | access variables and functions from the scope |
|
||||||
|
|{@link concepts#compiler Compiler} | parses the template and instantiates directives and expressions |
|
||||||
|
|{@link concepts#filter Filter} | formats the value of an expression for display to the user |
|
||||||
|
|{@link concepts#view View} | what the user sees (the DOM) |
|
||||||
|
|{@link concepts#databinding Data Binding} | sync data between the model and the view |
|
||||||
|
|{@link concepts#controller Controller} | the business logic behind views |
|
||||||
|
|{@link concepts#di Dependency Injection} | Creates and wires objects / functions |
|
||||||
|
|{@link concepts#injector Injector} | dependency injection container |
|
||||||
|
|{@link concepts#module Module} | configures the Injector |
|
||||||
|
|{@link concepts#service Service} | reusable business logic independent of views |
|
||||||
|
|
||||||
* {@link concepts#startup startup} - bring up hello world
|
|
||||||
* {@link concepts#runtime runtime} - overview of angular runtime
|
|
||||||
* {@link concepts#scope scope} - the glue between the view and the controller
|
|
||||||
* {@link concepts#controller controller} - application behavior
|
|
||||||
* {@link concepts#model model} - your application data
|
|
||||||
* {@link concepts#view view} - what the user sees
|
|
||||||
* {@link concepts#directives directives} - extend HTML vocabulary
|
|
||||||
* {@link concepts#filters filters} - format the data in user locale
|
|
||||||
* {@link concepts#injector injector} - assembles your application
|
|
||||||
* {@link concepts#module module} - configures the injector
|
|
||||||
* {@link concepts#angular_namespace `$`} - angular namespace
|
|
||||||
|
|
||||||
<a name="startup"></a>
|
# A first example: Data binding
|
||||||
# Startup
|
|
||||||
|
|
||||||
This is how we get the ball rolling (refer to the diagram and example below):
|
In the following we will build a form to calculate the costs of an invoice in different currencies.
|
||||||
|
|
||||||
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
|
Let's start with input fields for quantity and cost whose values are multiplied to produce the total of the invoice:
|
||||||
|
|
||||||
1. The browser loads the HTML and parses it into a DOM
|
|
||||||
2. The browser loads `angular.js` script
|
|
||||||
3. Angular waits for `DOMContentLoaded` event
|
|
||||||
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
|
|
||||||
{@link guide/directive directive}, which designates the application boundary
|
|
||||||
5. The {@link guide/module Module} specified in {@link
|
|
||||||
api/ng.directive:ngApp ng-app} (if any) is used to configure
|
|
||||||
the {@link api/AUTO.$injector $injector}
|
|
||||||
6. The {@link api/AUTO.$injector $injector} is used to create the {@link
|
|
||||||
api/ng.$compile $compile} service as well as {@link
|
|
||||||
api/ng.$rootScope $rootScope}
|
|
||||||
7. The {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
|
||||||
it with {@link api/ng.$rootScope $rootScope}
|
|
||||||
8. The {@link api/ng.directive:ngInit ng-init} {@link
|
|
||||||
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
|
|
||||||
scope}
|
|
||||||
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
|
|
||||||
`Hello World!`
|
|
||||||
|
|
||||||
<example>
|
<example>
|
||||||
<file name="index.html">
|
<file name="index.html">
|
||||||
<p ng-init=" name='World' ">Hello {{name}}!</p>
|
<div ng-init="qty=1;cost=2">
|
||||||
|
<b>Invoice:</b>
|
||||||
|
<div>
|
||||||
|
Quantity: <input type="number" ng-model="qty" required >
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Costs: <input type="number" ng-model="cost" required >
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Total:</b> {{qty * cost | currency}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</file>
|
</file>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
Try out the Live Preview above, and then let's walk through the example and describe what's going on.
|
||||||
|
|
||||||
<a name="runtime"></a>
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding1.png">
|
||||||
# Runtime
|
|
||||||
|
|
||||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
|
This looks like normal HTML, with some new markup. In Angular, a file like this is called a
|
||||||
|
<a name="template">"{@link templates template}"</a>. When Angular starts your application, it parses and
|
||||||
|
processes this new markup from the template using the so called <a name="compiler">"{@link compiler compiler}"</a>.
|
||||||
|
The loaded, transformed and rendered DOM is then called the <a name="view">"view"</a>.
|
||||||
|
|
||||||
The diagram and the example below describe how Angular interacts with the browser's event loop.
|
The first kind of new markup are the so called <a name="directive">"{@link directive directives}"</a>.
|
||||||
|
They apply special behavior to attributes or elements in the HTML. In the example above we use the
|
||||||
|
{@link api/ng.directive:ngApp `ng-app`} attribute, which is linked to a directive that automatically
|
||||||
|
initializes our application. Angular also defines a directive for the {@link api/ng.directive:input `input`}
|
||||||
|
element that adds extra behavior to the element. E.g. it is able to automatically validate that the entered
|
||||||
|
text is non empty by evaluating the `required` attribute.
|
||||||
|
The {@link api/ng.directive:ngModel `ng-model`} directive stores/updates
|
||||||
|
the value of the input field into/from a variable and shows the validation state of the input field by
|
||||||
|
adding css classes. In the example we use these css classes to mark an empty input field with a red border.
|
||||||
|
|
||||||
1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event,
|
<div class="alert alert-info">
|
||||||
or network event (response from a server).
|
**Custom directives to access the DOM**: In Angular, the only place where an application touches the DOM is
|
||||||
2. The event's callback gets executed. This enters the JavaScript context. The callback can
|
within directives. This is good as artifacts that access the DOM are hard to test.
|
||||||
modify the DOM structure.
|
If you need to access the DOM directly you should write a custom directive for this. The
|
||||||
3. Once the callback executes, the browser leaves the JavaScript context and
|
{@link directive directives guide} explains how to do this.
|
||||||
re-renders the view based on DOM changes.
|
|
||||||
|
|
||||||
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
|
|
||||||
splits the JavaScript into classical and Angular execution context. Only operations which are
|
|
||||||
applied in Angular execution context will benefit from Angular data-binding, exception handling,
|
|
||||||
property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in
|
|
||||||
mind that in most places (controllers, services) $apply has already been called for you by the
|
|
||||||
directive which is handling the event. An explicit call to $apply is needed only when
|
|
||||||
implementing custom event callbacks, or when working with third-party library callbacks.
|
|
||||||
|
|
||||||
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
|
|
||||||
api/ng.$rootScope.Scope#methods_$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
|
|
||||||
the work you wish to do in Angular execution context.
|
|
||||||
2. Angular executes the `stimulusFn()`, which typically modifies application state.
|
|
||||||
3. Angular enters the {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop. The
|
|
||||||
loop is made up of two smaller loops which process {@link
|
|
||||||
api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue and the {@link
|
|
||||||
api/ng.$rootScope.Scope#methods_$watch $watch} list. The {@link
|
|
||||||
api/ng.$rootScope.Scope#methods_$digest $digest} loop keeps iterating until the model
|
|
||||||
stabilizes, which means that the {@link api/ng.$rootScope.Scope#methods_$evalAsync
|
|
||||||
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#methods_$watch
|
|
||||||
$watch} list does not detect any changes.
|
|
||||||
4. The {@link api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue is used to
|
|
||||||
schedule work which needs to occur outside of current stack frame, but before the browser's
|
|
||||||
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
|
|
||||||
suffers from slowness and may cause view flickering since the browser renders the view after
|
|
||||||
each event.
|
|
||||||
5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list is a set of expressions
|
|
||||||
which may have changed since last iteration. If a change is detected then the `$watch`
|
|
||||||
function is called which typically updates the DOM with the new value.
|
|
||||||
6. Once the Angular {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop finishes
|
|
||||||
the execution leaves the Angular and JavaScript context. This is followed by the browser
|
|
||||||
re-rendering the DOM to reflect any changes.
|
|
||||||
|
|
||||||
|
|
||||||
Here is the explanation of how the `Hello world` example achieves the data-binding effect when the
|
|
||||||
user enters text into the text field.
|
|
||||||
|
|
||||||
1. During the compilation phase:
|
|
||||||
1. the {@link api/ng.directive:ngModel ng-model} and {@link
|
|
||||||
api/ng.directive:input input} {@link guide/directive
|
|
||||||
directive} set up a `keydown` listener on the `<input>` control.
|
|
||||||
2. the {@link api/ng.$interpolate {{name}} } interpolation
|
|
||||||
sets up a {@link api/ng.$rootScope.Scope#methods_$watch $watch} to be notified of
|
|
||||||
`name` changes.
|
|
||||||
2. During the runtime phase:
|
|
||||||
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
|
|
||||||
2. The {@link api/ng.directive:input input} directive
|
|
||||||
captures the change to the input's value and calls {@link
|
|
||||||
api/ng.$rootScope.Scope#methods_$apply $apply}`("name = 'X';")` to update the
|
|
||||||
application model inside the Angular execution context.
|
|
||||||
3. Angular applies the `name = 'X';` to the model.
|
|
||||||
4. The {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop begins
|
|
||||||
5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list detects a change
|
|
||||||
on the `name` property and notifies the {@link api/ng.$interpolate
|
|
||||||
{{name}} } interpolation, which in turn updates the DOM.
|
|
||||||
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
|
|
||||||
the JavaScript execution context.
|
|
||||||
7. The browser re-renders the view with update text.
|
|
||||||
|
|
||||||
<example>
|
|
||||||
<file name="index.html">
|
|
||||||
<input ng-model="name">
|
|
||||||
<p>Hello {{name}}!</p>
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
|
|
||||||
<a name="scope"></a>
|
|
||||||
#Scope
|
|
||||||
|
|
||||||
The {@link guide/scope scope} is responsible for detecting changes to the model section and
|
|
||||||
provides the execution context for expressions. The scopes are nested in a hierarchical structure
|
|
||||||
which closely follow the DOM structure. (See individual directive documentation to see which
|
|
||||||
directives cause a creation of new scopes.)
|
|
||||||
|
|
||||||
The following example demonstrates how the `name` {@link guide/expression expression} will evaluate
|
|
||||||
into a different value depending on which scope it is evaluated in. The example is followed by
|
|
||||||
a diagram depicting the scope boundaries.
|
|
||||||
|
|
||||||
<div class="show-scope">
|
|
||||||
<example>
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-controller="GreetCtrl">
|
|
||||||
Hello {{name}}!
|
|
||||||
</div>
|
|
||||||
<div ng-controller="ListCtrl">
|
|
||||||
<ol>
|
|
||||||
<li ng-repeat="name in names">{{name}}</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
<file name="script.js">
|
|
||||||
function GreetCtrl($scope) {
|
|
||||||
$scope.name = 'World';
|
|
||||||
}
|
|
||||||
|
|
||||||
function ListCtrl($scope) {
|
|
||||||
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
<file name="style.css">
|
|
||||||
.show-scope .doc-example-live.ng-scope,
|
|
||||||
.show-scope .doc-example-live .ng-scope {
|
|
||||||
border: 1px solid red;
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img class="center" src="img/guide/concepts-scope.png">
|
The second kind of new markup are the double curly braces `{{ expression | filter }}`:
|
||||||
|
When the compiler encounters this markup, it will replace it with the evaluated value of the markup.
|
||||||
|
An <a name="expression">"{@link expression expression}"</a> in a template is a JavaScript-like code snippet that allows
|
||||||
|
to read and write variables. Note that those variables are not global variables.
|
||||||
|
Just like variables in a JavaScript function live in a scope,
|
||||||
|
Angular provides a <a name="scope">"{@link scope scope}"</a> for the variables accessible to expressions.
|
||||||
|
The values that are stored in variables on the scope are referred to as the <a name="model">"model"</a>
|
||||||
|
in the rest of the documentation.
|
||||||
|
Applied to the example above, the markup directs Angular to "take the data we got from the input widgets
|
||||||
|
and multiply them together".
|
||||||
|
|
||||||
|
The example above also contains a <a name="filter">"{@link dev_guide.templates.filters filter}"</a>.
|
||||||
|
A filter formats the value of an expression for display to the user.
|
||||||
|
In the example above, the filter {@link api/ng.filter:currency `currency`} formats a number
|
||||||
|
into an output that looks like money.
|
||||||
|
|
||||||
|
The important thing in the example is that angular provides _live_ bindings:
|
||||||
|
Whenever the input values change, the value of the expressions are automatically
|
||||||
|
recalculated and the DOM is updated with their values.
|
||||||
|
The concept behind this is <a name="databinding">"{@link databinding two-way data binding}"</a>.
|
||||||
|
|
||||||
|
|
||||||
<a name="controller"></a>
|
# Adding UI logic: Controllers
|
||||||
# Controller
|
|
||||||
|
|
||||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
|
Let's add some more logic to the example to
|
||||||
|
allow to enter and calculate the costs in different currencies and also pay the invoice.
|
||||||
|
|
||||||
A controller is the code behind the view. Its job is to construct the model and publish it to the
|
<example module="invoice1">
|
||||||
view along with callback methods. The view is a projection of the scope onto the template (the
|
<file name="invoice1.js">
|
||||||
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
|
angular.module('invoice1', [])
|
||||||
controller.
|
.controller('InvoiceController', function() {
|
||||||
|
this.qty = 1;
|
||||||
|
this.cost = 2;
|
||||||
|
this.inCurr = 'EUR';
|
||||||
|
this.currencies = ['USD', 'EUR', 'CNY'];
|
||||||
|
this.usdToForeignRates = {
|
||||||
|
USD: 1,
|
||||||
|
EUR: 0.74,
|
||||||
|
CNY: 6.09
|
||||||
|
};
|
||||||
|
|
||||||
The separation of the controller and the view is important because:
|
this.total = function total(outCurr) {
|
||||||
|
return this.convertCurrency(this.qty * this.cost, this.inCurr, outCurr);
|
||||||
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
|
};
|
||||||
for specifying application behavior. The controller should not contain any rendering
|
this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
|
||||||
information (DOM references or HTML fragments).
|
return amount * this.usdToForeignRates[outCurr] * 1 / this.usdToForeignRates[inCurr];
|
||||||
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
|
};
|
||||||
specifying UI. The View should not contain any behavior.
|
this.pay = function pay() {
|
||||||
* Since the controller is unaware of the view, there could be many views for the same
|
window.alert("Thanks!");
|
||||||
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
|
};
|
||||||
and testability.
|
|
||||||
|
|
||||||
<example>
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-controller="MyCtrl">
|
|
||||||
Hello {{name}}!
|
|
||||||
<button ng-click="action()">
|
|
||||||
OK
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
<file name="script.js">
|
|
||||||
function MyCtrl($scope) {
|
|
||||||
$scope.action = function() {
|
|
||||||
$scope.name = 'OK';
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.name = 'World';
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
|
|
||||||
|
|
||||||
<a name="model"></a>
|
|
||||||
# Model
|
|
||||||
|
|
||||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
|
|
||||||
|
|
||||||
The model is the data which is merged with the template to produce the view. To be able to
|
|
||||||
render the model into the view, the model has to be able to be referenced from the scope. Unlike many
|
|
||||||
other frameworks Angular makes no restrictions or requirements on the model. There are no classes
|
|
||||||
to inherit from or special accessor methods for accessing or changing the model. The model can be
|
|
||||||
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
|
|
||||||
|
|
||||||
|
|
||||||
<a name="view"></a>
|
|
||||||
# View
|
|
||||||
|
|
||||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
|
|
||||||
|
|
||||||
The view is what the user sees. The view begins its life as a template, is merged with the
|
|
||||||
model and finally rendered into the browser DOM. Angular takes a very different approach to
|
|
||||||
rendering the view compared to most other templating systems.
|
|
||||||
|
|
||||||
* **Others** - Most templating systems begin as an HTML string with special templating markup.
|
|
||||||
Often the template markup breaks the HTML syntax which means that the template can not be
|
|
||||||
edited by an HTML editor. The template string is then parsed by the template engine, and
|
|
||||||
merged with the data. The result of the merge is an HTML string. The HTML string is then
|
|
||||||
written to the browser using the `.innerHTML`, which causes the browser to render the HTML.
|
|
||||||
When the model changes the whole process needs to be repeated. The granularity of the template
|
|
||||||
is the granularity of the DOM updates. The key here is that the templating system manipulates
|
|
||||||
strings.
|
|
||||||
* **Angular** - Angular is different, since its templating system works on DOM objects not on
|
|
||||||
strings. The template is still written in an HTML string, but it is HTML (not HTML with
|
|
||||||
template sprinkled in.) The browser parses the HTML into the DOM, and the DOM becomes the input to
|
|
||||||
the template engine known as the {@link api/ng.$compile compiler}. The compiler
|
|
||||||
looks for {@link guide/directive directives} which in turn set up {@link
|
|
||||||
api/ng.$rootScope.Scope#methods_$watch watches} on the model. The result is a
|
|
||||||
continuously updating view which does not need template model re-merging. Your model becomes
|
|
||||||
the single source-of-truth for your view.
|
|
||||||
|
|
||||||
<example>
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
|
||||||
<input ng-model="list" ng-list> <br>
|
|
||||||
<input ng-model="list" ng-list> <br>
|
|
||||||
<pre>list={{list}}</pre> <br>
|
|
||||||
<ol>
|
|
||||||
<li ng-repeat="item in list">
|
|
||||||
{{item}}
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
|
|
||||||
|
|
||||||
<a name="directives"></a>
|
|
||||||
# Directives
|
|
||||||
|
|
||||||
A directive is a behavior or DOM transformation which is triggered by the presence of a custom attribute,
|
|
||||||
element name, class name or comment. A directive allows you to extend the HTML vocabulary in a
|
|
||||||
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
|
|
||||||
in HTML.
|
|
||||||
|
|
||||||
<example module="directive">
|
|
||||||
<file name="script.js">
|
|
||||||
angular.module('directive', []).directive('contenteditable', function() {
|
|
||||||
return {
|
|
||||||
require: 'ngModel',
|
|
||||||
link: function(scope, elm, attrs, ctrl) {
|
|
||||||
// view -> model
|
|
||||||
elm.on('blur', function() {
|
|
||||||
scope.$apply(function() {
|
|
||||||
ctrl.$setViewValue(elm.html());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// model -> view
|
|
||||||
ctrl.$render = function(value) {
|
|
||||||
elm.html(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
// load init value from DOM
|
|
||||||
ctrl.$setViewValue(elm.html());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
</file>
|
|
||||||
<file name="index.html">
|
|
||||||
<div contentEditable="true" ng-model="content">Edit Me</div>
|
|
||||||
<pre>model = {{content}}</pre>
|
|
||||||
</file>
|
|
||||||
<file name="style.css">
|
|
||||||
div[contentEditable] {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #D0D0D0;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
|
|
||||||
<a name="filters"></a>
|
|
||||||
# Filters
|
|
||||||
|
|
||||||
{@link api/ng.$filter Filters} perform data transformation. Typically
|
|
||||||
they are used in conjunction with the locale to format the data in locale specific output.
|
|
||||||
They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
|
|
||||||
|
|
||||||
<example>
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
|
||||||
Number formatting: {{ 1234567890 | number }} <br>
|
|
||||||
array filtering <input ng-model="predicate">
|
|
||||||
{{ list | filter:predicate | json }}
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
|
|
||||||
|
|
||||||
<a name="module"></a>
|
|
||||||
<a name="injector"></a>
|
|
||||||
# Modules and the Injector
|
|
||||||
|
|
||||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
|
||||||
|
|
||||||
The {@link api/AUTO.$injector injector} is a service locator. There is a single
|
|
||||||
{@link api/AUTO.$injector injector} per Angular {@link
|
|
||||||
api/ng.directive:ngApp application}. The {@link
|
|
||||||
api/AUTO.$injector injector} provides a way to look up an object instance by its
|
|
||||||
name. The injector keeps an internal cache of all objects so that repeated calls to get the same
|
|
||||||
object name result in the same instance. If the object does not exist, then the {@link
|
|
||||||
api/AUTO.$injector injector} asks the instance factory to create a new instance.
|
|
||||||
|
|
||||||
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
|
|
||||||
as a {@link api/AUTO.$provide provider}.
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
// Create a module
|
|
||||||
var myModule = angular.module('myModule', [])
|
|
||||||
|
|
||||||
// Configure the injector
|
|
||||||
myModule.factory('serviceA', function() {
|
|
||||||
return {
|
|
||||||
// instead of {}, put your object creation here
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// create an injector and configure it from 'myModule'
|
|
||||||
var $injector = angular.injector(['myModule']);
|
|
||||||
|
|
||||||
// retrieve an object from the injector by name
|
|
||||||
var serviceA = $injector.get('serviceA');
|
|
||||||
|
|
||||||
// always true because of instance cache
|
|
||||||
$injector.get('serviceA') === $injector.get('serviceA');
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
|
|
||||||
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
|
|
||||||
used to {@link api/AUTO.$injector#methods_invoke call} methods and {@link
|
|
||||||
api/AUTO.$injector#methods_instantiate instantiate} types. This subtle feature is what
|
|
||||||
allows the methods and types to ask for their dependencies instead of having to look for them.
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
// You write functions such as this one.
|
|
||||||
function doSomething(serviceA, serviceB) {
|
|
||||||
// do something here.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angular provides the injector for your application
|
|
||||||
var $injector = ...;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////
|
|
||||||
// the old-school way of getting dependencies.
|
|
||||||
var serviceA = $injector.get('serviceA');
|
|
||||||
var serviceB = $injector.get('serviceB');
|
|
||||||
|
|
||||||
// now call the function
|
|
||||||
doSomething(serviceA, serviceB);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////
|
|
||||||
// the cool way of getting dependencies.
|
|
||||||
// the $injector will supply the arguments to the function automatically
|
|
||||||
$injector.invoke(doSomething); // This is how the framework calls your functions
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
Notice that the only thing you needed to write was the function, and list the dependencies in the
|
|
||||||
function arguments. When angular calls the function, it will use the {@link
|
|
||||||
api/AUTO.$injector#methods_invoke call} which will automatically fill the function
|
|
||||||
arguments.
|
|
||||||
|
|
||||||
Examine the `ClockCtrl` below, and notice how it lists the dependencies in the constructor. When the
|
|
||||||
{@link api/ng.directive:ngController ng-controller} instantiates
|
|
||||||
the controller it automatically provides the dependencies. There is no need to create
|
|
||||||
dependencies, look for dependencies, or even get a reference to the injector.
|
|
||||||
|
|
||||||
<example module="timeExampleModule">
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-controller="ClockCtrl">
|
|
||||||
Current time is: {{ time.now }}
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
<file name="script.js">
|
|
||||||
angular.module('timeExampleModule', []).
|
|
||||||
// Declare new object called time,
|
|
||||||
// which will be available for injection
|
|
||||||
factory('time', function($timeout) {
|
|
||||||
var time = {};
|
|
||||||
|
|
||||||
(function tick() {
|
|
||||||
time.now = new Date().toString();
|
|
||||||
$timeout(tick, 1000);
|
|
||||||
})();
|
|
||||||
return time;
|
|
||||||
});
|
});
|
||||||
|
</file>
|
||||||
// Notice that you can simply ask for time
|
<file name="index.html">
|
||||||
// and it will be provided. No need to look for it.
|
<div ng-controller="InvoiceController as invoice">
|
||||||
function ClockCtrl($scope, time) {
|
<b>Invoice:</b>
|
||||||
$scope.time = time;
|
<div>
|
||||||
}
|
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Costs: <input type="number" ng-model="invoice.cost" required >
|
||||||
|
<select ng-model="invoice.inCurr">
|
||||||
|
<option ng-repeat="c in invoice.currencies">{{c}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Total:</b>
|
||||||
|
<span ng-repeat="c in invoice.currencies">
|
||||||
|
{{invoice.total(c) | currency:c}}
|
||||||
|
</span>
|
||||||
|
<button ng-click="invoice.pay()">Pay</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</file>
|
</file>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
What changed?
|
||||||
|
|
||||||
<a name="angular_namespace"></a>
|
First, there is a new JavaScript file that contains a so called <a name="controller">"{@link controller controller}"</a>.
|
||||||
# Angular Namespace
|
More exactly, the file contains a constructor function that creates the actual controller instance.
|
||||||
|
The purpose of controllers is to expose variables and functionality to expressions and directives.
|
||||||
|
|
||||||
|
Besides the new file that contains the controller code we also added a
|
||||||
|
{@link api/ng.directive:ngController `ng-controller`} directive to the HTML.
|
||||||
|
This directive tells angular that the new `InvoiceController` is responsible for the element with the directive
|
||||||
|
and all of the element's children.
|
||||||
|
The syntax `InvoiceController as invoice` tells Angular to instantiate the controller
|
||||||
|
and save it in the variable `invoice` in the current scope.
|
||||||
|
|
||||||
|
We also changed all expressions in the page to read and write variables within that
|
||||||
|
controller instance by prefixing them with `invoice.` . The possible currencies are defined in the controller
|
||||||
|
and added to the template using {@link api/ng.directive:ngRepeat `ng-repeat`}.
|
||||||
|
As the controller contains a `total` function
|
||||||
|
we are also able to bind the result of that function to the DOM using `{{ invoice.total(...) }}`.
|
||||||
|
|
||||||
|
Again, this binding is live, i.e. the DOM will be automatically updated
|
||||||
|
whenever the result of the function changes.
|
||||||
|
The button to pay the invoice uses the directive {@link api/ng.directive:ngClick `ngClick`}. This will evaluate the
|
||||||
|
corresponding expression whenever the button is clicked.
|
||||||
|
|
||||||
|
In the new JavaScript file we are also creating a {@link concepts#module module}
|
||||||
|
at which we register the controller. We will talk about modules in the next section.
|
||||||
|
|
||||||
|
The following graphic shows how everything works together after we introduced the controller:
|
||||||
|
|
||||||
|
<img style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding2.png">
|
||||||
|
|
||||||
|
# View independent business logic: Services
|
||||||
|
|
||||||
|
Right now, the `InvoiceController` contains all logic of our example. When the application grows it
|
||||||
|
is a good practise to move view independent logic from the controller into a so called
|
||||||
|
<a name="service">"{@link dev_guide.services service}"</a>, so it can be reused by other parts
|
||||||
|
of the application as well. Later on, we could also change that service to load the exchange rates
|
||||||
|
from the web, e.g. by calling the Yahoo Finance API, without changing the controller.
|
||||||
|
|
||||||
|
Let's refactor our example and move the currency conversion into a service in another file:
|
||||||
|
|
||||||
|
<example module="invoice2">
|
||||||
|
<file name="finance2.js">
|
||||||
|
angular.module('finance2', [])
|
||||||
|
.factory('currencyConverter', function() {
|
||||||
|
var currencies = ['USD', 'EUR', 'CNY'],
|
||||||
|
usdToForeignRates = {
|
||||||
|
USD: 1,
|
||||||
|
EUR: 0.74,
|
||||||
|
CNY: 6.09
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
currencies: currencies,
|
||||||
|
convert: convert
|
||||||
|
};
|
||||||
|
|
||||||
|
function convert(amount, inCurr, outCurr) {
|
||||||
|
return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</file>
|
||||||
|
<file name="invoice2.js">
|
||||||
|
angular.module('invoice2', ['finance2'])
|
||||||
|
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
|
||||||
|
this.qty = 1;
|
||||||
|
this.cost = 2;
|
||||||
|
this.inCurr = 'EUR';
|
||||||
|
this.currencies = currencyConverter.currencies;
|
||||||
|
|
||||||
|
this.total = function total(outCurr) {
|
||||||
|
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
|
||||||
|
};
|
||||||
|
this.pay = function pay() {
|
||||||
|
window.alert("Thanks!");
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
</file>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="InvoiceController as invoice">
|
||||||
|
<b>Invoice:</b>
|
||||||
|
<div>
|
||||||
|
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Costs: <input type="number" ng-model="invoice.cost" required >
|
||||||
|
<select ng-model="invoice.inCurr">
|
||||||
|
<option ng-repeat="c in invoice.currencies">{{c}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Total:</b>
|
||||||
|
<span ng-repeat="c in invoice.currencies">
|
||||||
|
{{invoice.total(c) | currency:c}}
|
||||||
|
</span>
|
||||||
|
<button ng-click="invoice.pay()">Pay</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-service.png">
|
||||||
|
|
||||||
|
What changed?
|
||||||
|
We moved the `convertCurrency` function and the definition of the existing currencies
|
||||||
|
into the new file `finance.js`. But how does the controller
|
||||||
|
get a hold of the now separated function?
|
||||||
|
|
||||||
|
This is where <a name="di">"{@link di Dependency Injection}"</a> comes into play.
|
||||||
|
Dependency Injection (DI) is a software design pattern that
|
||||||
|
deals with how objects and functions get created and how they get a hold of their dependencies.
|
||||||
|
Everything within Angular (directives, filters, controllers,
|
||||||
|
services, ...) is created and wired using dependency injection. Within Angular,
|
||||||
|
the DI container is called the <a name="injector">"{@link di injector}"</a>.
|
||||||
|
|
||||||
|
To use DI, there needs to be a place where all the things that should work together are registered.
|
||||||
|
In Angular, this is the purpose of the so called <a name="module">"{@link module modules}"</a>.
|
||||||
|
When Angular starts, it will use the configuration of the module with the name defined by the `ng-app` directive,
|
||||||
|
including the configuration of all modules that this module depends on.
|
||||||
|
|
||||||
|
In the example above:
|
||||||
|
The template contains the directive `ng-app="invoice"`. This tells Angular
|
||||||
|
to use the `invoice` module as the main module for the application.
|
||||||
|
The code snippet `angular.module('invoice', ['finance'])` specifies that the `invoice` module depends on the
|
||||||
|
`finance` module. By this, Angular uses the `InvoiceController` as well as the `currencyConverter` service.
|
||||||
|
|
||||||
|
Now that Angular knows of all the parts of the application, it needs to create them.
|
||||||
|
In the previous section we saw that controllers are created using a factory function.
|
||||||
|
For services there are multiple ways to define their factory
|
||||||
|
(see the {@link dev_guide.services service guide}).
|
||||||
|
In the example above, we are using a function that returns the `currencyConverter` function as the factory
|
||||||
|
for the service.
|
||||||
|
|
||||||
|
Back to the initial question: How does the `InvoiceController` get a reference to the `currencyConverter` function?
|
||||||
|
In Angular, this is done by simply defining arguments on the constructor function. With this, the injector
|
||||||
|
is able to create the objects in the right order and pass the previously created objects into the
|
||||||
|
factories of the objects that depend on them.
|
||||||
|
In our example, the `InvoiceController` has an argument named `currencyConverter`. By this, Angular knows about the
|
||||||
|
dependency between the controller and the service and calls the controller with the service instance as argument.
|
||||||
|
|
||||||
|
The last thing that changed in the example between the previous section and this section is that we
|
||||||
|
now pass an array to the `module.controller` function, instead of a plain function. The array first
|
||||||
|
contains the names of the service dependencies that the controller needs. The last entry
|
||||||
|
in the array is the controller constructor function.
|
||||||
|
Angular uses this array syntax to define the dependencies so that the DI also works after minifying
|
||||||
|
the code, which will most probably rename the argument name of the controller constructor function
|
||||||
|
to something shorter like `a`.
|
||||||
|
|
||||||
|
# Accessing the backend
|
||||||
|
|
||||||
|
Let's finish our example by fetching the exchange rates from the Yahoo Finance API.
|
||||||
|
The following example shows how this is done with Angular:
|
||||||
|
|
||||||
|
<example module="invoice3">
|
||||||
|
<file name="invoice3.js">
|
||||||
|
angular.module('invoice3', ['finance3'])
|
||||||
|
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
|
||||||
|
this.qty = 1;
|
||||||
|
this.cost = 2;
|
||||||
|
this.inCurr = 'EUR';
|
||||||
|
this.currencies = currencyConverter.currencies;
|
||||||
|
|
||||||
|
this.total = function total(outCurr) {
|
||||||
|
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
|
||||||
|
};
|
||||||
|
this.pay = function pay() {
|
||||||
|
window.alert("Thanks!");
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
</file>
|
||||||
|
<file name="finance3.js">
|
||||||
|
angular.module('finance3', [])
|
||||||
|
.factory('currencyConverter', ['$http', function($http) {
|
||||||
|
var YAHOO_FINANCE_URL_PATTERN =
|
||||||
|
'http://query.yahooapis.com/v1/public/yql?q=select * from '+
|
||||||
|
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
|
||||||
|
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK',
|
||||||
|
currencies = ['USD', 'EUR', 'CNY'],
|
||||||
|
usdToForeignRates = {};
|
||||||
|
refresh();
|
||||||
|
return {
|
||||||
|
currencies: currencies,
|
||||||
|
convert: convert,
|
||||||
|
refresh: refresh
|
||||||
|
};
|
||||||
|
|
||||||
|
function convert(amount, inCurr, outCurr) {
|
||||||
|
return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
var url = YAHOO_FINANCE_URL_PATTERN.
|
||||||
|
replace('PAIRS', 'USD' + currencies.join('","USD'));
|
||||||
|
return $http.jsonp(url).success(function(data) {
|
||||||
|
var newUsdToForeignRates = {};
|
||||||
|
angular.forEach(data.query.results.rate, function(rate) {
|
||||||
|
var currency = rate.id.substring(3,6);
|
||||||
|
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
|
||||||
|
});
|
||||||
|
usdToForeignRates = newUsdToForeignRates;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
</file>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="InvoiceController as invoice">
|
||||||
|
<b>Invoice:</b>
|
||||||
|
<div>
|
||||||
|
Quantity: <input type="number" ng-model="invoice.qty" required >
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Costs: <input type="number" ng-model="invoice.cost" required >
|
||||||
|
<select ng-model="invoice.inCurr">
|
||||||
|
<option ng-repeat="c in invoice.currencies">{{c}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Total:</b>
|
||||||
|
<span ng-repeat="c in invoice.currencies">
|
||||||
|
{{invoice.total(c) | currency:c}}
|
||||||
|
</span>
|
||||||
|
<button ng-click="invoice.pay()">Pay</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
What changed?
|
||||||
|
Our `currencyConverter` service of the `finance` module now uses the
|
||||||
|
{@link api/ng.$http $http} service, a builtin service provided by Angular
|
||||||
|
for accessing the backend. It is a wrapper around [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
|
||||||
|
and [JSONP](http://en.wikipedia.org/wiki/JSONP) transports. Details can be found in the api docs of that service.
|
||||||
|
|
||||||
To prevent accidental name collision, Angular prefixes names of objects which could potentially
|
|
||||||
collide with `$`. Please do not use the `$` prefix in your code as it may accidentally collide
|
|
||||||
with Angular code.
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
@ngdoc overview
|
@ngdoc overview
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
@name Controllers
|
||||||
@description
|
@description
|
||||||
|
|
||||||
# Understanding Controllers
|
# Understanding Controllers
|
||||||
|
|
@ -85,7 +85,7 @@ expression in the template:
|
||||||
</div>
|
</div>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
As discussed in the {@link concepts Concepts} section of this guide, any
|
||||||
objects (or primitives) assigned to the scope become model properties. Any methods assigned to
|
objects (or primitives) assigned to the scope become model properties. Any methods assigned to
|
||||||
the scope are available in the template/view, and can be invoked via angular expressions
|
the scope are available in the template/view, and can be invoked via angular expressions
|
||||||
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
|
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
|
||||||
|
|
@ -105,7 +105,7 @@ 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
|
||||||
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
|
logic. Angular offers {@link databinding databinding} for automatic DOM manipulation. If
|
||||||
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
||||||
{@link guide/directive directives}.
|
{@link guide/directive directives}.
|
||||||
- Input formatting — Use {@link forms angular form controls} instead.
|
- Input formatting — Use {@link forms angular form controls} instead.
|
||||||
|
|
@ -126,7 +126,7 @@ directive} or {@link api/ngRoute.$route $route service}.
|
||||||
To illustrate further how Controller components work in Angular, let's create a little app with the
|
To illustrate further how Controller components work 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 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`
|
||||||
|
|
||||||
|
|
@ -337,10 +337,4 @@ describe('state', function() {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc About MVC in Angular}
|
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
@ngdoc overview
|
@ngdoc overview
|
||||||
@name Developer Guide: Templates: Data Binding in Angular
|
@name Data Binding
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Data-binding in Angular web apps is the automatic synchronization of data between the model and view
|
Data-binding in Angular web apps is the automatic synchronization of data between the model and view
|
||||||
|
|
@ -35,4 +35,4 @@ isolation without the view and the related DOM/browser dependency.
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
* {@link scope Angular Scopes}
|
* {@link scope Angular Scopes}
|
||||||
* {@link dev_guide.templates Angular Templates}
|
* {@link templates Angular Templates}
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: About MVC in Angular
|
|
||||||
@description
|
|
||||||
|
|
||||||
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
|
|
||||||
http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of
|
|
||||||
building client-side web applications.
|
|
||||||
|
|
||||||
The MVC pattern summarized:
|
|
||||||
|
|
||||||
* Separate applications into distinct presentation, data, and logic components
|
|
||||||
* Encourage loose coupling between these components
|
|
||||||
|
|
||||||
Along with {@link dev_guide.services services} and {@link di dependency injection}, MVC
|
|
||||||
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
|
|
||||||
developing web applications:
|
|
||||||
|
|
||||||
* {@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_view Understanding the View Component}
|
|
||||||
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
|
||||||
@description
|
|
||||||
|
|
||||||
Depending on the context of the discussion in the Angular documentation, the term _model_ can refer to
|
|
||||||
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).
|
|
||||||
|
|
||||||
In Angular, a model is any data that is reachable as a property of an angular {@link
|
|
||||||
scope Scope} object. The name of the property is the model identifier and the value is
|
|
||||||
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
|
|
||||||
referenced by an Angular scope as a property of that scope object. This property reference can be
|
|
||||||
created explicitly or implicitly.
|
|
||||||
|
|
||||||
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
|
||||||
following ways:
|
|
||||||
|
|
||||||
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
|
|
||||||
occurs in controllers:
|
|
||||||
|
|
||||||
function MyCtrl($scope) {
|
|
||||||
// create property 'foo' on the MyCtrl's scope
|
|
||||||
// and assign it an initial value 'bar'
|
|
||||||
$scope.foo = 'bar';
|
|
||||||
}
|
|
||||||
|
|
||||||
* Use an {@link expression angular expression} with an assignment operator in templates:
|
|
||||||
|
|
||||||
<button ng-click="{{foo='bar'}}">Click me</button>
|
|
||||||
|
|
||||||
* Use {@link api/ng.directive:ngInit ngInit directive} in templates (for toy/example apps
|
|
||||||
only, not recommended for real applications):
|
|
||||||
|
|
||||||
<body ng-init=" foo = 'bar' ">
|
|
||||||
|
|
||||||
Angular creates models implicitly (by creating a scope property and assigning it a suitable value)
|
|
||||||
when processing the following template constructs:
|
|
||||||
|
|
||||||
* Form input, select, textarea and other form elements:
|
|
||||||
|
|
||||||
<input ng-model="query" value="fluffy cloud">
|
|
||||||
|
|
||||||
The code above creates a model called "query" on the current scope with the value set to "fluffy
|
|
||||||
cloud".
|
|
||||||
|
|
||||||
* An iterator declaration in {@link api/ng.directive:ngRepeat ngRepeater}:
|
|
||||||
|
|
||||||
<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"
|
|
||||||
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:
|
|
||||||
|
|
||||||
* 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
|
|
||||||
garbage collection.
|
|
||||||
|
|
||||||
The following illustration shows a simple data model created implicitly from a simple template:
|
|
||||||
|
|
||||||
<img src="img/guide/about_model_final.png">
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc About MVC in Angular}
|
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the View Component
|
|
||||||
@description
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
<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.
|
|
||||||
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/ng.directive:ngController
|
|
||||||
ngController} and {@link api/ngRoute.directive:ngView ngView}, and through bindings of this form:
|
|
||||||
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
|
|
||||||
controller function.
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc About MVC in Angular}
|
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
|
||||||
|
|
@ -13,7 +13,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s
|
||||||
|
|
||||||
* `ng-binding`
|
* `ng-binding`
|
||||||
- **Usage:** angular applies this class to any element that is attached to a data binding, via `ng-bind` or
|
- **Usage:** angular applies this class to any element that is attached to a data binding, via `ng-bind` or
|
||||||
{{}} curly braces, for example. (see {@link guide/dev_guide.templates.databinding databinding} guide)
|
{{}} curly braces, for example. (see {@link guide/databinding databinding} guide)
|
||||||
|
|
||||||
* `ng-invalid`, `ng-valid`
|
* `ng-invalid`, `ng-valid`
|
||||||
- **Usage:** angular applies this class to an input widget element if that element's input does
|
- **Usage:** angular applies this class to an input widget element if that element's input does
|
||||||
|
|
@ -27,5 +27,5 @@ Angular sets these CSS classes. It is up to your application to provide useful s
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
* {@link dev_guide.templates Angular Templates}
|
* {@link templates Angular Templates}
|
||||||
* {@link forms Angular Forms}
|
* {@link forms Angular Forms}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ is simply handed the `greeter` at runtime.
|
||||||
This is desirable, but it puts the responsibility of getting hold of the dependency on the
|
This is desirable, but it puts the responsibility of getting hold of the dependency on the
|
||||||
code that constructs `SomeClass`.
|
code that constructs `SomeClass`.
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
||||||
|
|
||||||
To manage the responsibility of dependency creation, each Angular application has an {@link
|
To manage the responsibility of dependency creation, each Angular application has an {@link
|
||||||
api/angular.injector injector}. The injector is a service locator that is responsible for
|
api/angular.injector injector}. The injector is a service locator that is responsible for
|
||||||
construction and lookup of dependencies.
|
construction and lookup of dependencies.
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
Everything you need to know about AngularJS
|
Everything you need to know about AngularJS
|
||||||
|
|
||||||
## First steps
|
* {@link guide/introduction What is AngularJS?}
|
||||||
|
|
||||||
Just starting with Angular? These links will give you a solid foundation to start building apps.
|
* {@link guide/concepts Conceptual Overview}
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
* {@link tutorial/index Official AngularJS Tutorial}
|
* {@link tutorial/index Official AngularJS Tutorial}
|
||||||
|
|
||||||
|
|
@ -26,7 +28,7 @@ Just starting with Angular? These links will give you a solid foundation to sta
|
||||||
|
|
||||||
In Angular applications, you move the job of filling page templates with data from the server to the client. The result is a system better structured for dynamic page updates. Below are the core features you'll use.
|
In Angular applications, you move the job of filling page templates with data from the server to the client. The result is a system better structured for dynamic page updates. Below are the core features you'll use.
|
||||||
|
|
||||||
* {@link guide/dev_guide.templates.databinding Data binding}
|
* {@link guide/databinding Data binding}
|
||||||
|
|
||||||
* {@link guide/expression Expressions}
|
* {@link guide/expression Expressions}
|
||||||
|
|
||||||
|
|
@ -42,8 +44,6 @@ In Angular applications, you move the job of filling page templates with data fr
|
||||||
|
|
||||||
* **Blog post: **[When to use directives, controllers or services](http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/)
|
* **Blog post: **[When to use directives, controllers or services](http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/)
|
||||||
|
|
||||||
* **Separation of concerns:** {@link guide/dev_guide.mvc Model-View-Controller}
|
|
||||||
|
|
||||||
* **App wiring:** {@link guide/di Dependency injection}
|
* **App wiring:** {@link guide/di Dependency injection}
|
||||||
|
|
||||||
* **Exposing model to templates:** {@link guide/scope Scopes}
|
* **Exposing model to templates:** {@link guide/scope Scopes}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,114 @@
|
||||||
@ngdoc overview
|
@ngdoc overview
|
||||||
@name Developer Guide: Introduction
|
@name Introduction
|
||||||
@description
|
@description
|
||||||
|
|
||||||
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 apps easier and faster than ever before.
|
|
||||||
|
|
||||||
One important way that Angular simplifies web development is by increasing the level of abstraction
|
# What Is Angular?
|
||||||
between the developer and most low-level web app development tasks. Angular automatically takes
|
|
||||||
care of many of these tasks, including:
|
|
||||||
|
|
||||||
* DOM Manipulation
|
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
|
||||||
* Setting Up Listeners and Notifiers
|
language and lets you extend HTML's syntax to express your application's components clearly and
|
||||||
* Input Validation
|
succinctly. Out of the box, it eliminates much of the code you currently write through data
|
||||||
|
binding and dependency injection. And it all happens in JavaScript within the browser, making it
|
||||||
|
an ideal partner with any server technology.
|
||||||
|
|
||||||
Because Angular handles much of the work involved in these tasks, developers can concentrate more
|
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
||||||
on application logic and less on repetitive, error-prone, lower-level coding.
|
declarative language for static documents. It does not contain much in the way of creating
|
||||||
|
applications, and as a result building web applications is an exercise in *what do I have to do
|
||||||
|
to trick the browser into doing what I want.*
|
||||||
|
|
||||||
At the same time that Angular simplifies the development of web apps, it brings relatively
|
The impedance mismatch between dynamic applications and static documents is often solved with:
|
||||||
sophisticated techniques to the client-side, including:
|
|
||||||
|
|
||||||
* Separation of data, application logic, and presentation components
|
* **a library** - a collection of functions which are useful when writing web apps. Your code is
|
||||||
* Data Binding between data and presentation components
|
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
|
||||||
* Services (common web app operations, implemented as substitutable objects)
|
* **frameworks** - a particular implementation of a web application, where your code fills in
|
||||||
* Dependency Injection (used primarily for wiring together services)
|
the details. The framework is in charge and it calls into your code when it needs something
|
||||||
* An extensible HTML compiler (written entirely in JavaScript)
|
app specific. E.g., `knockout`, `ember`, etc.
|
||||||
* Ease of Testing
|
|
||||||
|
|
||||||
These techniques have been for the most part absent from the client-side for far too long.
|
|
||||||
|
|
||||||
## Single-page / Round-trip Applications
|
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
||||||
|
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
|
||||||
|
browser new syntax through a construct we call directives. Examples include:
|
||||||
|
|
||||||
You can use Angular to develop both single-page and round-trip apps, but Angular is designed
|
* Data binding, as in `{{}}`.
|
||||||
primarily for developing single-page apps. Angular supports browser history, forward and back
|
* DOM control structures for repeating/hiding DOM fragments.
|
||||||
buttons, and bookmarking in single-page apps.
|
* Support for forms and form validation.
|
||||||
|
* Attaching code-behind to DOM elements.
|
||||||
|
* Grouping of HTML into reusable components.
|
||||||
|
|
||||||
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's features (for example, templates to leverage angular's data-binding feature) to an
|
## A complete client-side solution
|
||||||
existing round-trip app. You might follow this course of action if you were migrating an older app
|
|
||||||
to a single-page Angular app.
|
Angular is not a single piece in the overall puzzle of building the client-side of a web
|
||||||
|
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
|
||||||
|
well-defined structure. This makes Angular opinionated about how a CRUD application should be
|
||||||
|
built. But while it is opinionated, it also tries to make sure that its opinion is just a
|
||||||
|
starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||||
|
|
||||||
|
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
|
||||||
|
directives, form validation, routing, deep-linking, reusable components, dependency injection.
|
||||||
|
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
|
||||||
|
* Seed application with directory layout and test scripts as a starting point.
|
||||||
|
|
||||||
|
|
||||||
|
## Angular Sweet Spot
|
||||||
|
|
||||||
|
Angular simplifies application development by presenting a higher level of abstraction to the
|
||||||
|
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
|
||||||
|
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
|
||||||
|
applications represent the majority of web applications. To understand what Angular is
|
||||||
|
good at, though, it helps to understand when an app is not a good fit for Angular.
|
||||||
|
|
||||||
|
Games and GUI editors are examples of applications with intensive and tricky DOM manipulation.
|
||||||
|
These kinds of apps are different from CRUD apps, and as a result are probably not a good fit for Angular.
|
||||||
|
In these cases it may be better to use a library with a lower level of abstraction, such as `jQuery`.
|
||||||
|
|
||||||
|
# The Zen of Angular
|
||||||
|
|
||||||
|
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
|
||||||
|
expressing business logic.
|
||||||
|
|
||||||
|
|
||||||
|
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
|
||||||
|
the testability of the code.
|
||||||
|
* It is a really, _really_ good idea to regard app testing as equal in importance to app
|
||||||
|
writing. Testing difficulty is dramatically affected by the way the code is structured.
|
||||||
|
* It is an excellent idea to decouple the client side of an app from the server side. This
|
||||||
|
allows development work to progress in parallel, and allows for reuse of both sides.
|
||||||
|
* It is very helpful indeed if the framework guides developers through the entire journey of
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Angular frees you from the following pains:
|
||||||
|
|
||||||
|
* **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 reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see
|
||||||
|
what your application does.
|
||||||
|
* **Manipulating HTML DOM programmatically:** Manipulating HTML DOM is a cornerstone of AJAX
|
||||||
|
applications, but it's cumbersome and error-prone. By declaratively describing how the UI
|
||||||
|
should change as your application state changes, you are freed from low-level DOM manipulation
|
||||||
|
tasks. Most applications written with Angular never have to programmatically manipulate the
|
||||||
|
DOM, although you can if you want to.
|
||||||
|
* **Marshaling data to and from the UI:** CRUD operations make up the majority of AJAX
|
||||||
|
applications' tasks. The flow of marshaling data from the server to an internal object to an HTML
|
||||||
|
form, allowing users to modify the form, validating the form, displaying validation errors,
|
||||||
|
returning to an internal model, and then back to the server, creates a lot of boilerplate
|
||||||
|
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
|
||||||
|
overall flow of the application rather than all of the implementation details.
|
||||||
|
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
|
||||||
|
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
|
||||||
|
your app easily using services, which are auto-injected into your application in a {@link
|
||||||
|
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
|
||||||
|
to get started developing features quickly. As a bonus, you get full control over the
|
||||||
|
initialization process in automated tests.
|
||||||
|
|
||||||
|
|
||||||
|
# Watch a Presentation About Angular
|
||||||
|
|
||||||
|
Here is a presentation on Angular from May 2012. The {@link http://mhevery.github.io/angular-demo-slides/index.html#/list corresponding slides} are also available.
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: Overview
|
|
||||||
@description
|
|
||||||
|
|
||||||
|
|
||||||
# What Is Angular?
|
|
||||||
|
|
||||||
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
|
|
||||||
language and lets you extend HTML's syntax to express your application's components clearly and
|
|
||||||
succinctly. Out of the box, it eliminates much of the code you currently write through data
|
|
||||||
binding and dependency injection. And it all happens in JavaScript within the browser, making it
|
|
||||||
an ideal partner with any server technology.
|
|
||||||
|
|
||||||
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
|
||||||
declarative language for static documents. It does not contain much in the way of creating
|
|
||||||
applications, and as a result building web applications is an exercise in *what do I have to do
|
|
||||||
to trick the browser into doing what I want.*
|
|
||||||
|
|
||||||
The impedance mismatch between dynamic applications and static documents is often solved with:
|
|
||||||
|
|
||||||
* **a library** - a collection of functions which are useful when writing web apps. Your code is
|
|
||||||
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
|
|
||||||
* **frameworks** - a particular implementation of a web application, where your code fills in
|
|
||||||
the details. The framework is in charge and it calls into your code when it needs something
|
|
||||||
app specific. E.g., `knockout`, `ember`, etc.
|
|
||||||
|
|
||||||
|
|
||||||
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
|
||||||
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
|
|
||||||
browser new syntax through a construct we call directives. Examples include:
|
|
||||||
|
|
||||||
* Data binding, as in `{{}}`.
|
|
||||||
* DOM control structures for repeating/hiding DOM fragments.
|
|
||||||
* Support for forms and form validation.
|
|
||||||
* Attaching code-behind to DOM elements.
|
|
||||||
* Grouping of HTML into reusable components.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## A complete client-side solution
|
|
||||||
|
|
||||||
Angular is not a single piece in the overall puzzle of building the client-side of a web
|
|
||||||
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
|
|
||||||
well-defined structure. This makes Angular opinionated about how a CRUD application should be
|
|
||||||
built. But while it is opinionated, it also tries to make sure that its opinion is just a
|
|
||||||
starting point you can easily change. Angular comes with the following out-of-the-box:
|
|
||||||
|
|
||||||
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
|
|
||||||
directives, form validation, routing, deep-linking, reusable components, dependency injection.
|
|
||||||
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
|
|
||||||
* Seed application with directory layout and test scripts as a starting point.
|
|
||||||
|
|
||||||
|
|
||||||
## Angular Sweet Spot
|
|
||||||
|
|
||||||
Angular simplifies application development by presenting a higher level of abstraction to the
|
|
||||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
|
|
||||||
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
|
|
||||||
applications represent the majority of web applications. To understand what Angular is
|
|
||||||
good at, though, it helps to understand when an app is not a good fit for Angular.
|
|
||||||
|
|
||||||
Games and GUI editors are examples of applications with intensive and tricky DOM manipulation.
|
|
||||||
These kinds of apps are different from CRUD apps, and as a result are probably not a good fit for Angular.
|
|
||||||
In these cases it may be better to use a library with a lower level of abstraction, such as `jQuery`.
|
|
||||||
|
|
||||||
|
|
||||||
# An Introductory Angular Example
|
|
||||||
|
|
||||||
Below is a typical CRUD application which contains a form. The form values are validated, and
|
|
||||||
are used to compute the total, which is formatted to a particular locale. These are some common
|
|
||||||
concepts which the application developer may face:
|
|
||||||
|
|
||||||
* attaching a data-model to the UI.
|
|
||||||
* writing, reading and validating user input.
|
|
||||||
* computing new values based on the model.
|
|
||||||
* formatting output in a user specific locale.
|
|
||||||
|
|
||||||
<example>
|
|
||||||
<file name="script.js">
|
|
||||||
function InvoiceCntl($scope) {
|
|
||||||
$scope.qty = 1;
|
|
||||||
$scope.cost = 19.95;
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
<file name="index.html">
|
|
||||||
<div ng-controller="InvoiceCntl">
|
|
||||||
<b>Invoice:</b>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Quantity</td>
|
|
||||||
<td>Cost</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required ></td>
|
|
||||||
<td><input type="number" ng-model="cost" required ></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<b>Total:</b> {{qty * cost | currency}}
|
|
||||||
</div>
|
|
||||||
</file>
|
|
||||||
<file name="scenario.js">
|
|
||||||
it('should show off angular binding', function() {
|
|
||||||
expect(binding('qty * cost')).toEqual('$19.95');
|
|
||||||
input('qty').enter('2');
|
|
||||||
input('cost').enter('5.00');
|
|
||||||
expect(binding('qty * cost')).toEqual('$10.00');
|
|
||||||
});
|
|
||||||
</file>
|
|
||||||
</example>
|
|
||||||
|
|
||||||
Try out the Live Preview above, and then let's walk through the example and describe what's going
|
|
||||||
on.
|
|
||||||
|
|
||||||
In the `<html>` tag, we specify that it is an Angular
|
|
||||||
application with the `ng-app` directive. The `ng-app` will cause Angular to {@link
|
|
||||||
bootstrap auto initialize} your application.
|
|
||||||
|
|
||||||
<html ng-app>
|
|
||||||
|
|
||||||
We load Angular using the `<script>` tag:
|
|
||||||
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
|
|
||||||
|
|
||||||
From the `ng-model` attribute of the `<input>` tags, Angular automatically sets up two-way data
|
|
||||||
binding, and we also demonstrate some easy input validation:
|
|
||||||
|
|
||||||
Quantity: <input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required >
|
|
||||||
Cost: <input type="number" ng-model="cost" required >
|
|
||||||
|
|
||||||
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
|
|
||||||
variables of the same name. Think of those variables as the "Model" component of the
|
|
||||||
Model-View-Controller design pattern.
|
|
||||||
* Note that the HTML widget {@link api/ng.directive:input input}
|
|
||||||
has special powers. The input invalidates itself by turning red when you enter invalid data or
|
|
||||||
leave the input fields blank. These new widget behaviors make it easier to implement field
|
|
||||||
validation, which is common in CRUD applications.
|
|
||||||
|
|
||||||
And finally, the mysterious `{{ double curly braces }}`:
|
|
||||||
|
|
||||||
Total: {{qty * cost | currency}}
|
|
||||||
|
|
||||||
This notation, `{{ _expression_ }}`, is Angular markup for data-binding. The expression itself can
|
|
||||||
be a combination of both an expression and a {@link dev_guide.templates.filters filter}: `{{
|
|
||||||
expression | filter }}`. Angular provides filters for formatting display data.
|
|
||||||
|
|
||||||
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
|
|
||||||
into output that looks like money."
|
|
||||||
|
|
||||||
Notice that we achieved this application behavior neither by calling Angular methods, nor by
|
|
||||||
implementing application specific behavior as a framework. We achieved the behavior because the
|
|
||||||
browser behaved more in line with what is needed for a dynamic web application rather than what is
|
|
||||||
needed for a static document. Angular has lowered the impedance mismatch to the point where no
|
|
||||||
library/framework calls are needed.
|
|
||||||
|
|
||||||
|
|
||||||
# The Zen of Angular
|
|
||||||
|
|
||||||
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
|
|
||||||
expressing business logic.
|
|
||||||
|
|
||||||
|
|
||||||
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
|
|
||||||
the testability of the code.
|
|
||||||
* It is a really, _really_ good idea to regard app testing as equal in importance to app
|
|
||||||
writing. Testing difficulty is dramatically affected by the way the code is structured.
|
|
||||||
* It is an excellent idea to decouple the client side of an app from the server side. This
|
|
||||||
allows development work to progress in parallel, and allows for reuse of both sides.
|
|
||||||
* It is very helpful indeed if the framework guides developers through the entire journey of
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Angular frees you from the following pains:
|
|
||||||
|
|
||||||
* **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 reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see
|
|
||||||
what your application does.
|
|
||||||
* **Manipulating HTML DOM programmatically:** Manipulating HTML DOM is a cornerstone of AJAX
|
|
||||||
applications, but it's cumbersome and error-prone. By declaratively describing how the UI
|
|
||||||
should change as your application state changes, you are freed from low-level DOM manipulation
|
|
||||||
tasks. Most applications written with Angular never have to programmatically manipulate the
|
|
||||||
DOM, although you can if you want to.
|
|
||||||
* **Marshaling data to and from the UI:** CRUD operations make up the majority of AJAX
|
|
||||||
applications' tasks. The flow of marshaling data from the server to an internal object to an HTML
|
|
||||||
form, allowing users to modify the form, validating the form, displaying validation errors,
|
|
||||||
returning to an internal model, and then back to the server, creates a lot of boilerplate
|
|
||||||
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
|
|
||||||
overall flow of the application rather than all of the implementation details.
|
|
||||||
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
|
|
||||||
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
|
|
||||||
your app easily using services, which are auto-injected into your application in a {@link
|
|
||||||
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
|
|
||||||
to get started developing features quickly. As a bonus, you get full control over the
|
|
||||||
initialization process in automated tests.
|
|
||||||
|
|
||||||
|
|
||||||
# Watch a Presentation About Angular
|
|
||||||
|
|
||||||
Here is a presentation on Angular from May 2012. The {@link http://mhevery.github.io/angular-demo-slides/index.html#/list corresponding slides} are also available.
|
|
||||||
|
|
||||||
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
|
||||||
|
|
@ -110,46 +110,46 @@ new child scopes (refer to directive documentation to see which directives creat
|
||||||
When new scopes are created, they are added as children of their parent scope. This creates a tree
|
When new scopes are created, they are added as children of their parent scope. This creates a tree
|
||||||
structure which parallels the DOM where they're attached
|
structure which parallels the DOM where they're attached
|
||||||
|
|
||||||
When Angular evaluates `{{username}}`, it first looks at the scope associated with the given
|
When Angular evaluates `{{name}}`, it first looks at the scope associated with the given
|
||||||
element for the `username` property. If no such property is found, it searches the parent scope
|
element for the `name` property. If no such property is found, it searches the parent scope
|
||||||
and so on until the root scope is reached. In JavaScript this behavior is known as prototypical
|
and so on until the root scope is reached. In JavaScript this behavior is known as prototypical
|
||||||
inheritance, and child scopes prototypically inherit from their parents.
|
inheritance, and child scopes prototypically inherit from their parents.
|
||||||
|
|
||||||
This example illustrates scopes in application, and prototypical inheritance of properties.
|
This example illustrates scopes in application, and prototypical inheritance of properties. The example is followed by
|
||||||
|
a diagram depicting the scope boundaries.
|
||||||
|
|
||||||
|
<div class="show-scope">
|
||||||
<example>
|
<example>
|
||||||
<file name="style.css">
|
|
||||||
/* remove .doc-example-live in jsfiddle */
|
|
||||||
.doc-example-live .ng-scope {
|
|
||||||
border: 1px dashed red;
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
<file name="script.js">
|
|
||||||
function EmployeeController($scope) {
|
|
||||||
$scope.department = 'Engineering';
|
|
||||||
$scope.employee = {
|
|
||||||
name: 'Joe the Manager',
|
|
||||||
reports: [
|
|
||||||
{name: 'John Smith'},
|
|
||||||
{name: 'Mary Run'}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</file>
|
|
||||||
<file name="index.html">
|
<file name="index.html">
|
||||||
<div ng-controller="EmployeeController">
|
<div ng-controller="GreetCtrl">
|
||||||
Manager: {{employee.name}} [ {{department}} ]<br>
|
Hello {{name}}!
|
||||||
Reports:
|
</div>
|
||||||
<ul>
|
<div ng-controller="ListCtrl">
|
||||||
<li ng-repeat="employee in employee.reports">
|
<ol>
|
||||||
{{employee.name}} [ {{department}} ]
|
<li ng-repeat="name in names">{{name}}</li>
|
||||||
</li>
|
</ol>
|
||||||
</ul>
|
|
||||||
<hr>
|
|
||||||
{{greeting}}
|
|
||||||
</div>
|
</div>
|
||||||
</file>
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
function GreetCtrl($scope) {
|
||||||
|
$scope.name = 'World';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListCtrl($scope) {
|
||||||
|
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
<file name="style.css">
|
||||||
|
.show-scope .doc-example-live.ng-scope,
|
||||||
|
.show-scope .doc-example-live .ng-scope {
|
||||||
|
border: 1px solid red;
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
</example>
|
</example>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img class="center" src="img/guide/concepts-scope.png">
|
||||||
|
|
||||||
Notice that Angular automatically places `ng-scope` class on elements where scopes are
|
Notice that Angular automatically places `ng-scope` class on elements where scopes are
|
||||||
attached. The `<style>` definition in this example highlights in red the new scope locations. The
|
attached. The `<style>` definition in this example highlights in red the new scope locations. The
|
||||||
|
|
@ -329,3 +329,72 @@ the dirty checking function must be efficient. Care should be taken that the dir
|
||||||
function does not do any DOM access, as DOM access is orders of magnitude slower then property
|
function does not do any DOM access, as DOM access is orders of magnitude slower then property
|
||||||
access on JavaScript object.
|
access on JavaScript object.
|
||||||
|
|
||||||
|
## Integration with the browser event loop
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
|
||||||
|
|
||||||
|
The diagram and the example below describe how Angular interacts with the browser's event loop.
|
||||||
|
|
||||||
|
1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event,
|
||||||
|
or network event (response from a server).
|
||||||
|
2. The event's callback gets executed. This enters the JavaScript context. The callback can
|
||||||
|
modify the DOM structure.
|
||||||
|
3. Once the callback executes, the browser leaves the JavaScript context and
|
||||||
|
re-renders the view based on DOM changes.
|
||||||
|
|
||||||
|
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
|
||||||
|
splits the JavaScript into classical and Angular execution context. Only operations which are
|
||||||
|
applied in Angular execution context will benefit from Angular data-binding, exception handling,
|
||||||
|
property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in
|
||||||
|
mind that in most places (controllers, services) $apply has already been called for you by the
|
||||||
|
directive which is handling the event. An explicit call to $apply is needed only when
|
||||||
|
implementing custom event callbacks, or when working with third-party library callbacks.
|
||||||
|
|
||||||
|
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
|
||||||
|
api/ng.$rootScope.Scope#methods_$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
|
||||||
|
the work you wish to do in Angular execution context.
|
||||||
|
2. Angular executes the `stimulusFn()`, which typically modifies application state.
|
||||||
|
3. Angular enters the {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop. The
|
||||||
|
loop is made up of two smaller loops which process {@link
|
||||||
|
api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue and the {@link
|
||||||
|
api/ng.$rootScope.Scope#methods_$watch $watch} list. The {@link
|
||||||
|
api/ng.$rootScope.Scope#methods_$digest $digest} loop keeps iterating until the model
|
||||||
|
stabilizes, which means that the {@link api/ng.$rootScope.Scope#methods_$evalAsync
|
||||||
|
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#methods_$watch
|
||||||
|
$watch} list does not detect any changes.
|
||||||
|
4. The {@link api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue is used to
|
||||||
|
schedule work which needs to occur outside of current stack frame, but before the browser's
|
||||||
|
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
|
||||||
|
suffers from slowness and may cause view flickering since the browser renders the view after
|
||||||
|
each event.
|
||||||
|
5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list is a set of expressions
|
||||||
|
which may have changed since last iteration. If a change is detected then the `$watch`
|
||||||
|
function is called which typically updates the DOM with the new value.
|
||||||
|
6. Once the Angular {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop finishes
|
||||||
|
the execution leaves the Angular and JavaScript context. This is followed by the browser
|
||||||
|
re-rendering the DOM to reflect any changes.
|
||||||
|
|
||||||
|
|
||||||
|
Here is the explanation of how the `Hello world` example achieves the data-binding effect when the
|
||||||
|
user enters text into the text field.
|
||||||
|
|
||||||
|
1. During the compilation phase:
|
||||||
|
1. the {@link api/ng.directive:ngModel ng-model} and {@link
|
||||||
|
api/ng.directive:input input} {@link guide/directive
|
||||||
|
directive} set up a `keydown` listener on the `<input>` control.
|
||||||
|
2. the {@link api/ng.$interpolate {{name}} } interpolation
|
||||||
|
sets up a {@link api/ng.$rootScope.Scope#methods_$watch $watch} to be notified of
|
||||||
|
`name` changes.
|
||||||
|
2. During the runtime phase:
|
||||||
|
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
|
||||||
|
2. The {@link api/ng.directive:input input} directive
|
||||||
|
captures the change to the input's value and calls {@link
|
||||||
|
api/ng.$rootScope.Scope#methods_$apply $apply}`("name = 'X';")` to update the
|
||||||
|
application model inside the Angular execution context.
|
||||||
|
3. Angular applies the `name = 'X';` to the model.
|
||||||
|
4. The {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop begins
|
||||||
|
5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list detects a change
|
||||||
|
on the `name` property and notifies the {@link api/ng.$interpolate
|
||||||
|
{{name}} } interpolation, which in turn updates the DOM.
|
||||||
|
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
|
||||||
|
the JavaScript execution context.
|
||||||
|
7. The browser re-renders the view with update text.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
@ngdoc overview
|
@ngdoc overview
|
||||||
@name Developer Guide: Understanding Angular Templates
|
@name 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
|
||||||
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 80 KiB |
BIN
docs/img/guide/concepts-databinding1.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/img/guide/concepts-databinding2.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 55 KiB |
BIN
docs/img/guide/concepts-module-service.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
|
|
@ -1181,7 +1181,7 @@ var GUIDE_PRIORITY = [
|
||||||
'dev_guide.services.$location',
|
'dev_guide.services.$location',
|
||||||
'dev_guide.services',
|
'dev_guide.services',
|
||||||
|
|
||||||
'dev_guide.templates.databinding',
|
'databinding',
|
||||||
'dev_guide.templates.css-styling',
|
'dev_guide.templates.css-styling',
|
||||||
'dev_guide.templates.filters.creating_filters',
|
'dev_guide.templates.filters.creating_filters',
|
||||||
'dev_guide.templates.filters',
|
'dev_guide.templates.filters',
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 4.5 KiB |
|
|
@ -12,7 +12,7 @@
|
||||||
* <div class="alert alert-error">
|
* <div class="alert alert-error">
|
||||||
* The only appropriate use of `ngInit` for aliasing special properties of
|
* The only appropriate use of `ngInit` for aliasing special properties of
|
||||||
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
||||||
* should use {@link guide/dev_guide.mvc.understanding_controller controllers} rather than `ngInit`
|
* should use {@link guide/controller controllers} rather than `ngInit`
|
||||||
* to initialize values on a scope.
|
* to initialize values on a scope.
|
||||||
* </div>
|
* </div>
|
||||||
*
|
*
|
||||||
|
|
|
||||||