Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f031127160 | |||
| 00b44d8e12 | |||
| ca865d29a3 | |||
| 3ccec13aa7 | |||
| 43d49013d1 | |||
| 116fac0562 | |||
| c3024254b6 | |||
| 770353df19 | |||
| 85b7d24357 | |||
| 8469779a8e | |||
| 3374e35953 | |||
| 90ff8a98d8 | |||
| a4dc21ebf5 | |||
| ec93f94cc9 | |||
| 7665497a53 | |||
| 2acadc4216 | |||
| c7658d9457 | |||
| b92c650e05 | |||
| f7a0f9d841 | |||
| b17d40b4a5 | |||
| d745df7e5f | |||
| 53b444419c | |||
| 9a21050b43 | |||
| 8473b9d558 | |||
| 679d418a50 | |||
| 16d247b386 | |||
| 4767d34ae8 | |||
| 5efc2ed5ac | |||
| f9bf194439 | |||
| 3c4460b513 | |||
| a98931de0e | |||
| 7e5154e755 | |||
| ec6b1cfaba | |||
| 8d8801f1ae | |||
| 301647bf1b | |||
| 1c03a1b9c0 | |||
| fd797cdb7e | |||
| ed1dbf2554 | |||
| 022cb3dc4e | |||
| 4f107acfcf | |||
| f363bcb437 | |||
| 7b2259f32c | |||
| 9e88fa18b9 | |||
| 094580c3da | |||
| cc4d08c5f0 | |||
| d0ae241afd | |||
| e1f103a8e4 | |||
| d17aa84be1 | |||
| e87c88914f | |||
| b5d48ee1f0 | |||
| 1c010b33aa | |||
| 16c7ab1ba0 | |||
| 9ef5d8f318 | |||
| 6a634e309b | |||
| 13f58447e2 | |||
| bc72211e7b | |||
| 230e124ddb | |||
| 10016ab3fd | |||
| 69dc003a0b | |||
| ae2fd55575 | |||
| f102fb75b6 | |||
| 8a7240ddfd | |||
| ac70ec0340 | |||
| dbd90a4d78 | |||
| 5b1f9b3c2b | |||
| 08a07f2d30 | |||
| b1143c9481 | |||
| 73e1d0054c | |||
| 33ab261817 | |||
| 230ff0576a | |||
| e3371d7c53 | |||
| 9b2b93d9bd | |||
| d7fb721b4d | |||
| e7cfa5c2bf | |||
| 2a3212a0a3 | |||
| 7a08a76875 | |||
| 22a09dddc6 | |||
| 8c72549cc2 | |||
| bba5214930 | |||
| fb194b9488 |
@@ -0,0 +1,23 @@
|
||||
Using AngularJS with the Closure Compiler
|
||||
=========================================
|
||||
|
||||
The Closure Compiler project contains externs definitions for AngularJS
|
||||
JavaScript in its `contrib/externs` directory.
|
||||
|
||||
The definitions contain externs for use with the Closure compiler (aka
|
||||
JSCompiler). Passing these files to the --externs parameter of a compiler
|
||||
pass allows using type annotations for AngularJS objects. For example,
|
||||
Angular's $scope objects can be annotated as:
|
||||
```js
|
||||
/** @type {angular.Scope} */
|
||||
var scope = $scope;
|
||||
```
|
||||
|
||||
This allows JSCompiler to type check accesses to scope, give warnings about
|
||||
missing methods or incorrect arguments, and also prevents renaming of property
|
||||
accesses with advanced compilation.
|
||||
|
||||
The externs are incomplete and maintained on an as-needed basis, but strive to
|
||||
be correct. Externs for individual modules should be added in separate files.
|
||||
|
||||
See https://developers.google.com/closure/compiler/
|
||||
@@ -16,6 +16,7 @@ it makes development fun!
|
||||
* API Docs: http://docs.angularjs.org/api
|
||||
* Developer Guide: http://docs.angularjs.org/guide
|
||||
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
|
||||
* Dashboard: http://dashboard.angularjs.org
|
||||
|
||||
Building AngularJS
|
||||
---------
|
||||
|
||||
@@ -93,7 +93,8 @@ Here is an example of manually initializing Angular:
|
||||
<script src="http://code.angularjs.org/angular.js"></script>
|
||||
<script>
|
||||
angular.element(document).ready(function() {
|
||||
angular.bootstrap(document, ['optionalModuleName']);
|
||||
angular.module('myApp', []);
|
||||
angular.bootstrap(document, ['myApp']);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
@@ -101,9 +102,8 @@ Here is an example of manually initializing Angular:
|
||||
</pre>
|
||||
|
||||
Note that we have provided the name of our application module to be loaded into the injector as the second
|
||||
parameter of the {@link api/angular.bootstrap} function. This example is equivalent to using the
|
||||
{@link api/ng.directive:ngApp ng-app} directive, with `ng-app="optionalModuleName"`, as in the automatic
|
||||
initialization example above.
|
||||
parameter of the {@link api/angular.bootstrap} function. Notice that `angular.bootstrap` will not create modules
|
||||
on the fly. You must create any custom {@link guide/module modules} before you pass them as a parameter.
|
||||
|
||||
This is the sequence that your code should follow:
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@ This is how we get the ball rolling (refer to the diagram and example below):
|
||||
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
|
||||
`Hello World!`
|
||||
|
||||
<div class="clear">
|
||||
</div>
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<p ng-init=" name='World' ">Hello {{name}}!</p>
|
||||
@@ -126,8 +124,6 @@ user enters text into the text field.
|
||||
the JavaScript execution context.
|
||||
7. The browser re-renders the view with update text.
|
||||
|
||||
<div class="clear">
|
||||
</div>
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<input ng-model="name">
|
||||
@@ -147,8 +143,6 @@ The following example demonstrates how the `name` {@link guide/expression expres
|
||||
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="clear">
|
||||
</div>
|
||||
<div class="show-scope">
|
||||
<example>
|
||||
<file name="index.html">
|
||||
@@ -204,8 +198,6 @@ The separation of the controller and the view is important because:
|
||||
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
|
||||
and testability.
|
||||
|
||||
<div class="clear">
|
||||
</div>
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div ng-controller="MyCtrl">
|
||||
@@ -239,10 +231,6 @@ to inherit from or special accessor methods for accessing or changing the model.
|
||||
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
|
||||
|
||||
|
||||
<div class="clear">
|
||||
</div>
|
||||
|
||||
|
||||
<a name="view"></a>
|
||||
# View
|
||||
|
||||
@@ -269,9 +257,6 @@ rendering the view compared to most other templating systems.
|
||||
continuously updating view which does not need template model re-merging. Your model becomes
|
||||
the single source-of-truth for your view.
|
||||
|
||||
<div class="clear">
|
||||
</div>
|
||||
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
||||
@@ -369,7 +354,6 @@ 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}.
|
||||
|
||||
<div class='clear'></div>
|
||||
<pre>
|
||||
// Create a module
|
||||
var myModule = angular.module('myModule', [])
|
||||
|
||||
@@ -38,9 +38,9 @@ it('should filter results', function() {
|
||||
});
|
||||
</pre>
|
||||
This scenario describes the requirements of a Buzz Client, specifically, that it should be able to
|
||||
filter the stream of the user. It starts by entering a value in the 'user' input field, clicking
|
||||
filter the stream of the user. It starts by entering a value in the input field with ng-model="user", clicking
|
||||
the only button on the page, and then it verifies that there are 10 items listed. It then enters
|
||||
'Bees' in the 'filterText' input field and verifies that the list is reduced to a single item.
|
||||
'Bees' in the input field with ng-model='filterText' and verifies that the list is reduced to a single item.
|
||||
|
||||
The API section below lists the available commands and expectations for the Runner.
|
||||
|
||||
@@ -134,10 +134,10 @@ Returns an array with the values in the column with the given `binding` in the r
|
||||
the given jQuery `selector`. The `label` is used for test output.
|
||||
|
||||
## select(name).option(value)
|
||||
Picks the option with the given `value` on the select with the given `name`.
|
||||
Picks the option with the given `value` on the select with the given ng-model `name`.
|
||||
|
||||
## select(name).options(value1, value2...)
|
||||
Picks the options with the given `values` on the multi select with the given `name`.
|
||||
Picks the options with the given `values` on the multi select with the given ng-model `name`.
|
||||
|
||||
## element(selector, label).count()
|
||||
Returns the number of elements that match the given jQuery `selector`. The `label` is used for test
|
||||
@@ -275,7 +275,7 @@ beforeEach(function () {
|
||||
|
||||
In order to understand what is happening, we should emphasize that ngScenario calls are not
|
||||
immediately executed, but queued (in ngScenario terms, we would be talking about adding
|
||||
future actions). If we had only one entry in our table, than the following future actions
|
||||
future actions). If we had only one entry in our table, then the following future actions
|
||||
would be queued:
|
||||
|
||||
<pre>
|
||||
|
||||
@@ -2,24 +2,31 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
||||
@description
|
||||
|
||||
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of
|
||||
angular {@link scope Scope}, excluding the root scope.
|
||||
# Understanding Controllers
|
||||
|
||||
Use controllers to:
|
||||
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
|
||||
{@link scope Angular Scope}.
|
||||
|
||||
- Set up the initial state of a scope object.
|
||||
- Add behavior to the scope object.
|
||||
When a Controller is attached to the DOM via the {@link api/ng.directive:ngController ng-controller}
|
||||
directive, Angular will instantiate a new Controller object, using the specified Controller's
|
||||
**constructor function**. A new **child scope** will be available as an injectable parameter to the
|
||||
Controller's constructor function as `$scope`.
|
||||
|
||||
# Setting up the initial state of a scope object
|
||||
Use Controllers to:
|
||||
|
||||
Typically, when you create an application you need to set up an initial state for an Angular scope.
|
||||
- Set up the initial state of the `$scope` object.
|
||||
- Add behavior to the `$scope` object.
|
||||
|
||||
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
|
||||
to a new Angular scope object, which sets up an initial scope state. This means that Angular never
|
||||
creates instances of the controller type (by invoking the `new` operator on the controller
|
||||
constructor). Constructors are always applied to an existing scope object.
|
||||
# Setting up the initial state of a `$scope` object
|
||||
|
||||
You set up the initial state of a scope by creating model properties. For example:
|
||||
Typically, when you create an application you need to set up the initial state for the Angular
|
||||
`$scope`. You set up the initial state of a scope by attaching properties to the `$scope` object.
|
||||
The properties contain the **view model** (the model that will be presented by the view). All the
|
||||
`$scope` properties will be available to the template at the point in the DOM where the Controller
|
||||
is registered.
|
||||
|
||||
The following example shows a very simple constructor function for a Controller, `GreetingCtrl`,
|
||||
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
|
||||
|
||||
<pre>
|
||||
function GreetingCtrl($scope) {
|
||||
@@ -27,12 +34,18 @@ You set up the initial state of a scope by creating model properties. For exampl
|
||||
}
|
||||
</pre>
|
||||
|
||||
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
|
||||
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
|
||||
template:
|
||||
|
||||
**NOTE**: Many of the examples in the documentation show the creation of functions
|
||||
in the global scope. This is only for demonstration purposes - in a real
|
||||
application you should use the `.controller` method of your Angular module for
|
||||
your application as follows:
|
||||
<pre>
|
||||
<div ng-controller="GreetingCtrl">
|
||||
{{ greeting }}
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is
|
||||
not recommended. In a real application you should use the `.controller` method of your
|
||||
{@link module Angular Module} for your application as follows:
|
||||
|
||||
<pre>
|
||||
var myApp = angular.module('myApp',[]);
|
||||
@@ -42,40 +55,62 @@ your application as follows:
|
||||
}]);
|
||||
</pre>
|
||||
|
||||
Note also that we use the array notation to explicitly specify the dependency
|
||||
of the controller on the `$scope` service provided by Angular.
|
||||
We have used an **inline injection annotation** to explicitly specify the dependency
|
||||
of the Controller on the `$scope` service provided by Angular. See the guide on
|
||||
{@link http://docs.angularjs.org/guide/di Dependency Injection} for more information.
|
||||
|
||||
|
||||
# Adding Behavior to a Scope Object
|
||||
|
||||
Behavior on an Angular scope object is in the form of scope method properties available to the
|
||||
template/view. This behavior interacts with and modifies the application model.
|
||||
In order to react to events or execute computation in the view we must provide behavior to the
|
||||
scope. We add behavior the scope by attaching methods to the `$scope` object. These methods are
|
||||
then available to be called from the template/view.
|
||||
|
||||
The following example uses a Controller to add a method to the scope, which doubles a number:
|
||||
|
||||
<pre>
|
||||
var myApp = angular.module('myApp',[]);
|
||||
|
||||
myApp.controller('DoubleCtrl', ['$scope', function($scope) {
|
||||
$scope.double = function(value) { return value * 2; };
|
||||
}]);
|
||||
</pre>
|
||||
|
||||
Once the Controller has been attached to the DOM, the `double` method can be invoked in an Angular
|
||||
expression in the template:
|
||||
|
||||
<pre>
|
||||
<div ng-controller="DoubleCtrl">
|
||||
Two times <input ng-model="num"> equals {{ double(num) }}
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
||||
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
|
||||
objects (or primitives) assigned to the scope become model properties. Any methods assigned to
|
||||
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}).
|
||||
|
||||
# Using Controllers Correctly
|
||||
|
||||
In general, a controller shouldn't try to do too much. It should contain only the business logic
|
||||
In general, a Controller shouldn't try to do too much. It should contain only the business logic
|
||||
needed for a single view.
|
||||
|
||||
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
|
||||
controllers into services and then using these services in controllers via dependency injection.
|
||||
The most common way to keep Controllers slim is by encapsulating work that doesn't belong to
|
||||
controllers into services and then using these services in Controllers via dependency injection.
|
||||
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
|
||||
Services} sections of this guide.
|
||||
|
||||
Do not use controllers for:
|
||||
Do not use Controllers for:
|
||||
|
||||
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
||||
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
|
||||
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
|
||||
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
|
||||
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
||||
{@link guide/directive directives}.
|
||||
- Input formatting — Use {@link forms angular form controls} instead.
|
||||
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
|
||||
- Sharing stateless or stateful code across controllers — Use {@link dev_guide.services angular
|
||||
- Sharing stateless or stateful code across Controllers — Use {@link dev_guide.services angular
|
||||
services} instead.
|
||||
- Managing the life-cycle of other components (for example, to create service instances).
|
||||
|
||||
@@ -86,189 +121,208 @@ You can associate controllers with scope objects implicitly via the {@link api/n
|
||||
directive} or {@link api/ng.$route $route service}.
|
||||
|
||||
|
||||
## Controller Constructor and Methods Example
|
||||
## Simple Spicy Controller Example
|
||||
|
||||
To illustrate how the controller component works 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:
|
||||
|
||||
- A {@link dev_guide.templates template} with two buttons and a simple message
|
||||
- A model consisting of a string named `spice`
|
||||
- A controller with two functions that set the value of `spice`
|
||||
- A Controller with two functions that set the value of `spice`
|
||||
|
||||
The message in our template contains a binding to the `spice` model, which by default is set to the
|
||||
string "very". Depending on which button is clicked, the `spice` model is set to `chili` or
|
||||
`jalapeño`, and the message is automatically updated by data-binding.
|
||||
|
||||
<doc:example module="spicyApp1">
|
||||
<doc:source>
|
||||
<div ng-app="spicyApp1" ng-controller="SpicyCtrl">
|
||||
<button ng-click="chiliSpicy()">Chili</button>
|
||||
<button ng-click="jalapenoSpicy()">Jalapeño</button>
|
||||
<p>The food is {{spice}} spicy!</p>
|
||||
</div>
|
||||
<script>
|
||||
var myApp = angular.module('spicyApp1', []);
|
||||
|
||||
## A Spicy Controller Example
|
||||
|
||||
<pre>
|
||||
<body ng-controller="SpicyCtrl">
|
||||
<button ng-click="chiliSpicy()">Chili</button>
|
||||
<button ng-click="jalapenoSpicy()">Jalapeño</button>
|
||||
<p>The food is {{spice}} spicy!</p>
|
||||
</body>
|
||||
|
||||
function SpicyCtrl($scope) {
|
||||
$scope.spice = 'very';
|
||||
$scope.chiliSpicy = function() {
|
||||
$scope.spice = 'chili';
|
||||
}
|
||||
$scope.jalapenoSpicy = function() {
|
||||
$scope.spice = 'jalapeño';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</pre>
|
||||
myApp.controller('SpicyCtrl', ['$scope', function($scope){
|
||||
$scope.spicy = 'very';
|
||||
|
||||
$scope.chiliSpicy = function() {
|
||||
$scope.spice = 'chili';
|
||||
};
|
||||
|
||||
$scope.jalapenoSpicy = function() {
|
||||
$scope.spice = 'jalapeño';
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
|
||||
Things to notice in the example above:
|
||||
|
||||
- The `ngController` directive is used to (implicitly) create a scope for our template, and the
|
||||
scope is augmented (managed) by the `SpicyCtrl` controller.
|
||||
- The `ng-controller` directive is used to (implicitly) create a scope for our template, and the
|
||||
scope is augmented (managed) by the `SpicyCtrl` Controller.
|
||||
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
|
||||
starts with capital letter and ends with "Ctrl" or "Controller".
|
||||
- Assigning a property to `$scope` creates or updates the model.
|
||||
- Controller methods can be created through direct assignment to scope (the `chiliSpicy` method)
|
||||
- Both controller methods are available in the template (for the `body` element and and its
|
||||
children).
|
||||
- NB: Previous versions of Angular (pre 1.0 RC) allowed you to use `this` interchangeably with
|
||||
the $scope method, but this is no longer the case. Inside of methods defined on the scope
|
||||
`this` and $scope are interchangeable (angular sets `this` to $scope), but not otherwise
|
||||
inside your controller constructor.
|
||||
- NB: Previous versions of Angular (pre 1.0 RC) added prototype methods into the scope
|
||||
automatically, but this is no longer the case; all methods need to be added manually to
|
||||
the scope.
|
||||
- Controller methods can be created through direct assignment to scope (see the `chiliSpicy` method)
|
||||
- The Controller methods and properties are available in the template (for the `<div>` element and
|
||||
and its children).
|
||||
|
||||
## Spicy Arguments Example
|
||||
|
||||
Controller methods can also take arguments, as demonstrated in the following variation of the
|
||||
previous example.
|
||||
|
||||
## Controller Method Arguments Example
|
||||
<doc:example module="spicyApp2">
|
||||
<doc:source>
|
||||
<div ng-app="spicyApp2" ng-controller="SpicyCtrl">
|
||||
<input ng-model="customSpice">
|
||||
<button ng-click="spicy('chili')">Chili</button>
|
||||
<button ng-click="spicy(customSpice)">Custom spice</button>
|
||||
<p>The food is {{spice}} spicy!</p>
|
||||
</div>
|
||||
<script>
|
||||
var myApp = angular.module('spicyApp2', []);
|
||||
|
||||
<pre>
|
||||
<body ng-controller="SpicyCtrl">
|
||||
<input ng-model="customSpice" value="wasabi">
|
||||
<button ng-click="spicy('chili')">Chili</button>
|
||||
<button ng-click="spicy(customSpice)">Custom spice</button>
|
||||
<p>The food is {{spice}} spicy!</p>
|
||||
</body>
|
||||
myApp.controller('SpicyCtrl', ['$scope', function($scope){
|
||||
$scope.customSpice = "wasabi";
|
||||
$scope.spice = 'very';
|
||||
|
||||
$scope.spicy = function(spice){
|
||||
$scope.spice = spice;
|
||||
};
|
||||
}]);
|
||||
</script>
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
|
||||
function SpicyCtrl($scope) {
|
||||
$scope.spice = 'very';
|
||||
$scope.spicy = function(spice) {
|
||||
$scope.spice = spice;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
Notice that the `SpicyCtrl` controller now defines just one method called `spicy`, which takes one
|
||||
argument called `spice`. The template then refers to this controller method and passes in a string
|
||||
Notice that the `SpicyCtrl` Controller now defines just one method called `spicy`, which takes one
|
||||
argument called `spice`. The template then refers to this Controller method and passes in a string
|
||||
constant `'chili'` in the binding for the first button and a model property `spice` (bound to an
|
||||
input box) in the second button.
|
||||
|
||||
## Scope Inheritance Example
|
||||
|
||||
## Controller Inheritance Example
|
||||
It is common to attach Controllers at different levels of the DOM hierarchy. Since the
|
||||
{@link api/ng.directive:ngController ng-controller} directive creates a new child scope, we get a
|
||||
hierarchy of scopes that inherit from each other. The `$scope` that each Controller receives will
|
||||
have access to properties and methods defined by Controllers higher up the hierarchy.
|
||||
See {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes Understanding Scopes} for
|
||||
more information about scope inheritance.
|
||||
|
||||
Controller inheritance in Angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
|
||||
have a look at an example:
|
||||
<doc:example module="scopeInheritance">
|
||||
<doc:source>
|
||||
<div ng-app="scopeInheritance" class="spicy">
|
||||
<div ng-controller="MainCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
|
||||
<pre>
|
||||
<body ng-controller="MainCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
<div ng-controller="ChildCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
||||
</div>
|
||||
</body>
|
||||
<div ng-controller="ChildCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
|
||||
function MainCtrl($scope) {
|
||||
$scope.timeOfDay = 'morning';
|
||||
$scope.name = 'Nikki';
|
||||
}
|
||||
<div ng-controller="BabyCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
div.spicy div {
|
||||
padding: 10px;
|
||||
border: solid 2px blue;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var myApp = angular.module('scopeInheritance', []);
|
||||
myApp.controller('MainCtrl', ['$scope', function($scope){
|
||||
$scope.timeOfDay = 'morning';
|
||||
$scope.name = 'Nikki';
|
||||
}]);
|
||||
myApp.controller('ChildCtrl', ['$scope', function($scope){
|
||||
$scope.name = 'Mattie';
|
||||
}]);
|
||||
myApp.controller('BabyCtrl', ['$scope', function($scope){
|
||||
$scope.timeOfDay = 'evening';
|
||||
$scope.name = 'Gingerbreak Baby';
|
||||
}]);
|
||||
</script>
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
|
||||
function ChildCtrl($scope) {
|
||||
$scope.name = 'Mattie';
|
||||
}
|
||||
|
||||
function BabyCtrl($scope) {
|
||||
$scope.timeOfDay = 'evening';
|
||||
$scope.name = 'Gingerbreak Baby';
|
||||
}
|
||||
</pre>
|
||||
|
||||
Notice how we nested three `ngController` directives in our template. This template construct will
|
||||
result in 4 scopes being created for our view:
|
||||
Notice how we nested three `ng-controller` directives in our template. This will result in four
|
||||
scopes being created for our view:
|
||||
|
||||
- The root scope
|
||||
- The `MainCtrl` scope, which contains `timeOfDay` and `name` models
|
||||
- The `ChildCtrl` scope, which shadows the `name` model from the previous scope and inherits the
|
||||
`timeOfDay` model
|
||||
- The `BabyCtrl` scope, which shadows both the `timeOfDay` model defined in `MainCtrl` and `name`
|
||||
model defined in the ChildCtrl
|
||||
- The `MainCtrl` scope, which contains `timeOfDay` and `name` properties
|
||||
- The `ChildCtrl` scope, which inherits the `timeOfDay` property but overrides (hides) the `name`
|
||||
property from the previous
|
||||
- The `BabyCtrl` scope, which overrides (hides) both the `timeOfDay` property defined in `MainCtrl`
|
||||
and the `name` property defined in `ChildCtrl`
|
||||
|
||||
Inheritance works between controllers in the same way as it does with models. So in our previous
|
||||
examples, all of the models could be replaced with controller methods that return string values.
|
||||
|
||||
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
|
||||
because as we mentioned earlier, controllers are not instantiated directly by Angular, but rather
|
||||
are applied to the scope object.
|
||||
Inheritance works with methods in the same way as it does with properties. So in our previous
|
||||
examples, all of the properties could be replaced with methods that return string values.
|
||||
|
||||
|
||||
## Testing Controllers
|
||||
|
||||
Although there are many ways to test a controller, one of the best conventions, shown below,
|
||||
involves injecting the `$rootScope` and `$controller`
|
||||
Although there are many ways to test a Controller, one of the best conventions, shown below,
|
||||
involves injecting the {@link api/ng.$rootScope $rootScope} and {@link api/ng.$controller $controller}:
|
||||
|
||||
Controller Function:
|
||||
**Controller Definition:**
|
||||
<pre>
|
||||
function myController($scope) {
|
||||
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
|
||||
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
|
||||
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
|
||||
var myApp = angular.module('myApp',[]);
|
||||
|
||||
$scope.spice = "habanero";
|
||||
}
|
||||
myApp.controller('MyController', function($scope) {
|
||||
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
|
||||
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
|
||||
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
|
||||
$scope.spice = "habanero";
|
||||
});
|
||||
</pre>
|
||||
|
||||
Controller Test:
|
||||
**Controller Test:**
|
||||
<pre>
|
||||
describe('myController function', function() {
|
||||
|
||||
describe('myController', function() {
|
||||
var scope;
|
||||
var $scope;
|
||||
|
||||
beforeEach(module('myApp'));
|
||||
|
||||
beforeEach(inject(function($rootScope, $controller) {
|
||||
scope = $rootScope.$new();
|
||||
var ctrl = $controller(myController, {$scope: scope});
|
||||
$scope = $rootScope.$new();
|
||||
$controller('MyController', {$scope: $scope});
|
||||
}));
|
||||
|
||||
it('should create "spices" model with 3 spices', function() {
|
||||
expect(scope.spices.length).toBe(3);
|
||||
expect($scope.spices.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should set the default value of spice', function() {
|
||||
expect(scope.spice).toBe('habanero');
|
||||
expect($scope.spice).toBe('habanero');
|
||||
});
|
||||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
|
||||
If you need to test a nested controller you need to create the same scope hierarchy
|
||||
in your test that exists in the DOM.
|
||||
If you need to test a nested Controller you need to create the same scope hierarchy
|
||||
in your test that exists in the DOM:
|
||||
|
||||
<pre>
|
||||
describe('state', function() {
|
||||
var mainScope, childScope, babyScope;
|
||||
|
||||
beforeEach(module('myApp'));
|
||||
|
||||
beforeEach(inject(function($rootScope, $controller) {
|
||||
mainScope = $rootScope.$new();
|
||||
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
|
||||
$controller('MainCtrl', {$scope: mainScope});
|
||||
childScope = mainScope.$new();
|
||||
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
|
||||
$controller('ChildCtrl', {$scope: childScope});
|
||||
babyScope = childScope.$new();
|
||||
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
|
||||
$controller('BabyCtrl', {$scope: babyScope});
|
||||
}));
|
||||
|
||||
it('should have over and selected', function() {
|
||||
|
||||
@@ -14,10 +14,10 @@ changes to $location are reflected into the browser address bar.
|
||||
- Exposes the current URL in the browser address bar, so you can
|
||||
- Watch and observe the URL.
|
||||
- Change the URL.
|
||||
- Synchronizes the URL with the browser when the user
|
||||
- Changes the address bar.
|
||||
- Clicks the back or forward button (or clicks a History link).
|
||||
- Clicks on a link.
|
||||
- Maintains synchronization between itself and the browser's URL when the user
|
||||
- Changes the address in the browser's address bar.
|
||||
- Clicks the back or forward button in the browser (or clicks a History link).
|
||||
- Clicks on a link in the page.
|
||||
- Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
|
||||
|
||||
|
||||
@@ -121,6 +121,8 @@ All of the setter methods return the same `$location` object to allow chaining.
|
||||
change multiple segments in one go, chain setters like this:
|
||||
<pre>$location.path('/newValue').search({key: value});</pre>
|
||||
|
||||
## Replace method
|
||||
|
||||
There is a special `replace` method which can be used to tell the $location service that the next
|
||||
time the $location service is synced with the browser, the last history record should be replaced
|
||||
instead of creating a new one. This is useful when you want to implement redirection, which would
|
||||
@@ -321,6 +323,14 @@ reload to the original link.
|
||||
Example: `<a href="http://angularjs.org/">link</a>`
|
||||
- Links starting with '/' that lead to a different base path when base is defined<br>
|
||||
Example: `<a href="/not-my-base/link">link</a>`
|
||||
|
||||
When running Angular in the root of a domain, along side perhaps a normal application in the same
|
||||
directory, the "otherwise" route handler will try to handle all the URLs, including ones that map
|
||||
to static files.
|
||||
|
||||
To prevent this, you can set your base href for the app to `<base href=".">` and then prefix links
|
||||
to URLs that should be handled with `.`. Now, links to locations, which are not to be routed by Angular,
|
||||
are not prefixed with `.` and will not be intercepted by the `otherwise` rule in your `$routeProvider`.
|
||||
|
||||
|
||||
### Server side
|
||||
|
||||
@@ -7,9 +7,17 @@ Angular sets these CSS classes. It is up to your application to provide useful s
|
||||
|
||||
# CSS classes used by angular
|
||||
|
||||
* `ng-scope`
|
||||
- **Usage:** angular applies this class to any element that where a new {@link api/ng.$rootScope.Scope scope}
|
||||
is defined. (see {@link guide/scope scope} guide for more information about scopes)
|
||||
|
||||
* `ng-binding`
|
||||
- **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)
|
||||
|
||||
* `ng-invalid`, `ng-valid`
|
||||
- **Usage:** angular applies this class to an input widget element if that element's input does
|
||||
not pass validation. (see {@link api/ng.directive:input input} directive).
|
||||
not pass validation. (see {@link api/ng.directive:input input} directive)
|
||||
|
||||
* `ng-pristine`, `ng-dirty`
|
||||
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
|
||||
|
||||
@@ -147,6 +147,8 @@ of service names to inject.
|
||||
MyController.$inject = ['$scope', 'greeter'];
|
||||
</pre>
|
||||
|
||||
In this scenario the ordering of the values in the '$inject' array must match the ordering of the arguments to inject.
|
||||
Using above code snippet as an example, '$scope' will be injected into 'renamed$scope' and 'greeter' into 'renamedGreeter'.
|
||||
Care must be taken that the `$inject` annotation is kept in sync with the actual arguments in the
|
||||
function declaration.
|
||||
|
||||
|
||||
@@ -27,28 +27,28 @@ attribute only.)
|
||||
<!-- directive: my-dir exp -->
|
||||
</pre>
|
||||
|
||||
Directives can be invoked in many different ways, but are equivalent in the end result as shown in
|
||||
the following example.
|
||||
The following demonstrates the various ways a Directive (ngBind in this case) can be referenced from within a template.
|
||||
|
||||
<doc:example>
|
||||
<doc:source >
|
||||
<script>
|
||||
function Ctrl1($scope) {
|
||||
$scope.name = 'angular';
|
||||
$scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)';
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="Ctrl1">
|
||||
Hello <input ng-model='name'> <hr/>
|
||||
<span ng-bind="name"> <span ng-bind="name"></span> <br/>
|
||||
<span ng:bind="name"> <span ng:bind="name"></span> <br/>
|
||||
<span ng_bind="name"> <span ng_bind="name"></span> <br/>
|
||||
<span ng-bind="name"> <span ng-bind="name"></span> <br/>
|
||||
<span data-ng-bind="name"> <span data-ng-bind="name"></span> <br/>
|
||||
<span x-ng-bind="name"> <span x-ng-bind="name"></span> <br/>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should show off bindings', function() {
|
||||
expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular');
|
||||
expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text())
|
||||
.toBe('Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
@@ -647,10 +647,10 @@ Following is an example of building a reusable widget.
|
||||
'</div>',
|
||||
// The linking function will add behavior to the template
|
||||
link: function(scope, element, attrs) {
|
||||
// Title element
|
||||
// Title element
|
||||
var title = angular.element(element.children()[0]),
|
||||
// Opened / closed state
|
||||
opened = true;
|
||||
// Opened / closed state
|
||||
opened = true;
|
||||
|
||||
// Clicking on title should open/close the zippy
|
||||
title.bind('click', toggle);
|
||||
|
||||
@@ -154,10 +154,10 @@ This allows us to extend the above example with these features:
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master= {};
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master= angular.copy(user);
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
|
||||
@@ -56,22 +56,22 @@ locale-specific file to the end of `angular.js` or `angular.min.js` file.
|
||||
For example on *nix, to create an angular.js file that contains localization rules for german
|
||||
locale, you can do the following:
|
||||
|
||||
`cat angular.js i18n/angular-locale_de-ge.js > angular_de-ge.js`
|
||||
`cat angular.js i18n/angular-locale_de-de.js > angular_de-de.js`
|
||||
|
||||
When the application containing `angular_de-ge.js` script instead of the generic angular.js script
|
||||
When the application containing `angular_de-de.js` script instead of the generic angular.js script
|
||||
starts, Angular is automatically pre-configured with localization rules for the german locale.
|
||||
|
||||
**2. Including locale js script in index.html page**
|
||||
|
||||
You can also include the locale specific js file in the index.html page. For example, if one client
|
||||
requires German locale, you would serve index_de-ge.html which will look something like this:
|
||||
requires German locale, you would serve index_de-de.html which will look something like this:
|
||||
|
||||
<pre>
|
||||
<html ng-app>
|
||||
<head>
|
||||
….
|
||||
<script src="angular.js"></script>
|
||||
<script src="i18n/angular-locale_de-ge.js"></script>
|
||||
<script src="i18n/angular-locale_de-de.js"></script>
|
||||
….
|
||||
</head>
|
||||
</html>
|
||||
|
||||
@@ -56,12 +56,12 @@ starting point you can easily change. Angular comes with the following out-of-th
|
||||
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 for the CRUD application in mind. Luckily CRUD
|
||||
applications represent at least 90% of the web applications. But to understand what Angular is
|
||||
applications represent the majority of web applications. But to understand what Angular is
|
||||
good at one also has to understand when an app is not a good fit for Angular.
|
||||
|
||||
Games, and GUI editors are examples of very intensive and tricky DOM manipulation. These kinds of
|
||||
apps are different from CRUD apps, and as a result are not a good fit for Angular. In these cases
|
||||
using something closer to bare metal such as `jQuery` may be a better fit.
|
||||
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
|
||||
@@ -151,7 +151,7 @@ into output that looks like money."
|
||||
|
||||
Notice that we achieved this application behavior not 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 then what is
|
||||
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.
|
||||
|
||||
@@ -175,7 +175,7 @@ expressing business logic.
|
||||
|
||||
|
||||
|
||||
Angular frees you from the following pain:
|
||||
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
|
||||
|
||||
@@ -153,7 +153,7 @@ for most cases. In advanced cases, such as when using script loaders, you can us
|
||||
There are 3 important things that happen during the app bootstrap:
|
||||
|
||||
1. The {@link api/AUTO.$injector injector} that will be used for dependency injection
|
||||
within this app is created.
|
||||
when this app is created.
|
||||
|
||||
2. The injector will then create the {@link api/ng.$rootScope root scope} that will
|
||||
become the context for the model of our application.
|
||||
|
||||
@@ -69,7 +69,7 @@ available as a filter input in the list repeater (`phone in phones | filter:`__`
|
||||
changes to the data model cause the repeater's input to change, the repeater efficiently updates
|
||||
the DOM to reflect the current state of the model.
|
||||
|
||||
<img class="diagram" src="img/tutorial/tutorial_03.png">
|
||||
<img class="diagram" src="img/tutorial/tutorial_03.png">
|
||||
|
||||
* Use of the `filter` filter: The {@link api/ng.filter:filter filter} function uses the
|
||||
`query` value to create a new array that contains only those records that match the `query`.
|
||||
@@ -127,6 +127,9 @@ end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests
|
||||
with unit tests, Karma will exit after the test run and will not automatically rerun the test
|
||||
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
|
||||
|
||||
Note: You must ensure you've installed karma-ng-scenario prior to running the `e2e-test.sh` script.
|
||||
You can do this by issuing `npm install karma-ng-scenario` into your terminal.
|
||||
|
||||
This test verifies that the search box and the repeater are correctly wired together. Notice how
|
||||
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
|
||||
really is that easy to set up any functional, readable, end-to-end test.
|
||||
|
||||
@@ -45,7 +45,7 @@ We made the following changes to the `index.html` template:
|
||||
* First, we added a `<select>` html element named `orderProp`, so that our users can pick from the
|
||||
two provided sorting options.
|
||||
|
||||
<img class="diagram" src="img/tutorial/tutorial_04.png">
|
||||
<img class="diagram" src="img/tutorial/tutorial_04.png">
|
||||
|
||||
* We then chained the `filter` filter with {@link api/ng.filter:orderBy `orderBy`}
|
||||
filter to further process the input into the repeater. `orderBy` is a filter that takes an input
|
||||
|
||||
@@ -94,7 +94,6 @@ describe('filter', function() {
|
||||
|
||||
beforeEach(module('phonecatFilters'));
|
||||
|
||||
|
||||
describe('checkmark', function() {
|
||||
|
||||
it('should convert boolean values to unicode checkmark or cross',
|
||||
@@ -106,8 +105,12 @@ describe('filter', function() {
|
||||
});
|
||||
</pre>
|
||||
|
||||
Note that you need to configure our test injector with the `phonecatFilters` module before any of
|
||||
our filter tests execute.
|
||||
We must call `beforeEach(module('phonecatFilters'))` before any of
|
||||
our filter tests execute. This call loads our `phonecatFilters` module into the injector
|
||||
for this test run.
|
||||
|
||||
Note that we call the helper function, `inject(function(checkmarkFilter) { ... })`, to get
|
||||
access to the filter that we want to test. See {@link api/angular.mock.inject angular.mock.inject()}.
|
||||
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ __`test/e2e/scenarios.js`:__
|
||||
|
||||
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||
runner to see the tests run, or you can see them running on {@link
|
||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||
http://angular.github.com/angular-phonecat/step-10/test/e2e/runner.html
|
||||
Angular's server}.
|
||||
|
||||
# Experiments
|
||||
|
||||
@@ -135,7 +135,7 @@ The {@link api/ngResource.$resource $resource} service augments the response obj
|
||||
with methods for updating and deleting the resource. If we were to use the standard `toEqual`
|
||||
matcher, our tests would fail because the test values would not match the responses exactly. To
|
||||
solve the problem, we use a newly-defined `toEqualData` {@link
|
||||
http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine matcher}. When the
|
||||
https://github.com/pivotal/jasmine/wiki/Matchers Jasmine matcher}. When the
|
||||
`toEqualData` matcher compares two objects, it takes only object properties into account and
|
||||
ignores methods.
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
font-family: monospace;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.content h2,
|
||||
|
||||
@@ -7,8 +7,8 @@ cd $BASE_DIR
|
||||
|
||||
set -x # Trace commands as they're executed.
|
||||
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/currency.js > closure/currencySymbols.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/datetimesymbols.js > closure/datetimeSymbols.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/datetimesymbolsext.js > closure/datetimeSymbolsExt.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/numberformatsymbols.js > closure/numberSymbols.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/pluralrules.js > closure/pluralRules.js
|
||||
curl http://google.github.io/closure-library/source/closure/goog/i18n/currency.js > closure/currencySymbols.js
|
||||
curl http://google.github.io/closure-library/source/closure/goog/i18n/datetimesymbols.js > closure/datetimeSymbols.js
|
||||
curl http://google.github.io/closure-library/source/closure/goog/i18n/datetimesymbolsext.js > closure/datetimeSymbolsExt.js
|
||||
curl http://google.github.io/closure-library/source/closure/goog/i18n/numberformatsymbols.js > closure/numberSymbols.js
|
||||
curl http://google.github.io/closure-library/source/closure/goog/i18n/pluralrules.js > closure/pluralRules.js
|
||||
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh,/Users/jenkins/bin/ie8.sh,/Users/jenkins/bin/ie9.sh"
|
||||
fi
|
||||
|
||||
if [[ -z "$BROWSERS_E2E" ]]
|
||||
then
|
||||
BROWSERS_E2E="Chrome,Firefox,/Users/jenkins/bin/safari.sh"
|
||||
fi
|
||||
|
||||
|
||||
# CLEAN #
|
||||
rm -f angular.min.js.gzip.size
|
||||
rm -f angular.js.size
|
||||
|
||||
|
||||
# BUILD #
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
|
||||
# UNIT TESTS #
|
||||
grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
# END TO END TESTS #
|
||||
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
# CHECK SIZE #
|
||||
gzip -c < build/angular.min.js > build/angular.min.js.gzip
|
||||
echo "YVALUE=`ls -l build/angular.min.js | cut -d" " -f 8`" > angular.min.js.size
|
||||
echo "YVALUE=`ls -l build/angular.min.js.gzip | cut -d" " -f 8`" > angular.min.js.gzip.size
|
||||
+9
-9
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"version": "1.0.8",
|
||||
"cdnVersion": "1.0.6",
|
||||
"codename": "bubble-burst",
|
||||
"version": "1.0.9-snapshot",
|
||||
"cdnVersion": "1.0.7",
|
||||
"codename": "marc-todo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "0.4.0",
|
||||
"grunt-contrib-clean": "0.4.0",
|
||||
"grunt-contrib-compress": "0.4.1",
|
||||
"grunt-contrib-connect": "0.1.2",
|
||||
"grunt-contrib-copy": "0.4.1",
|
||||
"grunt-parallel": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-connect": "~0.3.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"grunt-parallel": "git://github.com/vojtajina/grunt-parallel.git#streaming-per-task",
|
||||
"grunt-ddescribe-iit": "~0.0.1",
|
||||
"grunt-merge-conflict": "~0.0.1",
|
||||
"jasmine-node": "1.2.3",
|
||||
|
||||
+45
-5
@@ -578,7 +578,8 @@ function isLeafNode (node) {
|
||||
* * If no destination is supplied, a copy of the object or array is created.
|
||||
* * If a destination is provided, all of its elements (for array) or properties (for objects)
|
||||
* are deleted and then all elements/properties from the source are copied to it.
|
||||
* * If `source` is not an object or array, `source` is returned.
|
||||
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
|
||||
* * If `source` is identical to 'destination' an exception will be thrown.
|
||||
*
|
||||
* Note: this function is used to augment the Object type in Angular expressions. See
|
||||
* {@link ng.$filter} for more information about Angular arrays.
|
||||
@@ -588,6 +589,42 @@ function isLeafNode (node) {
|
||||
* @param {(Object|Array)=} destination Destination into which the source is copied. If
|
||||
* provided, must be of the same type as `source`.
|
||||
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<div ng-controller="Controller">
|
||||
<form novalidate class="simple-form">
|
||||
Name: <input type="text" ng-model="user.name" /><br />
|
||||
E-mail: <input type="email" ng-model="user.email" /><br />
|
||||
Gender: <input type="radio" ng-model="user.gender" value="male" />male
|
||||
<input type="radio" ng-model="user.gender" value="female" />female<br />
|
||||
<button ng-click="reset()">RESET</button>
|
||||
<button ng-click="update(user)">SAVE</button>
|
||||
</form>
|
||||
<pre>form = {{user | json}}</pre>
|
||||
<pre>master = {{master | json}}</pre>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master= {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
// Example with 1 argument
|
||||
$scope.master= angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
// Example with 2 arguments
|
||||
angular.copy($scope.master, $scope.user);
|
||||
};
|
||||
|
||||
$scope.reset();
|
||||
}
|
||||
</script>
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function copy(source, destination){
|
||||
if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
|
||||
@@ -726,7 +763,8 @@ function sliceArgs(args, startIndex) {
|
||||
* @description
|
||||
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
|
||||
* `fn`). You can supply optional `args` that are prebound to the function. This feature is also
|
||||
* known as [function currying](http://en.wikipedia.org/wiki/Currying).
|
||||
* known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as distinguished
|
||||
* from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
|
||||
*
|
||||
* @param {Object} self Context which `fn` should be evaluated in.
|
||||
* @param {function()} fn Function to be bound.
|
||||
@@ -757,7 +795,7 @@ function bind(self, fn) {
|
||||
function toJsonReplacer(key, value) {
|
||||
var val = value;
|
||||
|
||||
if (/^\$+/.test(key)) {
|
||||
if (typeof key === 'string' && key.charAt(0) === '$') {
|
||||
val = undefined;
|
||||
} else if (isWindow(value)) {
|
||||
val = '$WINDOW';
|
||||
@@ -948,7 +986,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
* HTML document you must manually bootstrap them using {@link angular.bootstrap}.
|
||||
* Applications cannot be nested.
|
||||
*
|
||||
* In the example below if the `ngApp` directive would not be placed
|
||||
* In the example below if the `ngApp` directive were not placed
|
||||
* on the `html` element then the document would not be compiled
|
||||
* and the `{{ 1+2 }}` would not be resolved to `3`.
|
||||
*
|
||||
@@ -1017,7 +1055,9 @@ function angularInit(element, bootstrap) {
|
||||
* They must use {@link api/ng.directive:ngApp ngApp}.
|
||||
*
|
||||
* @param {Element} element DOM element which is the root of angular application.
|
||||
* @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules}
|
||||
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
|
||||
* Each item in the array should be the name of a predefined module or a (DI annotated)
|
||||
* function that will be invoked by the injector as a run block. See: {@link angular.module modules}
|
||||
* @returns {AUTO.$injector} Returns the newly created injector for this app.
|
||||
*/
|
||||
function bootstrap(element, modules) {
|
||||
|
||||
+202
-49
@@ -253,46 +253,37 @@ function annotate(fn) {
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
|
||||
* The providers share the same name as the instance they create with `Provider` suffixed to them.
|
||||
* The {@link AUTO.$provide $provide} service has a number of methods for registering components with
|
||||
* the {@link AUTO.$injector $injector}. Many of these functions are also exposed on {@link angular.Module}.
|
||||
*
|
||||
* A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
|
||||
* a service. The Provider can have additional methods which would allow for configuration of the provider.
|
||||
* An Angular **service** is a singleton object created by a **service factory**. These **service
|
||||
* factories** are functions which, in turn, are created by a **service provider**.
|
||||
* The **service providers** are constructor functions. When instantiated they must contain a property
|
||||
* called `$get`, which holds the **service factory** function.
|
||||
*
|
||||
* When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the
|
||||
* correct **service provider**, instantiating it and then calling its `$get` **service factory**
|
||||
* function to get the instance of the **service**.
|
||||
*
|
||||
* Often services have no configuration options and there is no need to add methods to the service
|
||||
* provider. The provider will be no more than a constructor function with a `$get` property. For
|
||||
* these cases the {@link AUTO.$provide $provide} service has additional helper methods to register
|
||||
* services without specifying a provider.
|
||||
*
|
||||
* <pre>
|
||||
* function GreetProvider() {
|
||||
* var salutation = 'Hello';
|
||||
* * {@link AUTO.$provide#provider provider(provider)} - registers a **service provider** with the
|
||||
* {@link AUTO.$injector $injector}
|
||||
* * {@link AUTO.$provide#constant constant(obj)} - registers a value/object that can be accessed by
|
||||
* providers and services.
|
||||
* * {@link AUTO.$provide#value value(obj)} - registers a value/object that can only be accessed by
|
||||
* services, not providers.
|
||||
* * {@link AUTO.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, that
|
||||
* will be wrapped in a **service provider** object, whose `$get` property will contain the given
|
||||
* factory function.
|
||||
* * {@link AUTO.$provide#service service(class)} - registers a **constructor function**, `class` that
|
||||
* will be wrapped in a **service provider** object, whose `$get` property will instantiate a new
|
||||
* object using the given constructor function.
|
||||
*
|
||||
* this.salutation = function(text) {
|
||||
* salutation = text;
|
||||
* };
|
||||
*
|
||||
* this.$get = function() {
|
||||
* return function (name) {
|
||||
* return salutation + ' ' + name + '!';
|
||||
* };
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* describe('Greeter', function(){
|
||||
*
|
||||
* beforeEach(module(function($provide) {
|
||||
* $provide.provider('greet', GreetProvider);
|
||||
* }));
|
||||
*
|
||||
* it('should greet', inject(function(greet) {
|
||||
* expect(greet('angular')).toEqual('Hello angular!');
|
||||
* }));
|
||||
*
|
||||
* it('should allow configuration of salutation', function() {
|
||||
* module(function(greetProvider) {
|
||||
* greetProvider.salutation('Ahoj');
|
||||
* });
|
||||
* inject(function(greet) {
|
||||
* expect(greet('angular')).toEqual('Ahoj angular!');
|
||||
* });
|
||||
* });
|
||||
* </pre>
|
||||
* See the individual methods for more information and examples.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -301,7 +292,18 @@ function annotate(fn) {
|
||||
* @methodOf AUTO.$provide
|
||||
* @description
|
||||
*
|
||||
* Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
|
||||
* Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions are
|
||||
* constructor functions, whose instances are responsible for "providing" a factory for a service.
|
||||
*
|
||||
* Service provider names start with the name of the service they provide followed by `Provider`.
|
||||
* For example, the {@link ng.$log $log} service has a provider called {@link ng.$logProvider $logProvider}.
|
||||
*
|
||||
* Service provider objects can have additional methods which allow configuration of the provider and
|
||||
* its service. Importantly, you can configure what kind of service is created by the `$get` method,
|
||||
* or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a method
|
||||
* {@link ng.$logProvider#debugEnabled debugEnabled}
|
||||
* which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
|
||||
* console or not.
|
||||
*
|
||||
* @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
|
||||
* @param {(Object|function())} provider If the provider is:
|
||||
@@ -312,6 +314,70 @@ function annotate(fn) {
|
||||
* {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
|
||||
*
|
||||
* @returns {Object} registered provider instance
|
||||
|
||||
* @example
|
||||
*
|
||||
* The following example shows how to create a simple event tracking service and register it using
|
||||
* {@link AUTO.$provide#provider $provide.provider()}.
|
||||
*
|
||||
* <pre>
|
||||
* // Define the eventTracker provider
|
||||
* function EventTrackerProvider() {
|
||||
* var trackingUrl = '/track';
|
||||
*
|
||||
* // A provider method for configuring where the tracked events should been saved
|
||||
* this.setTrackingUrl = function(url) {
|
||||
* trackingUrl = url;
|
||||
* };
|
||||
*
|
||||
* // The service factory function
|
||||
* this.$get = ['$http', function($http) {
|
||||
* var trackedEvents = {};
|
||||
* return {
|
||||
* // Call this to track an event
|
||||
* event: function(event) {
|
||||
* var count = trackedEvents[event] || 0;
|
||||
* count += 1;
|
||||
* trackedEvents[event] = count;
|
||||
* return count;
|
||||
* },
|
||||
* // Call this to save the tracked events to the trackingUrl
|
||||
* save: function() {
|
||||
* $http.post(trackingUrl, trackedEvents);
|
||||
* }
|
||||
* };
|
||||
* }];
|
||||
* }
|
||||
*
|
||||
* describe('eventTracker', function() {
|
||||
* var postSpy;
|
||||
*
|
||||
* beforeEach(module(function($provide) {
|
||||
* // Register the eventTracker provider
|
||||
* $provide.provider('eventTracker', EventTrackerProvider);
|
||||
* }));
|
||||
*
|
||||
* beforeEach(module(function(eventTrackerProvider) {
|
||||
* // Configure eventTracker provider
|
||||
* eventTrackerProvider.setTrackingUrl('/custom-track');
|
||||
* }));
|
||||
*
|
||||
* it('tracks events', inject(function(eventTracker) {
|
||||
* expect(eventTracker.event('login')).toEqual(1);
|
||||
* expect(eventTracker.event('login')).toEqual(2);
|
||||
* }));
|
||||
*
|
||||
* it('saves to the tracking url', inject(function(eventTracker, $http) {
|
||||
* postSpy = spyOn($http, 'post');
|
||||
* eventTracker.event('login');
|
||||
* eventTracker.save();
|
||||
* expect(postSpy).toHaveBeenCalled();
|
||||
* expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
|
||||
* expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
|
||||
* expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
|
||||
* }));
|
||||
* });
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -320,12 +386,32 @@ function annotate(fn) {
|
||||
* @methodOf AUTO.$provide
|
||||
* @description
|
||||
*
|
||||
* A short hand for configuring services if only `$get` method is required.
|
||||
* Register a **service factory**, which will be called to return the service instance.
|
||||
* This is short for registering a service where its provider consists of only a `$get` property,
|
||||
* which is the given service factory function.
|
||||
* You should use {@link AUTO.$provide#factory $provide.factor(getFn)} if you do not need to configure
|
||||
* your service in a provider.
|
||||
*
|
||||
* @param {string} name The name of the instance.
|
||||
* @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
|
||||
* `$provide.provider(name, {$get: $getFn})`.
|
||||
* @returns {Object} registered provider instance
|
||||
*
|
||||
* @example
|
||||
* Here is an example of registering a service
|
||||
* <pre>
|
||||
* $provide.factory('ping', ['$http', function($http) {
|
||||
* return function ping() {
|
||||
* return $http.send('/ping');
|
||||
* };
|
||||
* }]);
|
||||
* </pre>
|
||||
* You would then inject and use this service like this:
|
||||
* <pre>
|
||||
* someModule.controller('Ctrl', ['ping', function(ping) {
|
||||
* ping();
|
||||
* }]);
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
@@ -335,11 +421,34 @@ function annotate(fn) {
|
||||
* @methodOf AUTO.$provide
|
||||
* @description
|
||||
*
|
||||
* A short hand for registering service of given class.
|
||||
* Register a **service constructor**, which will be invoked with `new` to create the service instance.
|
||||
* This is short for registering a service where its provider's `$get` property is the service
|
||||
* constructor function that will be used to instantiate the service instance.
|
||||
*
|
||||
* You should use {@link AUTO.$provide#service $provide.service(class)} if you define your service
|
||||
* as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}.
|
||||
*
|
||||
* @param {string} name The name of the instance.
|
||||
* @param {Function} constructor A class (constructor function) that will be instantiated.
|
||||
* @returns {Object} registered provider instance
|
||||
*
|
||||
* @example
|
||||
* Here is an example of registering a service using {@link AUTO.$provide#service $provide.service(class)}
|
||||
* that is defined as a CoffeeScript class.
|
||||
* <pre>
|
||||
* class Ping
|
||||
* constructor: (@$http)->
|
||||
* send: ()=>
|
||||
* @$http.get('/ping')
|
||||
*
|
||||
* $provide.service('ping', ['$http', Ping])
|
||||
* </pre>
|
||||
* You would then inject and use this service like this:
|
||||
* <pre>
|
||||
* someModule.controller 'Ctrl', ['ping', (ping)->
|
||||
* ping.send()
|
||||
* ]
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
@@ -349,11 +458,29 @@ function annotate(fn) {
|
||||
* @methodOf AUTO.$provide
|
||||
* @description
|
||||
*
|
||||
* A short hand for configuring services if the `$get` method is a constant.
|
||||
* Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a number,
|
||||
* an array, an object or a function. This is short for registering a service where its provider's
|
||||
* `$get` property is a factory function that takes no arguments and returns the **value service**.
|
||||
*
|
||||
* Value services are similar to constant services, except that they cannot be injected into a module
|
||||
* configuration function (see {@link angular.Module#config}) but they can be overridden by an Angular
|
||||
* {@link AUTO.$provide#decorator decorator}.
|
||||
*
|
||||
* @param {string} name The name of the instance.
|
||||
* @param {*} value The value.
|
||||
* @returns {Object} registered provider instance
|
||||
*
|
||||
* @example
|
||||
* Here are some examples of creating value services.
|
||||
* <pre>
|
||||
* $provide.constant('ADMIN_USER', 'admin');
|
||||
*
|
||||
* $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 });
|
||||
*
|
||||
* $provide.constant('halfOf', function(value) {
|
||||
* return value / 2;
|
||||
* });
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
@@ -363,13 +490,26 @@ function annotate(fn) {
|
||||
* @methodOf AUTO.$provide
|
||||
* @description
|
||||
*
|
||||
* A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
|
||||
* into configuration function (other modules) and it is not interceptable by
|
||||
* {@link AUTO.$provide#decorator decorator}.
|
||||
* Register a **constant service**, such as a string, a number, an array, an object or a function, with
|
||||
* the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be injected
|
||||
* into a module configuration function (see {@link angular.Module#config}) and it cannot be
|
||||
* overridden by an Angular {@link AUTO.$provide#decorator decorator}.
|
||||
*
|
||||
* @param {string} name The name of the constant.
|
||||
* @param {*} value The constant value.
|
||||
* @returns {Object} registered instance
|
||||
*
|
||||
* @example
|
||||
* Here a some examples of creating constants:
|
||||
* <pre>
|
||||
* $provide.constant('SHARD_HEIGHT', 306);
|
||||
*
|
||||
* $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
|
||||
*
|
||||
* $provide.constant('double', function(value) {
|
||||
* return value * 2;
|
||||
* });
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
@@ -379,17 +519,29 @@ function annotate(fn) {
|
||||
* @methodOf AUTO.$provide
|
||||
* @description
|
||||
*
|
||||
* Decoration of service, allows the decorator to intercept the service instance creation. The
|
||||
* returned instance may be the original instance, or a new instance which delegates to the
|
||||
* original instance.
|
||||
* Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator
|
||||
* intercepts the creation of a service, allowing it to override or modify the behaviour of the
|
||||
* service. The object returned by the decorator may be the original service, or a new service object
|
||||
* which replaces or wraps and delegates to the original service.
|
||||
*
|
||||
* @param {string} name The name of the service to decorate.
|
||||
* @param {function()} decorator This function will be invoked when the service needs to be
|
||||
* instantiated. The function is called using the {@link AUTO.$injector#invoke
|
||||
* injector.invoke} method and is therefore fully injectable. Local injection arguments:
|
||||
* instantiated and should return the decorated service instance. The function is called using
|
||||
* the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable.
|
||||
* Local injection arguments:
|
||||
*
|
||||
* * `$delegate` - The original service instance, which can be monkey patched, configured,
|
||||
* decorated or delegated to.
|
||||
*
|
||||
* @example
|
||||
* Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
|
||||
* calls to {@link ng.$log#error $log.warn()}.
|
||||
* <pre>
|
||||
* $provider.decorator('$log', ['$delegate', function($delegate) {
|
||||
* $delegate.warn = $delegate.error;
|
||||
* return $delegate;
|
||||
* }]);
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
@@ -602,3 +754,4 @@ function createInjector(modulesToLoad) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@
|
||||
*
|
||||
* ### Events
|
||||
* - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
|
||||
* on all DOM nodes being removed. This can be used to clean up and 3rd party bindings to the DOM
|
||||
* on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
|
||||
* element before it is removed.
|
||||
* ### Methods
|
||||
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
|
||||
|
||||
+4
-2
@@ -178,7 +178,8 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#controller
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name Controller name.
|
||||
* @param {string|Object} name Controller name, or an object map of controllers where the
|
||||
* keys are the names and the values are the constructors.
|
||||
* @param {Function} constructor Controller constructor function.
|
||||
* @description
|
||||
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
|
||||
@@ -189,7 +190,8 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#directive
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name directive name
|
||||
* @param {string|Object} name Directive name, or an object map of directives where the
|
||||
* keys are the names and the values are the factories.
|
||||
* @param {Function} directiveFactory Factory function for creating new instance of
|
||||
* directives.
|
||||
* @description
|
||||
|
||||
+29
-1
@@ -10,8 +10,36 @@
|
||||
* according to rules specified in
|
||||
* {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
|
||||
*
|
||||
* It also watches the `$location.hash()` and scroll whenever it changes to match any anchor.
|
||||
* It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
|
||||
* This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCtrl">
|
||||
<a ng-click="gotoBottom()">Go to bottom</a>
|
||||
<a id="bottom"></a> You're at the bottom!
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
function ScrollCtrl($scope, $location, $anchorScroll) {
|
||||
$scope.gotoBottom = function (){
|
||||
// set the location.hash to the id of
|
||||
// the element you wish to scroll to.
|
||||
$location.hash('bottom');
|
||||
|
||||
// call $anchorScroll()
|
||||
$anchorScroll();
|
||||
}
|
||||
}
|
||||
</file>
|
||||
<file name="style.css">
|
||||
#bottom {
|
||||
display: block;
|
||||
margin-top: 2000px;
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
function $AnchorScrollProvider() {
|
||||
|
||||
|
||||
+5
-1
@@ -238,10 +238,14 @@ function Browser(window, document, $log, $sniffer) {
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @name ng.$browser#baseHref
|
||||
* @methodOf ng.$browser
|
||||
*
|
||||
* @description
|
||||
* Returns current <base href>
|
||||
* (always relative - without domain)
|
||||
*
|
||||
* @returns {string=}
|
||||
* @returns {string=} current <base href>
|
||||
*/
|
||||
self.baseHref = function() {
|
||||
var href = baseElement.attr('href');
|
||||
|
||||
+16
-6
@@ -168,10 +168,11 @@ function $CompileProvider($provide) {
|
||||
* @description
|
||||
* Register a new directive with the compiler.
|
||||
*
|
||||
* @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
|
||||
* <code>ng-bind</code>).
|
||||
* @param {function|Array} directiveFactory An injectable directive factory function. See {@link guide/directive} for more
|
||||
* info.
|
||||
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
|
||||
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
|
||||
* names and the values are the factories.
|
||||
* @param {function|Array} directiveFactory An injectable directive factory function. See
|
||||
* {@link guide/directive} for more info.
|
||||
* @returns {ng.$compileProvider} Self for chaining.
|
||||
*/
|
||||
this.directive = function registerDirective(name, directiveFactory) {
|
||||
@@ -319,12 +320,21 @@ function $CompileProvider($provide) {
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$compile.directive.Attributes#$observe
|
||||
* @methodOf ng.$compile.directive.Attributes
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Observe an interpolated attribute.
|
||||
* The observer will never be called, if given attribute is not interpolated.
|
||||
* The interpolated value of the attribute is passed to the observer function.
|
||||
*
|
||||
* @param {string} key Normalized key. (ie ngAttribute) .
|
||||
* @param {function(*)} fn Function that will be called whenever the attribute value changes.
|
||||
* @returns {function(*)} the `fn` Function passed in.
|
||||
* @param {function(interpolatedValue)} fn Function that will be called whenever
|
||||
the interpolated value of the attribute changes.
|
||||
* See the {@link guide/directive#Attributes Directives} guide for more info.
|
||||
* @returns {function()} the `fn` parameter.
|
||||
*/
|
||||
$observe: function(key, fn) {
|
||||
var attrs = this,
|
||||
|
||||
@@ -18,7 +18,8 @@ function $ControllerProvider() {
|
||||
* @ngdoc function
|
||||
* @name ng.$controllerProvider#register
|
||||
* @methodOf ng.$controllerProvider
|
||||
* @param {string} name Controller name
|
||||
* @param {string|Object} name Controller name, or an object map of controllers where the keys are
|
||||
* the names and the values are the constructors.
|
||||
* @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
|
||||
* annotations in the array notation).
|
||||
*/
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* Modifies the default behavior of html A tag, so that the default action is prevented when href
|
||||
* attribute is empty.
|
||||
* Modifies the default behavior of the html A tag so that the default action is prevented when
|
||||
* the href attribute is empty.
|
||||
*
|
||||
* The reasoning for this change is to allow easy creation of action links with `ngClick` directive
|
||||
* This change permits the easy creation of action links with the `ngClick` directive
|
||||
* without changing the location or causing page reloads, e.g.:
|
||||
* `<a href="" ng-click="model.$save()">Save</a>`
|
||||
*/
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
* @restrict A
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like {{hash}} in an href attribute makes
|
||||
* the page open to a wrong URL, if the user clicks that link before
|
||||
* angular has a chance to replace the {{hash}} with actual URL, the
|
||||
* link will be broken and will most likely return a 404 error.
|
||||
* Using Angular markup like `{{hash}}` in an href attribute will
|
||||
* make the link go to the wrong URL if the user clicks it before
|
||||
* Angular has a chance to replace the `{{hash}}` markup with its
|
||||
* value. Until Angular replaces the markup the link will be broken
|
||||
* and will most likely return a 404 error.
|
||||
*
|
||||
* The `ngHref` directive solves this problem.
|
||||
*
|
||||
* The buggy way to write it:
|
||||
* The wrong way to write it:
|
||||
* <pre>
|
||||
* <a href="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* </pre>
|
||||
@@ -26,7 +28,8 @@
|
||||
* @param {template} ngHref any string which can contain `{{}}` markup.
|
||||
*
|
||||
* @example
|
||||
* This example uses `link` variable inside `href` attribute:
|
||||
* This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
|
||||
* in links and their different behaviors:
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-model="value" /><br />
|
||||
@@ -119,9 +122,9 @@
|
||||
* </div>
|
||||
* </pre>
|
||||
*
|
||||
* The HTML specs do not require browsers to preserve the special attributes such as disabled.
|
||||
* (The presence of them means true and absence means false)
|
||||
* This prevents the angular compiler from correctly retrieving the binding expression.
|
||||
* The HTML specs do not require browsers to preserve the values of special attributes
|
||||
* such as disabled. (The presence of them means true and absence means false)
|
||||
* This prevents the Angular compiler from correctly retrieving the binding expression.
|
||||
* To solve this problem, we introduce the `ngDisabled` directive.
|
||||
*
|
||||
* @example
|
||||
@@ -140,7 +143,8 @@
|
||||
</doc:example>
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {expression} ngDisabled Angular expression that will be evaluated.
|
||||
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "disabled" will be set on the element.
|
||||
*/
|
||||
|
||||
|
||||
@@ -170,7 +174,8 @@
|
||||
</doc:example>
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {expression} ngChecked Angular expression that will be evaluated.
|
||||
* @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "checked" will be set on the element.
|
||||
*/
|
||||
|
||||
|
||||
@@ -206,7 +211,8 @@
|
||||
</doc:example>
|
||||
*
|
||||
* @element SELECT
|
||||
* @param {expression} ngMultiple Angular expression that will be evaluated.
|
||||
* @param {expression} ngMultiple If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "multiple" will be set on the element.
|
||||
*/
|
||||
|
||||
|
||||
@@ -236,7 +242,8 @@
|
||||
</doc:example>
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {string} expression Angular expression that will be evaluated.
|
||||
* @param {string} expression If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "readonly" will be set on the element.
|
||||
*/
|
||||
|
||||
|
||||
@@ -269,7 +276,8 @@
|
||||
</doc:example>
|
||||
*
|
||||
* @element OPTION
|
||||
* @param {string} expression Angular expression that will be evaluated.
|
||||
* @param {string} expression If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "selected" will be set on the element.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -188,15 +188,19 @@ function FormController(element, attrs) {
|
||||
* Directive that instantiates
|
||||
* {@link ng.directive:form.FormController FormController}.
|
||||
*
|
||||
* If `name` attribute is specified, the form controller is published onto the current scope under
|
||||
* If the `name` attribute is specified, the form controller is published onto the current scope under
|
||||
* this name.
|
||||
*
|
||||
* # Alias: {@link ng.directive:ngForm `ngForm`}
|
||||
*
|
||||
* In angular forms can be nested. This means that the outer form is valid when all of the child
|
||||
* forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
|
||||
* reason angular provides {@link ng.directive:ngForm `ngForm`} alias
|
||||
* which behaves identical to `<form>` but allows form nesting.
|
||||
* In Angular forms can be nested. This means that the outer form is valid when all of the child
|
||||
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
|
||||
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
|
||||
* `<form>` but can be nested. This allows you to have nested forms, which is very useful when
|
||||
* using Angular validation directives in forms that are dynamically generated using the
|
||||
* {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
|
||||
* attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
|
||||
* `ngForm` directive and nest these in an outer `form` element.
|
||||
*
|
||||
*
|
||||
* # CSS classes
|
||||
@@ -206,12 +210,12 @@ function FormController(element, attrs) {
|
||||
* - `ng-dirty` Is set if the form is dirty.
|
||||
*
|
||||
*
|
||||
* # Submitting a form and preventing default action
|
||||
* # Submitting a form and preventing the default action
|
||||
*
|
||||
* Since the role of forms in client-side Angular applications is different than in classical
|
||||
* roundtrip apps, it is desirable for the browser not to translate the form submission into a full
|
||||
* page reload that sends the data to the server. Instead some javascript logic should be triggered
|
||||
* to handle the form submission in application specific way.
|
||||
* to handle the form submission in an application-specific way.
|
||||
*
|
||||
* For this reason, Angular prevents the default action (form submission to the server) unless the
|
||||
* `<form>` element has an `action` attribute specified.
|
||||
@@ -223,8 +227,9 @@ function FormController(element, attrs) {
|
||||
* - {@link ng.directive:ngClick ngClick} directive on the first
|
||||
* button or input field of type submit (input[type=submit])
|
||||
*
|
||||
* To prevent double execution of the handler, use only one of ngSubmit or ngClick directives. This
|
||||
* is because of the following form submission rules coming from the html spec:
|
||||
* To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
|
||||
* or {@link ng.directive:ngClick ngClick} directives.
|
||||
* This is because of the following form submission rules in the HTML specification:
|
||||
*
|
||||
* - If a form has only one input field then hitting enter in this field triggers form submit
|
||||
* (`ngSubmit`)
|
||||
|
||||
+106
-19
@@ -824,19 +824,19 @@ var VALID_CLASS = 'ng-valid',
|
||||
* @description
|
||||
*
|
||||
* `NgModelController` provides API for the `ng-model` directive. The controller contains
|
||||
* services for data-binding, validation, CSS update, value formatting and parsing. It
|
||||
* specifically does not contain any logic which deals with DOM rendering or listening to
|
||||
* DOM events. The `NgModelController` is meant to be extended by other directives where, the
|
||||
* directive provides DOM manipulation and the `NgModelController` provides the data-binding.
|
||||
* Note that you cannot use `NgModelController` in a directive with an isolated scope,
|
||||
* as, in that case, the `ng-model` value gets put into the isolated scope and does not get
|
||||
* propogated to the parent scope.
|
||||
*
|
||||
* services for data-binding, validation, CSS updates, and value formatting and parsing. It
|
||||
* purposefully does not contain any logic which deals with DOM rendering or listening to
|
||||
* DOM events. Such DOM related logic should be provided by other directives which make use of
|
||||
* `NgModelController` for data-binding.
|
||||
*
|
||||
* ## Custom Control Example
|
||||
* This example shows how to use `NgModelController` with a custom control to achieve
|
||||
* data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
|
||||
* collaborate together to achieve the desired result.
|
||||
*
|
||||
* Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
|
||||
* contents be edited in place by the user. This will not work on older browsers.
|
||||
*
|
||||
* <example module="customControl">
|
||||
<file name="style.css">
|
||||
[contenteditable] {
|
||||
@@ -907,6 +907,39 @@ var VALID_CLASS = 'ng-valid',
|
||||
</file>
|
||||
* </example>
|
||||
*
|
||||
* ## Isolated Scope Pitfall
|
||||
*
|
||||
* Note that if you have a directive with an isolated scope, you cannot require `ngModel`
|
||||
* since the model value will be looked up on the isolated scope rather than the outer scope.
|
||||
* When the directive updates the model value, calling `ngModel.$setViewValue()` the property
|
||||
* on the outer scope will not be updated.
|
||||
*
|
||||
* Here is an example of this situation. You'll notice that even though both 'input' and 'div'
|
||||
* seem to be attached to the same model, they are not kept in synch.
|
||||
*
|
||||
* <example module="badIsolatedDirective">
|
||||
<file name="script.js">
|
||||
angular.module('badIsolatedDirective', []).directive('bad', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
scope: { },
|
||||
template: '<input ng-model="innerModel">',
|
||||
link: function(scope, element, attrs, ngModel) {
|
||||
scope.$watch('innerModel', function(value) {
|
||||
console.log(value);
|
||||
ngModel.$setViewValue(value);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<input ng-model="someModel">
|
||||
<div bad ng-model="someModel"></div>
|
||||
</file>
|
||||
* </example>
|
||||
*
|
||||
*
|
||||
*/
|
||||
var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
|
||||
function($scope, $exceptionHandler, $attr, $element, $parse) {
|
||||
@@ -1077,22 +1110,27 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* @element input
|
||||
*
|
||||
* @description
|
||||
* Is a directive that tells Angular to do two-way data binding. It works together with `input`,
|
||||
* `select`, `textarea`. You can easily write your own directives to use `ngModel` as well.
|
||||
* The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
|
||||
* property on the scope using {@link ng.directive:ngModel.NgModelController NgModelController},
|
||||
* which is created and exposed by this directive.
|
||||
*
|
||||
* `ngModel` is responsible for:
|
||||
*
|
||||
* - binding the view into the model, which other directives such as `input`, `textarea` or `select`
|
||||
* require,
|
||||
* - providing validation behavior (i.e. required, number, email, url),
|
||||
* - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
|
||||
* - setting related css class onto the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`),
|
||||
* - register the control with parent {@link ng.directive:form form}.
|
||||
* - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
|
||||
* require.
|
||||
* - Providing validation behavior (i.e. required, number, email, url).
|
||||
* - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
|
||||
* - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`).
|
||||
* - Registering the control with its parent {@link ng.directive:form form}.
|
||||
*
|
||||
* Note: `ngModel` will try to bind to the property given by evaluating the expression on the
|
||||
* current scope. If the property doesn't already exist on this scope, it will be created
|
||||
* implicitly and added to the scope.
|
||||
*
|
||||
* For best practices on using `ngModel`, see:
|
||||
*
|
||||
* - {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes}
|
||||
*
|
||||
* For basic examples, how to use `ngModel`, see:
|
||||
*
|
||||
* - {@link ng.directive:input input}
|
||||
@@ -1292,17 +1330,66 @@ var ngListDirective = function() {
|
||||
|
||||
|
||||
var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngValue
|
||||
*
|
||||
* @description
|
||||
* Binds the given expression to the value of `input[select]` or `input[radio]`, so
|
||||
* that when the element is selected, the `ngModel` of that element is set to the
|
||||
* bound value.
|
||||
*
|
||||
* `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
|
||||
* shown below.
|
||||
*
|
||||
* @element input
|
||||
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
|
||||
* of the `input` element
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl($scope) {
|
||||
$scope.names = ['pizza', 'unicorns', 'robots'];
|
||||
$scope.my = { favorite: 'unicorns' };
|
||||
}
|
||||
</script>
|
||||
<form ng-controller="Ctrl">
|
||||
<h2>Which is your favorite?</h2>
|
||||
<label ng-repeat="name in names" for="{{name}}">
|
||||
{{name}}
|
||||
<input type="radio"
|
||||
ng-model="my.favorite"
|
||||
ng-value="name"
|
||||
id="{{name}}"
|
||||
name="favorite">
|
||||
</label>
|
||||
</span>
|
||||
<div>You chose {{my.favorite}}</div>
|
||||
</form>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should initialize to model', function() {
|
||||
expect(binding('my.favorite')).toEqual('unicorns');
|
||||
});
|
||||
it('should bind the values to the inputs', function() {
|
||||
input('my.favorite').select('pizza');
|
||||
expect(binding('my.favorite')).toEqual('pizza');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
*/
|
||||
var ngValueDirective = function() {
|
||||
return {
|
||||
priority: 100,
|
||||
compile: function(tpl, tplAttr) {
|
||||
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
|
||||
return function(scope, elm, attr) {
|
||||
return function ngValueConstantLink(scope, elm, attr) {
|
||||
attr.$set('value', scope.$eval(attr.ngValue));
|
||||
};
|
||||
} else {
|
||||
return function(scope, elm, attr) {
|
||||
return function ngValueLink(scope, elm, attr) {
|
||||
scope.$watch(attr.ngValue, function valueWatchAction(value) {
|
||||
attr.$set('value', value);
|
||||
});
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
* @name ng.directive:ngController
|
||||
*
|
||||
* @description
|
||||
* The `ngController` directive assigns behavior to a scope. This is a key aspect of how angular
|
||||
* The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
|
||||
* supports the principles behind the Model-View-Controller design pattern.
|
||||
*
|
||||
* MVC components in angular:
|
||||
*
|
||||
* * Model — The Model is data in scope properties; scopes are attached to the DOM.
|
||||
* * View — The template (HTML with data bindings) is rendered into the View.
|
||||
* * Controller — The `ngController` directive specifies a Controller class; the class has
|
||||
* methods that typically express the business logic behind the application.
|
||||
* * Model — The Model is scope properties; scopes are attached to DOM where scope properties
|
||||
* are accessed through bindings.
|
||||
* * View — The template (HTML with data bindings) that is rendered into the View.
|
||||
* * Controller — The `ngController` directive specifies a Controller class; the class contains business
|
||||
* logic behind the application to decorate the scope with functions and values
|
||||
*
|
||||
* Note that an alternative way to define controllers is via the {@link ng.$route $route} service.
|
||||
*
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
|
||||
* any of these restrictions.
|
||||
*
|
||||
* AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
|
||||
* it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
|
||||
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
|
||||
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
|
||||
* evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
|
||||
* be raised.
|
||||
*
|
||||
* In order to use this feature put `ngCsp` directive on the root element of the application.
|
||||
* In order to use this feature put the `ngCsp` directive on the root element of the application.
|
||||
*
|
||||
* @example
|
||||
* This example shows how to apply the `ngCsp` directive to the `html` tag.
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* @name ng.directive:ngClick
|
||||
*
|
||||
* @description
|
||||
* The ngClick allows you to specify custom behavior when
|
||||
* element is clicked.
|
||||
* The ngClick directive allows you to specify custom behavior when
|
||||
* an element is clicked.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
|
||||
@@ -58,11 +58,11 @@ forEach(
|
||||
* @name ng.directive:ngDblclick
|
||||
*
|
||||
* @description
|
||||
* The `ngDblclick` directive allows you to specify custom behavior on dblclick event.
|
||||
* The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
|
||||
* dblclick. (Event object is available as `$event`)
|
||||
* a dblclick. (The Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
|
||||
@@ -384,6 +384,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
modelValue = ctrl.$modelValue,
|
||||
values = valuesFn(scope) || [],
|
||||
keys = keyName ? sortedKeys(values) : values,
|
||||
key,
|
||||
groupLength, length,
|
||||
groupIndex, index,
|
||||
locals = {},
|
||||
@@ -399,8 +400,17 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
|
||||
// We now build up the list of options we need (we merge later)
|
||||
for (index = 0; length = keys.length, index < length; index++) {
|
||||
locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index];
|
||||
optionGroupName = groupByFn(scope, locals) || '';
|
||||
|
||||
key = index;
|
||||
if (keyName) {
|
||||
key = keys[index];
|
||||
if ( key.charAt(0) === '$' ) continue;
|
||||
locals[keyName] = key;
|
||||
}
|
||||
|
||||
locals[valueName] = values[key];
|
||||
|
||||
optionGroupName = groupByFn(scope, locals) || '';
|
||||
if (!(optionGroup = optionGroups[optionGroupName])) {
|
||||
optionGroup = optionGroups[optionGroupName] = [];
|
||||
optionGroupNames.push(optionGroupName);
|
||||
|
||||
@@ -9,10 +9,24 @@
|
||||
* Any uncaught exception in angular expressions is delegated to this service.
|
||||
* The default implementation simply delegates to `$log.error` which logs it into
|
||||
* the browser console.
|
||||
*
|
||||
*
|
||||
* In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
|
||||
* {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
|
||||
*
|
||||
* ## Example:
|
||||
*
|
||||
* <pre>
|
||||
* angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
|
||||
* return function (exception, cause) {
|
||||
* exception.message += ' (caused by "' + cause + '")';
|
||||
* throw exception;
|
||||
* };
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* This example will override the normal action of `$exceptionHandler`, to make angular
|
||||
* exceptions fail hard when they happen, instead of just logging to the console.
|
||||
*
|
||||
* @param {Error} exception Exception associated with the error.
|
||||
* @param {string=} cause optional information about the context in which
|
||||
* the error was thrown.
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<table class="friend">
|
||||
<tr>
|
||||
<th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
|
||||
(<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
|
||||
(<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
|
||||
<th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
|
||||
<th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
|
||||
</tr>
|
||||
|
||||
+30
-3
@@ -185,6 +185,33 @@ function $HttpProvider() {
|
||||
* will result in the success callback being called. Note that if the response is a redirect,
|
||||
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
||||
* called for such responses.
|
||||
*
|
||||
* # Calling $http from outside AngularJS
|
||||
* The `$http` service will not actually send the request until the next `$digest()` is executed.
|
||||
* Normally this is not an issue, since almost all the time your call to `$http` will be from within
|
||||
* a `$apply()` block.
|
||||
* If you are calling `$http` from outside Angular, then you should wrap it in a call to `$apply`
|
||||
* to cause a $digest to occur and also to handle errors in the block correctly.
|
||||
*
|
||||
* ```
|
||||
* $scope.$apply(function() {
|
||||
* $http(...);
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* # Writing Unit Tests that use $http
|
||||
* When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do not
|
||||
* trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have been
|
||||
* made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the code
|
||||
* that calls the `$http()` method inside a $apply block as explained in the previous section.
|
||||
*
|
||||
* ```
|
||||
* $httpBackend.expectGET(...);
|
||||
* $scope.$apply(function() {
|
||||
* $http.get(...);
|
||||
* });
|
||||
* $httpBackend.flush();
|
||||
* ```
|
||||
*
|
||||
* # Shortcut methods
|
||||
*
|
||||
@@ -224,7 +251,7 @@ function $HttpProvider() {
|
||||
* To add or overwrite these defaults, simply add or remove a property from these configuration
|
||||
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
|
||||
* with the lowercased HTTP method name as the key, e.g.
|
||||
* `$httpProvider.defaults.headers.get['My-Header']='value'`.
|
||||
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
|
||||
*
|
||||
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
|
||||
* fashion.
|
||||
@@ -706,7 +733,7 @@ function $HttpProvider() {
|
||||
|
||||
if (cache) {
|
||||
cachedResp = cache.get(url);
|
||||
if (cachedResp) {
|
||||
if (isDefined(cachedResp)) {
|
||||
if (cachedResp.then) {
|
||||
// cached request has already been sent, but there is no response yet
|
||||
cachedResp.then(removePendingReq, removePendingReq);
|
||||
@@ -726,7 +753,7 @@ function $HttpProvider() {
|
||||
}
|
||||
|
||||
// if we won't have the response in cache, send the request to the backend
|
||||
if (!cachedResp) {
|
||||
if (isUndefined(cachedResp)) {
|
||||
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
|
||||
config.withCredentials);
|
||||
}
|
||||
|
||||
+1
-1
@@ -494,7 +494,7 @@ function $LocationProvider(){
|
||||
* @name ng.$locationProvider#html5Mode
|
||||
* @methodOf ng.$locationProvider
|
||||
* @description
|
||||
* @param {string=} mode Use HTML5 strategy if available.
|
||||
* @param {boolean=} mode Use HTML5 strategy if available.
|
||||
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
||||
*/
|
||||
this.html5Mode = function(mode) {
|
||||
|
||||
+2
-2
@@ -377,8 +377,8 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
* @param {Array.<Promise>} promises An array of promises.
|
||||
* @returns {Promise} Returns a single promise that will be resolved with an array of values,
|
||||
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
||||
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
||||
* same rejection.
|
||||
* the promises is resolved with a rejection, this resulting promise will be rejected with the
|
||||
* same rejection value.
|
||||
*/
|
||||
function all(promises) {
|
||||
var deferred = defer(),
|
||||
|
||||
+4
-2
@@ -55,8 +55,10 @@
|
||||
* @description
|
||||
*
|
||||
* Every application has a single root {@link ng.$rootScope.Scope scope}.
|
||||
* All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
|
||||
* event processing life-cycle. See {@link guide/scope developer guide on scopes}.
|
||||
* All other scopes are descendant scopes of the root scope. Scopes provide separation
|
||||
* between the model and the view, via a mechanism for watching the model for changes.
|
||||
* They also provide an event emission/broadcast and subscription facility. See the
|
||||
* {@link guide/scope developer guide on scopes}.
|
||||
*/
|
||||
function $RootScopeProvider(){
|
||||
var TTL = 10;
|
||||
|
||||
@@ -31,6 +31,94 @@ function $TimeoutProvider() {
|
||||
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
||||
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
||||
* promise will be resolved with is the return value of the `fn` function.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$timeout) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
stop = $timeout(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
$scope.fight();
|
||||
} else {
|
||||
$timeout.cancel(stop);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
$timeout.cancel(stop);
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $timeout and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
timeoutId; // timeoutId, so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
// schedule update in one second
|
||||
function updateLater() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
updateLater(); // schedule another update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
});
|
||||
|
||||
updateLater(); // kick off the UI update process.
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function timeout(fn, delay, invokeApply) {
|
||||
var deferred = $q.defer(),
|
||||
|
||||
Vendored
+34
-2
@@ -1735,8 +1735,40 @@ window.jasmine && (function(window) {
|
||||
* instance of {@link AUTO.$injector $injector} per test, which is then used for
|
||||
* resolving references.
|
||||
*
|
||||
* See also {@link angular.mock.module module}
|
||||
*
|
||||
* ## Resolving References (Underscore Wrapping)
|
||||
* Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
|
||||
* in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
|
||||
* that is declared in the scope of the `describe()` block. Since we would, most likely, want
|
||||
* the variable to have the same name of the reference we have a problem, since the parameter
|
||||
* to the `inject()` function would hide the outer variable.
|
||||
*
|
||||
* To help with this, the injected parameters can, optionally, be enclosed with underscores.
|
||||
* These are ignored by the injector when the reference name is resolved.
|
||||
*
|
||||
* For example, the parameter `_myService_` would be resolved as the reference `myService`.
|
||||
* Since it is available in the function body as _myService_, we can then assign it to a variable
|
||||
* defined in an outer scope.
|
||||
*
|
||||
* ```
|
||||
* // Defined out reference variable outside
|
||||
* var myService;
|
||||
*
|
||||
* // Wrap the parameter in underscores
|
||||
* beforeEach( inject( function(_myService_){
|
||||
* myService = _myService_;
|
||||
* }));
|
||||
*
|
||||
* // Use myService in a series of tests.
|
||||
* it('makes use of myService', function() {
|
||||
* myService.doStuff();
|
||||
* });
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* See also {@link angular.mock.module angular.mock.module}
|
||||
*
|
||||
* ## Example
|
||||
* Example of what a typical jasmine tests looks like with the inject method.
|
||||
* <pre>
|
||||
*
|
||||
@@ -1773,7 +1805,7 @@ window.jasmine && (function(window) {
|
||||
* });
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param {...Function} fns any number of functions which will be injected using the injector.
|
||||
*/
|
||||
window.inject = angular.mock.inject = function() {
|
||||
|
||||
@@ -141,6 +141,7 @@ var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:
|
||||
BEGIN_TAG_REGEXP = /^</,
|
||||
BEGING_END_TAGE_REGEXP = /^<\s*\//,
|
||||
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
||||
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
|
||||
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
||||
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/i,
|
||||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
|
||||
@@ -223,7 +224,14 @@ function htmlParser( html, handler ) {
|
||||
html = html.substring( index + 3 );
|
||||
chars = false;
|
||||
}
|
||||
// DOCTYPE
|
||||
} else if ( DOCTYPE_REGEXP.test(html) ) {
|
||||
match = html.match( DOCTYPE_REGEXP );
|
||||
|
||||
if ( match ) {
|
||||
html = html.replace( match[0] , '');
|
||||
chars = false;
|
||||
}
|
||||
// end tag
|
||||
} else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
|
||||
match = html.match( END_TAG_REGEXP );
|
||||
|
||||
@@ -69,18 +69,17 @@ angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
|
||||
*/
|
||||
angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
|
||||
angular.scenario.matcher[name] = function(expected) {
|
||||
var prefix = 'expect ' + this.future.name + ' ';
|
||||
if (this.inverse) {
|
||||
prefix += 'not ';
|
||||
}
|
||||
var description = this.future.name +
|
||||
(this.inverse ? ' not ' : ' ') + name +
|
||||
' ' + angular.toJson(expected);
|
||||
var self = this;
|
||||
this.addFuture(prefix + name + ' ' + angular.toJson(expected),
|
||||
this.addFuture('expect ' + description,
|
||||
function(done) {
|
||||
var error;
|
||||
self.actual = self.future.value;
|
||||
if ((self.inverse && fn.call(self, expected)) ||
|
||||
(!self.inverse && !fn.call(self, expected))) {
|
||||
error = 'expected ' + angular.toJson(expected) +
|
||||
error = 'expected ' + description +
|
||||
' but was ' + angular.toJson(self.actual);
|
||||
}
|
||||
done(error);
|
||||
|
||||
@@ -187,9 +187,14 @@ describe('$compile', function() {
|
||||
if (msie < 9) return;
|
||||
|
||||
element = jqLite('<div>{{1+2}}</div>');
|
||||
element[0].childNodes[1] = {nodeType: 3, nodeName: 'OBJECT', textContent: 'fake node'};
|
||||
|
||||
if (!element[0].childNodes[1]) return; //browser doesn't support this kind of mocking
|
||||
try {
|
||||
element[0].childNodes[1] = {nodeType: 3, nodeName: 'OBJECT', textContent: 'fake node'};
|
||||
} catch(e) {
|
||||
} finally {
|
||||
if (!element[0].childNodes[1]) return; //browser doesn't support this kind of mocking
|
||||
}
|
||||
|
||||
expect(element[0].childNodes[1].textContent).toBe('fake node');
|
||||
|
||||
$compile(element)($rootScope);
|
||||
|
||||
@@ -693,6 +693,21 @@ describe('select', function() {
|
||||
expect(jqLite(element.find('option')[0]).text()).toEqual('blank');
|
||||
});
|
||||
|
||||
it('should ignore $ and $$ properties', function() {
|
||||
createSelect({
|
||||
'ng-options': 'key as value for (key, value) in object',
|
||||
'ng-model': 'selected'
|
||||
});
|
||||
|
||||
scope.$apply(function() {
|
||||
scope.object = {'regularProperty': 'visible', '$$private': 'invisible', '$property': 'invisible'};
|
||||
scope.selected = 'regularProperty';
|
||||
});
|
||||
|
||||
var options = element.find('option');
|
||||
expect(options.length).toEqual(1);
|
||||
expect(sortedHtml(options[0])).toEqual('<option value="regularProperty">visible</option>');
|
||||
});
|
||||
|
||||
describe('binding', function() {
|
||||
|
||||
|
||||
@@ -896,6 +896,20 @@ describe('$http', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should allow the cached value to be an empty string', function () {
|
||||
cache.put('/abc', '');
|
||||
|
||||
callback.andCallFake(function (response, status, headers) {
|
||||
expect(response).toBe('');
|
||||
expect(status).toBe(200);
|
||||
});
|
||||
|
||||
$http({method: 'GET', url: '/abc', cache: cache}).success(callback);
|
||||
$rootScope.$digest();
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should default to status code 200 and empty headers if cache contains a non-array element',
|
||||
inject(function($rootScope) {
|
||||
cache.put('/myurl', 'simple response');
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('HTML', function() {
|
||||
attrs: attrs,
|
||||
unary: unary
|
||||
};
|
||||
// Since different browsers handle newlines differenttly we trim
|
||||
// Since different browsers handle newlines differently we trim
|
||||
// so that it is easier to write tests.
|
||||
angular.forEach(attrs, function(value, key) {
|
||||
attrs[key] = value.replace(/^\s*/, '').replace(/\s*$/, '')
|
||||
@@ -80,6 +80,13 @@ describe('HTML', function() {
|
||||
expectHTML('a<SCRIPT>evil< / scrIpt >c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
it('should remove DOCTYPE header', function() {
|
||||
expectHTML('<!DOCTYPE html>').toEqual('');
|
||||
expectHTML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n"http://www.w3.org/TR/html4/strict.dtd">').toEqual('');
|
||||
expectHTML('a<!DOCTYPE html>c.').toEqual('ac.');
|
||||
expectHTML('a<!DocTyPe html>c.').toEqual('ac.');
|
||||
});
|
||||
|
||||
it('should remove nested script', function() {
|
||||
expectHTML('a< SCRIPT >A< SCRIPT >evil< / scrIpt >B< / scrIpt >c.').toEqual('ac.');
|
||||
});
|
||||
@@ -286,5 +293,6 @@ describe('HTML', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('angular.scenario.Application', function() {
|
||||
return {x:counter++, document:{x:counter++}};
|
||||
};
|
||||
app.navigateTo('http://www.google.com/');
|
||||
app.executeAction(function($document, $window) {
|
||||
app.executeAction(function($window, $document) {
|
||||
testWindow = $window;
|
||||
testDocument = $document;
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* Installation:
|
||||
* >> cd <angular-repo>
|
||||
* >> ln -s validate-commit-msg.js .git/hooks/commit-msg
|
||||
* >> ln -s ../../validate-commit-msg.js .git/hooks/commit-msg
|
||||
*/
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
|
||||
Reference in New Issue
Block a user