Compare commits

...

80 Commits

Author SHA1 Message Date
Chirayu Krishnappa f031127160 fix(i18n): update obsolete/404 code.google.com links 2015-04-28 00:49:37 -07:00
Martin Probst 00b44d8e12 refactor(externs): move Closure Externs back to Closure code repository
While Closure Compiler generally recommends to maintain the externs for
projects together with their source, this has not worked well for
AngularJS:
- Changes to externs must be tested; they can break clients. AngularJS
  has no testing infrastructure for this.
- Changes mostly come from users inside of Google and are much more
  easily submitted together with the code using them within Google's
  repository.

This change deletes the externs here and adds a README.closure.md to
document the change. They will be added back to Closure Compiler in a
separate submit.

Closes #5907
2014-01-22 11:39:09 -08:00
Igor Minar ca865d29a3 test(compileSpec): fix broken build on FF
FF 26.0 now throws:

"TypeError: NodeList doesn't have an indexed property setter."

when we try to assign to `childNodes[1]`, since this test still works properly
on Chrome and the issue being tested is not a cross-browser issues, I'm
just making the patchability check more robust instead of trying to figure
out how to make this test fully pass on FF.
2014-01-22 11:19:31 -08:00
Martin Probst 3ccec13aa7 feat(Angular.js): add externs file for Closure Compiler
This adds an (incomplete) externs file for use with the Closure Compiler. Users
can pass this as -extern to the compiler pass to get type checking and protect
their AngularJS use against property renaming in advanced compilation mode.
2013-10-30 14:59:33 -07:00
Daniel Lamb 43d49013d1 revert(validate-commit-msg): fix incorrect comment
Revert d5b62465f0 since it was not valid.

Closes #3952
2013-10-21 16:27:04 +01:00
Pete Bacon Darwin 116fac0562 docs(guide/controller): improve guidance and examples
Remove mention of global controller functions
Convert larger examples to runnable demos
Remove mention of pre-1.0 controllers, in particular discussion of
controller inheritance.

TODO: Probably could do with updating to explain the "controller as" syntax
at some point.

Closes: #4373
2013-10-11 12:59:39 +01:00
Felix c3024254b6 docs(guide/controller): use .controller syntax
Use the recommended `module.controller` syntax rather than global
functions to define controllers in the examples.
2013-10-11 12:58:22 +01:00
Pete Bacon Darwin 770353df19 docs($provide): improve docs and examples further
Improve the "tracking" service example by adding a configuration option.
Get better formatting of the generated code samples using <pre> tags.
Move the detailed explanations into each function's documentation block.
Improve the overview and list the constituent functions by significance.

Closes #4302
2013-10-10 18:22:52 +01:00
Tim Ruffles 85b7d24357 docs($provide): improve examples and explanations
$provide's example seems awkward. Replace with more real-world example,
using an injected service, where the service defined has a good reason to
be a singleton.

There's quite a lot of confusion around $provide:
http://stackoverflow.com/search?q=angularjs+service+vs+factory
Tests for example at: http://jsbin.com/EMabAv/1/edit?js,output
2013-10-10 18:22:51 +01:00
Marko Bonaci 8469779a8e docs(tutorial/step11): correct Jasmine Matcher link
Link http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html
is no longer valid.

Closes #4329
2013-10-09 11:30:47 +01:00
Brian Ford 3374e35953 docs(ngValue): add docs for ngValue directive
Closes #4267
2013-10-07 14:42:54 +01:00
Dave Peticolas 90ff8a98d8 docs(ngModel): fix grammar and improve clarity
Closes #4291

Conflicts:
	src/ng/directive/input.js
2013-10-07 14:41:08 +01:00
Joe Hanink a4dc21ebf5 docs(angular.bind): clarify that bind is partial application
The `angular.bind` function reflects the definition of "partial application", which
reduces a function's arity rather than transforming a function with n args into a
chain of n functions, each having a single arg.

curry : f(x,y,z) -> f(x)(y)(z)
partial application : f(x,y,z) -> f(x)(y,z)

Closes #4239
2013-10-03 23:46:24 +01:00
mtaran-google ec93f94cc9 docs(guide/directive): fix indentation in example code
Closes #4241
2013-10-03 23:45:36 +01:00
gdennie 7665497a53 docs(guide/directive): clarify use of binding to scopes
The use of 'angular' as sample text is confusing to the newbie in that they are forced
to confirm that the text 'angular' is not a keyword or otherwise referring to a system
component. This is changed to a more obvious sample text.

The most common form of `ngBind` is moved to the top of the list.

