| <a href='http://github.com/angular/angular.js/edit/master/docs/content/guide/concepts.ngdoc' class='improve-docs btn btn-primary'><i class="glyphicon glyphicon-edit"> </i>Improve this doc</a> |
| |
| |
| <h1 id="conceptual-overview">Conceptual Overview</h1> |
| <p>This section briefly touches on all of the important parts of AngularJS using a simple example. |
| For a more in-depth explanation, see the <a href="tutorial/">tutorial</a>.</p> |
| <table> |
| <thead> |
| <tr> |
| <th>Concept</th> |
| <th>Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td><a href="guide/concepts#template">Template</a></td> |
| <td>HTML with additional markup</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#directive">Directives</a></td> |
| <td>extend HTML with custom attributes and elements</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#model">Model</a></td> |
| <td>the data that is shown to the user and with which the user interacts</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#scope">Scope</a></td> |
| <td>context where the model is stored so that controllers, directives and expressions can access it</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#expression">Expressions</a></td> |
| <td>access variables and functions from the scope</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#compiler">Compiler</a></td> |
| <td>parses the template and instantiates directives and expressions</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#filter">Filter</a></td> |
| <td>formats the value of an expression for display to the user</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#view">View</a></td> |
| <td>what the user sees (the DOM)</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#databinding">Data Binding</a></td> |
| <td>sync data between the model and the view</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#controller">Controller</a></td> |
| <td>the business logic behind views</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#di">Dependency Injection</a></td> |
| <td>Creates and wires objects / functions</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#injector">Injector</a></td> |
| <td>dependency injection container</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#module">Module</a></td> |
| <td>configures the Injector</td> |
| </tr> |
| <tr> |
| <td><a href="guide/concepts#service">Service</a></td> |
| <td>reusable business logic independent of views</td> |
| </tr> |
| </tbody> |
| </table> |
| <h2 id="a-first-example-data-binding">A first example: Data binding</h2> |
| <p>In the following example we will build a form to calculate the costs of an invoice in different currencies.</p> |
| <p>Let's start with input fields for quantity and cost whose values are multiplied to produce the total of the invoice:</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-guide-concepts-1@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-guide-concepts-1" |
| name="guide-concepts-1" |
| ng-app-included="true"> |
| |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><div ng-app 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></code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-guide-concepts-1/index.html" name="example-guide-concepts-1"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <p>Try out the Live Preview above, and then let's walk through the example and describe what's going on.</p> |
| <p><img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding1.png"></p> |
| <p>This looks like normal HTML, with some new markup. In Angular, a file like this is called a |
| <a name="template">"<a href="guide/templates">template</a>"</a>. When Angular starts your application, it parses and |
| processes this new markup from the template using the so called <a name="compiler">"<a href="guide/compiler">compiler</a>"</a>. |
| The loaded, transformed and rendered DOM is then called the <a name="view">"view"</a>.</p> |
| <p>The first kind of new markup are the so called <a name="directive">"<a href="guide/directive">directives</a>"</a>. |
| They apply special behavior to attributes or elements in the HTML. In the example above we use the |
| <a href="api/ng/directive/ngApp"><code>ng-app</code></a> attribute, which is linked to a directive that automatically |
| initializes our application. Angular also defines a directive for the <a href="api/ng/directive/input"><code>input</code></a> |
| 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 <code>required</code> attribute. |
| The <a href="api/ng/directive/ngModel"><code>ng-model</code></a> 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.</p> |
| <div class="alert alert-info"> |
| <strong>Custom directives to access the DOM</strong>: In Angular, the only place where an application touches the DOM is |
| within directives. This is good as artifacts that access the DOM are hard to test. |
| If you need to access the DOM directly you should write a custom directive for this. The |
| <a href="guide/directive">directives guide</a> explains how to do this. |
| </div> |
| |
| <p>The second kind of new markup are the double curly braces <code>{{ expression | filter }}</code>: |
| When the compiler encounters this markup, it will replace it with the evaluated value of the markup. |
| An <a name="expression">"<a href="guide/expression">expression</a>"</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">"<a href="guide/scope">scope</a>"</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".</p> |
| <p>The example above also contains a <a name="filter">"<a href="guide/filter">filter</a>"</a>. |
| A filter formats the value of an expression for display to the user. |
| In the example above, the filter <a href="api/ng/filter/currency"><code>currency</code></a> formats a number |
| into an output that looks like money.</p> |
| <p>The important thing in the example is that angular provides <em>live</em> 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">"<a href="guide/databinding">two-way data binding</a>"</a>.</p> |
| <h2 id="adding-ui-logic-controllers">Adding UI logic: Controllers</h2> |
| <p>Let's add some more logic to the example that allows us to enter and calculate the costs in |
| different currencies and also pay the invoice.</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-guide-concepts-2@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-guide-concepts-2" |
| name="guide-concepts-2" |
| ng-app-included="true"> |
| |
| |
| <div class="runnable-example-file" |
| name="invoice1.js" |
| language="js" |
| type="js"> |
| <pre><code>angular.module('invoice1', []) .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 }; this.total = function total(outCurr) { return this.convertCurrency(this.qty * this.cost, this.inCurr, outCurr); }; this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) { return amount * this.usdToForeignRates[outCurr] / this.usdToForeignRates[inCurr]; }; this.pay = function pay() { window.alert("Thanks!"); }; });</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><div ng-app="invoice1" 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 class="btn" ng-click="invoice.pay()">Pay</button> </div> </div></code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-guide-concepts-2/index.html" name="example-guide-concepts-2"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <p>What changed?</p> |
| <p>First, there is a new JavaScript file that contains a so called <a name="controller">"<a href="guide/controller">controller</a>"</a>. |
| 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.</p> |
| <p>Besides the new file that contains the controller code we also added a |
| <a href="api/ng/directive/ngController"><code>ng-controller</code></a> directive to the HTML. |
| This directive tells angular that the new <code>InvoiceController</code> is responsible for the element with the directive |
| and all of the element's children. |
| The syntax <code>InvoiceController as invoice</code> tells Angular to instantiate the controller |
| and save it in the variable <code>invoice</code> in the current scope.</p> |
| <p>We also changed all expressions in the page to read and write variables within that |
| controller instance by prefixing them with <code>invoice.</code> . The possible currencies are defined in the controller |
| and added to the template using <a href="api/ng/directive/ngRepeat"><code>ng-repeat</code></a>. |
| As the controller contains a <code>total</code> function |
| we are also able to bind the result of that function to the DOM using <code>{{ invoice.total(...) }}</code>.</p> |
| <p>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 <a href="api/ng/directive/ngClick"><code>ngClick</code></a>. This will evaluate the |
| corresponding expression whenever the button is clicked.</p> |
| <p>In the new JavaScript file we are also creating a <a href="guide/concepts#module">module</a> |
| at which we register the controller. We will talk about modules in the next section.</p> |
| <p>The following graphic shows how everything works together after we introduced the controller:</p> |
| <p><img style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding2.png"></p> |
| <h2 id="view-independent-business-logic-services">View independent business logic: Services</h2> |
| <p>Right now, the <code>InvoiceController</code> contains all logic of our example. When the application grows it |
| is a good practice to move view independent logic from the controller into a so called |
| <a name="service">"<a href="guide/services">service</a>"</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.</p> |
| <p>Let's refactor our example and move the currency conversion into a service in another file:</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-guide-concepts-21@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-guide-concepts-21" |
| name="guide-concepts-2" |
| ng-app-included="true"> |
| |
| |
| <div class="runnable-example-file" |
| name="finance2.js" |
| language="js" |
| type="js"> |
| <pre><code>angular.module('finance2', []) .factory('currencyConverter', function() { var currencies = ['USD', 'EUR', 'CNY']; var usdToForeignRates = { USD: 1, EUR: 0.74, CNY: 6.09 }; var convert = function (amount, inCurr, outCurr) { return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr]; }; return { currencies: currencies, convert: convert }; });</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="invoice2.js" |
| language="js" |
| type="js"> |
| <pre><code>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!"); }; }]);</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><div ng-app="invoice2" 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 class="btn" ng-click="invoice.pay()">Pay</button> </div> </div></code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-guide-concepts-21/index.html" name="example-guide-concepts-21"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <p><img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-service.png"></p> |
| <p>What changed? |
| We moved the <code>convertCurrency</code> function and the definition of the existing currencies |
| into the new file <code>finance.js</code>. But how does the controller |
| get a hold of the now separated function?</p> |
| <p>This is where <a name="di">"<a href="guide/di">Dependency Injection</a>"</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">"<a href="guide/di">injector</a>"</a>.</p> |
| <p>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">"<a href="guide/module">modules</a>"</a>. |
| When Angular starts, it will use the configuration of the module with the name defined by the <code>ng-app</code> directive, |
| including the configuration of all modules that this module depends on.</p> |
| <p>In the example above: |
| The template contains the directive <code>ng-app="invoice2"</code>. This tells Angular |
| to use the <code>invoice2</code> module as the main module for the application. |
| The code snippet <code>angular.module('invoice2', ['finance2'])</code> specifies that the <code>invoice2</code> module depends on the |
| <code>finance2</code> module. By this, Angular uses the <code>InvoiceController</code> as well as the <code>currencyConverter</code> service.</p> |
| <p>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 <a href="guide/services">service guide</a>). |
| In the example above, we are using a function that returns the <code>currencyConverter</code> function as the factory |
| for the service.</p> |
| <p>Back to the initial question: How does the <code>InvoiceController</code> get a reference to the <code>currencyConverter</code> 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 <code>InvoiceController</code> has an argument named <code>currencyConverter</code>. By this, Angular knows about the |
| dependency between the controller and the service and calls the controller with the service instance as argument.</p> |
| <p>The last thing that changed in the example between the previous section and this section is that we |
| now pass an array to the <code>module.controller</code> 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 <code>a</code>.</p> |
| <h2 id="accessing-the-backend">Accessing the backend</h2> |
| <p>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:</p> |
| <p> |
| |
| <div> |
| <a ng-href="http://plnkr.co/edit/ngdoc:example-guide-concepts-3@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank"> |
| <i class="glyphicon glyphicon-edit"> </i> |
| Edit in Plunker</a> |
| <div class="runnable-example" |
| path="examples/example-guide-concepts-3" |
| name="guide-concepts-3" |
| ng-app-included="true"> |
| |
| |
| <div class="runnable-example-file" |
| name="invoice3.js" |
| language="js" |
| type="js"> |
| <pre><code>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!"); }; }]);</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="finance3.js" |
| language="js" |
| type="js"> |
| <pre><code>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'; var currencies = ['USD', 'EUR', 'CNY']; var usdToForeignRates = {}; var convert = function (amount, inCurr, outCurr) { return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr]; }; var refresh = function() { 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; }); }; refresh(); return { currencies: currencies, convert: convert, refresh: refresh }; }]);</code></pre> |
| </div> |
| |
| <div class="runnable-example-file" |
| name="index.html" |
| language="html" |
| type="html"> |
| <pre><code><div ng-app="invoice3" 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 class="btn" ng-click="invoice.pay()">Pay</button> </div> </div></code></pre> |
| </div> |
| |
| |
| <iframe class="runnable-example-frame" src="examples/example-guide-concepts-3/index.html" name="example-guide-concepts-3"></iframe> |
| </div> |
| </div> |
| |
| </p> |
| <p>What changed? |
| Our <code>currencyConverter</code> service of the <code>finance</code> module now uses the <a href="api/ng/service/$http"><code>$http</code></a>, a |
| built-in service provided by Angular for accessing a server backend. <code>$http</code> is a wrapper around |
| <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> |
| and <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> transports.</p> |
| |
| |