Closes #4237
2013-10-03 23:44:54 +01:00
Pete Bacon Darwin 2acadc4216 docs(rootScope): improve grammar and clarity 2013-10-03 23:18:45 +01:00
paolo-delmundo c7658d9457 fix($sanitize): sanitize DOCTYPE declarations correctly
HTML to be sanitized that contains a DOCTYPE declaration were causing
the HTML parser to throw an error.  Now the parser correctly removes
the declarations when sanitizing HTML.

Closes #3931
2013-10-03 08:43:06 +01:00
Uri Goldshtein b92c650e05 docs(angular.copy): add an example with the two possible arguments
Closes #4179
2013-09-30 22:16:30 +01:00
Richard Sentino f7a0f9d841 docs(tutorial/step0): fix minor typo
Closes #4154
2013-09-30 21:42:37 +01:00
Uri Goldshtein b17d40b4a5 docs($timeout): add a $timeout example
The original example is by gxlcl.

Closes #4180
2013-09-28 15:26:36 +01:00
Thomas Tuts d745df7e5f docs(guide/overview): fix typo
Closes #4188
2013-09-28 15:05:43 +01:00
joscarsson 53b444419c docs(guide/e2e-testing): select also uses ng-model (like input)
This is specified for input fields, but not for selects. This change specifies it also for select().
2013-09-27 16:24:17 -07:00
David Bennett 9a21050b43 docs(angular.Module): fix controller and directive method parameters 2013-09-27 16:11:42 -07:00
Dave Peticolas 8473b9d558 docs(ngCsp): fix grammar 2013-09-27 13:14:23 -07:00
Dave Peticolas 679d418a50 docs(dblClick): fix grammar 2013-09-27 13:07:01 -07:00
Dave Peticolas 16d247b386 docs(ngDisabled): clarify 2013-09-27 13:06:13 -07:00
Misha Moroshko 4767d34ae8 docs(docs.css): prevent <code> elements from wrapping
Closes #4114
2013-09-25 22:39:37 +01:00
Dave Peticolas 5efc2ed5ac docs(ngHref): fix formatting and clarify
Closes #4106
2013-09-25 22:33:13 +01:00
lorint f9bf194439 docs(jqLite): fix typo
Closes #4105
2013-09-25 22:31:19 +01:00
gdennie 3c4460b513 docs(guide/$location): provide a title for section about replace()
Closes #4104
2013-09-25 22:30:10 +01:00
gdennie a98931de0e docs(guide/$location): clarify $location service role
Clean up confusing use of the term URL to refer to $location as well as 'URL in the browser'.

Closes #4103
2013-09-25 22:27:43 +01:00
Mr.Raindrop 7e5154e755 docs($http): fix adding default header to get request example
Initially, `$httpProvider.defaults.headers.get` is `undefined`, so
`$httpProvider.defaults.headers.get['My-Header']='value'` will throw an
error.

Closes #4101
2013-09-25 22:27:33 +01:00
janhartigan ec6b1cfaba docs(guide/e2e-testing): Fix typo
Closes #4100
2013-09-25 22:27:06 +01:00
Pete Bacon Darwin 8d8801f1ae fix(ngScenario): fix error message description 2013-09-25 12:43:03 +01:00
Boris Serdyuk 301647bf1b refactor(angular.toJson): use charAt instead of regexp
Provides a performance improvement when serializing to JSON strings.

Closes #4093
2013-09-23 11:16:33 +01:00
Pete Bacon Darwin 1c03a1b9c0 docs(ngModelController): clarify issue with isolated scope directive
See #4043
2013-09-19 21:09:20 +01:00
ts-web fd797cdb7e docs(input): fix spelling error and reword for clarity 2013-09-19 21:09:20 +01:00
Dave Peticolas ed1dbf2554 doc(ngApp): fix grammar 2013-09-19 20:17:49 +01:00
Jared Forsyth 022cb3dc4e docs($exceptionHandler): add an example of overriding the handler
Closes #3816
2013-09-19 14:51:50 +01:00
Maarten Stolte 4f107acfcf docs(guide/i18n): change non-existent de-ge to de-de
The de-ge locale does not exist

Closes #4053
2013-09-19 11:27:20 +01:00
Dave Peticolas f363bcb437 docs(ngForm): fix grammar and improve explanation
Closes #4050
2013-09-19 10:41:30 +01:00
Ash 7b2259f32c docs(guide/$location): describe workaround for collocated apps
When using Angular in the root of a domain with HTML5 URLs
where there are links to external paths within the same directory,
the `otherwise` route handler will catch these external files.
This can be fixed by prefixing '.' onto the links to URLs that should
be handled by angular routing.

Original Issue: #3520
Example of Fix: http://fiddle.jshell.net/fgHf6/3/

Closes #3555
2013-09-18 14:34:39 +01:00
Zachary Friedman 9e88fa18b9 docs(tutorial/step_03): add info about karma-ng-scenario plug-in
The existing documentation for this step could have people find themselves
unable to run the `e2e-test.sh` script. This note added regarding
`karma-ng-scenario` will minimize their confusion and allow people to run
the script.

Closes #4033
2013-09-18 12:45:05 +01:00
Hubert SABLONNIÈRE 094580c3da fix(scenario): include "not " in error messages if test is inverted
Closes #3840
2013-09-18 12:34:25 +01:00
James cc4d08c5f0 docs(input): clarify that contenteditable is an HTML5 attribute
Closes #3841
2013-09-17 11:44:04 +01:00
Jesse Palmer d0ae241afd docs(orderBy): fix typo in orderBy.js documentation
Closes #3838
2013-09-16 22:29:25 +01:00
Dave Peticolas e1f103a8e4 doc(api): fix grammar in a directive description
- Add missing words.
- Simplify text.
2013-09-16 16:36:19 +01:00
Dave Peticolas d17aa84be1 docs(api): fix grammar in ngClick description
- Add missing word 'directive'.
- Add missing word 'an'.
2013-09-16 16:33:51 +01:00
Ben Tesser e87c88914f docs($browser): add jsdoc tags and fix typo 2013-09-13 21:37:51 +01:00
Dean Sofer b5d48ee1f0 docs(ngController): rephrased the description for clarity 2013-09-13 14:27:26 +01:00
Pete Bacon Darwin 1c010b33aa docs($http): add examples when calling $http outside $apply
Closes #3996
2013-09-13 14:20:14 +01:00
Dang Nguyen Anh Khoa 16c7ab1ba0 docs($http): explain why $http may not make the request immediately
I came across this issue today and after researching has found out this thread on so:
http://stackoverflow.com/questions/17039998/angular-not-making-http-requests-immediately.

It took me quite sometimes to figure out this so I hope the addition in documentation could save somebody else some times and frustration.
2013-09-13 14:20:14 +01:00
Gowtam Lal 9ef5d8f318 fix(ngOptions): ignore object properties which start with $ 2013-09-13 13:22:36 +01:00
brakon 6a634e309b docs(guide/e2e_testing): clarify that .enter searches by ng-model 2013-09-13 12:34:40 +01:00
Woody Peterson 13f58447e2 test($browser): correct false positive in ApplicationSpec.js
Previously, the check that Application should return a new $window and
$document had the arguments reversed in the first call to navigateTo;
thus, the subsequent check of inequality of $window and $document in the
next navigateTo call would always pass.

This corrects the argument order, which makes this test not succeptible
to false positives.
2013-09-11 22:21:12 +01:00
cjmling bc72211e7b docs(tutorial/step-10): fix incorrect link to step-8 tests
Closes #3972
2013-09-11 20:50:26 +01:00
Paxton Hare 230e124ddb docs(ngModel): provide link for best practices.
Closes #3973
2013-09-11 20:42:15 +01:00
Randi Hillerøe 10016ab3fd docs(guide/concepts): remove div-clear-tags that break the formatting
Closes #3974
2013-09-11 20:37:44 +01:00
Butch Peters 69dc003a0b docs(Attributes): add missing documentation for $observe method
- Add proper ngdoc annotations to existing $observe documentation
- Add link to directive guide for usage example of $observe
- Add note about $observe function parameter signature

Closes #3957
2013-09-11 12:11:57 +01:00
naorye ae2fd55575 docs($q): clarify what happens when rejected
Closes #3943
2013-09-10 22:09:01 +01:00
jakub-bochenski f102fb75b6 docs(angular.copy): clarify corner cases
The behaviour when null or undefined was passed was not clear.
The exception thrown when source == destination was not documented.

Closes #3946
2013-09-10 22:07:22 +01:00
Anthony Tran 8a7240ddfd docs(forms.ngdoc): fix spacing in example
Closes #3930
2013-09-09 17:31:45 +01:00
Richard ac70ec0340 docs(README): add dashboard link
Closes #3934
2013-09-09 12:26:41 +01:00
Pete Bacon Darwin dbd90a4d78 docs(mock.inject): fix typo 2013-09-09 08:44:25 +01:00
JasonM23 5b1f9b3c2b docs(mock.inject): document underscore wrapping syntax
Add a summary describing the ignored underscore syntax sugar helper,
with a simple use case example.

Closes #3621
2013-09-05 14:35:25 +01:00
Alexander Kaidalov 08a07f2d30 docs(tutorial): fix markup for tutorial_03.png diagram
Closes #3707
2013-09-05 14:11:52 +01:00
Alexander Kaidalov b1143c9481 docs(tutorial): fix markup for tutorial_04.png diagram 2013-09-05 14:08:58 +01:00
Pete Bacon Darwin 73e1d0054c docs(tutorial): clarify use of inject() in step 9
Closes #3718
2013-09-05 13:58:34 +01:00
Pete Bacon Darwin 33ab261817 docs(booleanAttrs): improve parameter docs for boolean attributes 2013-09-05 13:29:21 +01:00
Nick Donohue 230ff0576a docs(css_styling_guide): add ng-scope and ng-binding classes
I noticed angular was adding these css classes to elements and believe they
should be listed in the documentation at this page. The ng-scope class is
mentioned in the developer guide, hence the link there, and the ng-binding
class is not mentioned anywhere else in the documentation or the guide that
I found.

Closes #3728
2013-09-05 13:07:10 +01:00
Pete Bacon Darwin e3371d7c53 docs(angular.bootstrap): clarify modules parameter
It was not clear what you could pass to specify modules to load in the
`module` parameter of this function. The `modules` parameter takes an
array.

The main case is to provide a String, which is the name of a "predefined"
angular module.
The side cases are to provide a Function (or an annotated function in the
form of an Array), which will be invoked by the injector as a run block.

It is not possible to "define" new modules via this parameter.

Closes #3692
2013-09-05 12:19:18 +01:00
Calvin Fernandez 9b2b93d9bd docs(bootstrap.ngdoc): clarify bootstrap example
Clear up confusion about module declaration when using manual bootstrap.
2013-09-05 10:24:22 +01:00
Pete Bacon Darwin d7fb721b4d docs(): parameter for html5Mode is boolean 2013-09-05 10:02:07 +01:00
Ben Lesh e7cfa5c2bf docs($anchorScroll): provide an example of basic usage.
Per a request made by Peter Bacon Darwin here:  http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html?showComment=1370941217879#c8718313084813008967
2013-09-05 08:34:35 +01:00
jankuca 2a3212a0a3 fix($http): allow empty responses to be cached
Closes #3809
2013-09-02 11:48:14 +02:00
Igor Minar 7a08a76875 chore(build): add jenkins_build.sh file
cherry-pick from the master branch with the promises-aplus tests
removed.
2013-08-30 23:36:17 +02:00
Brian Ford 22a09dddc6 chore: upgrade grunt packages to match master 2013-08-28 14:59:26 -07:00
phanboy4 8c72549cc2 docs(guide): update description of $inject mechanism to be a little clearer 2013-08-28 13:43:28 -07:00
Brian Ford bba5214930 docs(overview): improve grammar 2013-08-22 17:40:50 -07:00
Igor Minar fb194b9488 chore(release): start new 1.0.9 iteration
Marc is working on the code name :-)
2013-08-22 11:23:17 -07:00
55 changed files with 1051 additions and 361 deletions
+23
View File
@@ -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/
+1
View File
@@ -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
---------
+4 -4
View File
@@ -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:
-16
View File
@@ -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
manipulationthe presentation logic of an applicationis 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
+2
View File
@@ -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.
+8 -8
View File
@@ -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/>
&lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
&lt;span ng:bind="name"&gt; <span ng:bind="name"></span> <br/>
&lt;span ng_bind="name"&gt; <span ng_bind="name"></span> <br/>
&lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
&lt;span data-ng-bind="name"&gt; <span data-ng-bind="name"></span> <br/>
&lt;span x-ng-bind="name"&gt; <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);
+2 -2
View File
@@ -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() {
+4 -4
View File
@@ -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>
+6 -6
View File
@@ -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
+1 -1
View File
@@ -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.
+4 -1
View File
@@ -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.
+1 -1
View File
@@ -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
+6 -3
View File
@@ -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:
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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.
+1
View File
@@ -116,6 +116,7 @@
padding: 0;
font-size: inherit;
font-family: monospace;
white-space: nowrap;
}
.content h2,
+5 -5
View File
@@ -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
+40
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+2 -1
View File
@@ -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).
*/
+3 -3
View File
@@ -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>`
*/
+22 -14
View File
@@ -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.
*/
+14 -9
View File
@@ -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
View File
@@ -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);
});
+6 -5
View File
@@ -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.
*
+3 -3
View File
@@ -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.
+4 -4
View File
@@ -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}
+12 -2
View File
@@ -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);
+15 -1
View File
@@ -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.
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+88
View File
@@ -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(),
+34 -2
View File
@@ -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() {
+8
View File
@@ -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 );
+5 -6
View File
@@ -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);
+7 -2
View File
@@ -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);
+15
View File
@@ -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() {
+14
View File
@@ -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');
+9 -1
View File
@@ -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() {
});
});
});
});
+1 -1
View File
@@ -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;
});
+1 -1
View File
@@ -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');