Compare commits
180 Commits
v1.3.0-rc.5
...
v1.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
| ed6e91b318 | |||
| 7b7b082125 | |||
| 3831e45a7d | |||
| 018991f8c8 | |||
| c77f5d1a29 | |||
| 030101a43a | |||
| 2a0254e181 | |||
| ce20dd06fe | |||
| d7a78e420a | |||
| 4b4098bfca | |||
| c3b3b90bc9 | |||
| 43b1a3739a | |||
| b4db713cde | |||
| df3d739654 | |||
| 99ec8d66c5 | |||
| d1ccf17635 | |||
| c3fcbbd750 | |||
| 29d727210d | |||
| 875f8f6557 | |||
| f34c1ff53f | |||
| 54ddca537e | |||
| 2cd5b4ec44 | |||
| 4bf254c155 | |||
| d0226ebbbf | |||
| 3df9de2e31 | |||
| 4d12812bb4 | |||
| 42f7c80bb6 | |||
| 7574dd25d9 | |||
| 3b3d9218e8 | |||
| e780eeee27 | |||
| 4cccf0f2a8 | |||
| a54b25d779 | |||
| 36666f6fad | |||
| d3b1f502e3 | |||
| 94f5a285bf | |||
| 7f65f97919 | |||
| 922162853b | |||
| 655fccce3a | |||
| 40bbc98178 | |||
| 9ad6c77568 | |||
| cfe7b0e9ef | |||
| 031d4cd2a9 | |||
| acbd302efb | |||
| 37790e920d | |||
| 531a8de72c | |||
| d488a89466 | |||
| 3635721ce4 | |||
| e9c5be58ab | |||
| 5d7763ebf9 | |||
| 0a380b4264 | |||
| 52ceec2229 | |||
| 38d12de661 | |||
| 89c57a8761 | |||
| 2240c113f5 | |||
| fc56c9b3cc | |||
| 22b817ec11 | |||
| 762713e660 | |||
| d97b427656 | |||
| 303610c743 | |||
| 1025f6ebf4 | |||
| a7f886e6c8 | |||
| b8f3ad4b21 | |||
| 483ce91da2 | |||
| 31ec9f14ef | |||
| 8b921617e9 | |||
| e4ce0ddda5 | |||
| e1c0a8e642 | |||
| ba9d0738cd | |||
| 998c61cbe0 | |||
| 35e2a068ad | |||
| 146440c5b2 | |||
| bf9e7bfb5a | |||
| ed3f799b5c | |||
| b64b9ea02c | |||
| 7fa66348cb | |||
| e5c53b393b | |||
| 24d00cce4f | |||
| accb22d644 | |||
| 1785251eab | |||
| fe58238e35 | |||
| 1bd473eb45 | |||
| 9078a6ae37 | |||
| e9dcec0c5d | |||
| d5457bb83b | |||
| 036871df5e | |||
| c06e12276b | |||
| 4aaf47534e | |||
| 502bb648ff | |||
| 6cba9c5e7c | |||
| 6e5e76e4b1 | |||
| 45252c3a54 | |||
| c2edef86c5 | |||
| 5b982998c3 | |||
| d7f84e2d7f | |||
| fddf4bd5fe | |||
| c2fb4b6986 | |||
| 8b2f1a47b5 | |||
| fb1b202f38 | |||
| 47e15aa2b4 | |||
| 22da294cbb | |||
| 22407a9296 | |||
| fc70a98be4 | |||
| 49d03a5b2e | |||
| ed85ec4d70 | |||
| 6502ab0977 | |||
| 02aa4f4b85 | |||
| 69bf2f02d0 | |||
| fd375c5d46 | |||
| b8b63df664 | |||
| 28661d1a8c | |||
| 7f4d24c6fa | |||
| 399a7afafe | |||
| f277c56837 | |||
| 02be700bda | |||
| e5f4d7b10a | |||
| 63ef085b9a | |||
| 0f6aa10413 | |||
| 3345bf8bc7 | |||
| 8b568d7c38 | |||
| 520db0ca7e | |||
| 4a85512174 | |||
| 28133cbd2a | |||
| b747d3bf4b | |||
| c44fc6d811 | |||
| 1efaf3dc13 | |||
| 393c1c7c20 | |||
| 874cac825b | |||
| 57f804a4ed | |||
| a708632c9f | |||
| 353de4f531 | |||
| 09c39d2ce6 | |||
| 0dd316efea | |||
| b6f4d4b8d4 | |||
| 20685ffe11 | |||
| 9ba24c54d6 | |||
| 44746332fa | |||
| 9a2b6efd11 | |||
| e83fab9568 | |||
| 86a3361353 | |||
| ea1897606f | |||
| d71fb6f271 | |||
| addfff3c46 | |||
| 6e4955a308 | |||
| 9db70d3959 | |||
| b90f5e59cf | |||
| 9e0ab14826 | |||
| e499433f60 | |||
| bb390ef525 | |||
| aa99df9e53 | |||
| 257a3f35dc | |||
| 2230fb4c10 | |||
| 01f50e1a7b | |||
| 9f2ad53084 | |||
| c4e21efcb7 | |||
| 5030707e76 | |||
| 3f6b380bde | |||
| 12ca1e38f9 | |||
| 7b9fddfe77 | |||
| a3f44ed1f0 | |||
| b0307a33eb | |||
| 40d4bb5863 | |||
| 9c9959059e | |||
| 2691668876 | |||
| ec88017944 | |||
| da072d49a0 | |||
| 4568bc037d | |||
| e07ebded23 | |||
| 1f650bae4b | |||
| d1eec47cb8 | |||
| a4db4e6187 | |||
| aa1c23a2bf | |||
| 58e8c02c14 | |||
| 64241a57e2 | |||
| 2435e2b8f8 | |||
| 944408edf8 | |||
| 372fa6993b | |||
| 7b102323e9 | |||
| c7a9009e14 | |||
| e15d2fd472 | |||
| daf37375d3 |
@@ -10,9 +10,6 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[src/ngLocale/**]
|
||||
insert_final_newline = false
|
||||
|
||||
[dropdown-toggle.js]
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
{
|
||||
"excludeFiles": ["src/ngLocale/**"],
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowSpaceAfterObjectKeys": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
|
||||
"disallowSpaceBeforeBinaryOperators": [","],
|
||||
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
|
||||
"disallowSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInNamedFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"disallowTrailingComma": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"requireRightStickedOperators": ["!"],
|
||||
"requireLeftStickedOperators": [","]
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"validateLineBreaks": "LF",
|
||||
"validateParameterSeparator": ", "
|
||||
}
|
||||
|
||||
@@ -5,13 +5,11 @@
|
||||
|
||||
{
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"disallowLeftStickedOperators": ["?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"disallowRightStickedOperators": ["?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"validateJSDoc": {
|
||||
"checkParamNames": true,
|
||||
"requireParamTypes": true
|
||||
|
||||
@@ -1,3 +1,75 @@
|
||||
<a name="1.3.0"></a>
|
||||
# 1.3.0 superluminal-nudge (2014-10-13)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$browser:**
|
||||
- account for IE deserializing history.state on each read
|
||||
([1efaf3dc](https://github.com/angular/angular.js/commit/1efaf3dc136f822703a9cda55afac7895a923ccb),
|
||||
[#9587](https://github.com/angular/angular.js/issues/9587), [#9545](https://github.com/angular/angular.js/issues/9545))
|
||||
- do not decode cookies that do not appear encoded
|
||||
([9c995905](https://github.com/angular/angular.js/commit/9c9959059eb84f0f1d748b70b50ec47b7d23d065),
|
||||
[#9211](https://github.com/angular/angular.js/issues/9211), [#9225](https://github.com/angular/angular.js/issues/9225))
|
||||
- **$http:**
|
||||
- allow empty json response
|
||||
([9ba24c54](https://github.com/angular/angular.js/commit/9ba24c54d60e643b1450cc5cfa8f990bd524c130),
|
||||
[#9532](https://github.com/angular/angular.js/issues/9532), [#9562](https://github.com/angular/angular.js/issues/9562))
|
||||
- don't run transformData on HEAD methods
|
||||
([6e4955a3](https://github.com/angular/angular.js/commit/6e4955a3086555d8ca30c29955faa213b39c6f27),
|
||||
[#9528](https://github.com/angular/angular.js/issues/9528), [#9529](https://github.com/angular/angular.js/issues/9529))
|
||||
- **$injector:** ensure $get method invoked with provider context
|
||||
([372fa699](https://github.com/angular/angular.js/commit/372fa6993b2b1b4848aa4be3c3e11f69244fca6f),
|
||||
[#9511](https://github.com/angular/angular.js/issues/9511), [#9512](https://github.com/angular/angular.js/issues/9512))
|
||||
- **$location:** use clone of passed search() object
|
||||
([c7a9009e](https://github.com/angular/angular.js/commit/c7a9009e143299f0e45a85d715ff22fc676d3f93),
|
||||
[#9445](https://github.com/angular/angular.js/issues/9445))
|
||||
- **$parse:** stabilize one-time literal expressions correctly
|
||||
([874cac82](https://github.com/angular/angular.js/commit/874cac825bf29a936cb1b35f9af239687bc5e036))
|
||||
- **formController:** remove scope reference when form is destroyed
|
||||
([01f50e1a](https://github.com/angular/angular.js/commit/01f50e1a7b2bff7070616494774ec493f8133204),
|
||||
[#9315](https://github.com/angular/angular.js/issues/9315))
|
||||
- **jqLite:** remove native listener when all jqLite listeners were deregistered
|
||||
([d71fb6f2](https://github.com/angular/angular.js/commit/d71fb6f2713f1a636f6e9c25479870ee9941ad18),
|
||||
[#9509](https://github.com/angular/angular.js/issues/9509))
|
||||
- **select:**
|
||||
- add basic track by and select as support
|
||||
([addfff3c](https://github.com/angular/angular.js/commit/addfff3c46311f59bdcd100351260006d457316f),
|
||||
[#6564](https://github.com/angular/angular.js/issues/6564))
|
||||
- manage select controller options correctly
|
||||
([2435e2b8](https://github.com/angular/angular.js/commit/2435e2b8f84fde9495b8e9440a2b4f865b1ff541),
|
||||
[#9418](https://github.com/angular/angular.js/issues/9418))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$anchorScroll:** support a configurable vertical scroll offset
|
||||
([09c39d2c](https://github.com/angular/angular.js/commit/09c39d2ce687cdf0ac35dbb34a91f0d198c9d83a),
|
||||
[#9368](https://github.com/angular/angular.js/issues/9368), [#2070](https://github.com/angular/angular.js/issues/2070), [#9360](https://github.com/angular/angular.js/issues/9360))
|
||||
- **$animate:**
|
||||
- introduce the $animate.animate() method
|
||||
([02be700b](https://github.com/angular/angular.js/commit/02be700bda191b454de393f2805916f374a1d764))
|
||||
- allow $animate to pass custom styles into animations
|
||||
([e5f4d7b1](https://github.com/angular/angular.js/commit/e5f4d7b10ae5e6a17ab349995451c33b7d294245))
|
||||
- **currencyFilter:** add fractionSize as optional parameter
|
||||
([20685ffe](https://github.com/angular/angular.js/commit/20685ffe11036d4d604d13f0d792ca46497af4a1),
|
||||
[#3642](https://github.com/angular/angular.js/issues/3642), [#3461](https://github.com/angular/angular.js/issues/3461), [#3642](https://github.com/angular/angular.js/issues/3642), [#7922](https://github.com/angular/angular.js/issues/7922))
|
||||
- **jqLite:** add private jqLiteDocumentLoaded function
|
||||
([0dd316ef](https://github.com/angular/angular.js/commit/0dd316efea209e5e5de3e456b4e6562f011a1294))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$animate:** due to [e5f4d7b1](https://github.com/angular/angular.js/commit/e5f4d7b10ae5e6a17ab349995451c33b7d294245),
|
||||
staggering animations that use transitions will now
|
||||
always block the transition from starting (via `transition: 0s none`)
|
||||
up until the stagger step kicks in. The former behaviour was that the
|
||||
block was removed as soon as the pending class was added. This fix
|
||||
allows for styles to be applied in the pending class without causing
|
||||
an animation to trigger prematurely.
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-rc.5"></a>
|
||||
# 1.3.0-rc.5 impossible-choreography (2014-10-08)
|
||||
|
||||
@@ -144,17 +216,7 @@ Now: `$locationChangeStart` -> `$routeChangeStart`
|
||||
|
||||
Fixes #5581
|
||||
Closes #5714
|
||||
Closes #9502- **ngAnimate:** due to [667183a8](https://github.com/angular/angular.js/commit/667183a8c79d6ffce571a2be78c05dc76503b222),
|
||||
|
||||
|
||||
The $animate class API will always defer changes until the end of the next digest. This allows ngAnimate
|
||||
to coalesce class changes which occur over a short period of time into 1 or 2 DOM writes, rather than
|
||||
many. This prevents jank in browsers such as IE, and is generally a good thing.
|
||||
|
||||
If you're finding that your classes are not being immediately applied, be sure to invoke $digest().
|
||||
|
||||
Closes #8234
|
||||
Closes #9263
|
||||
Closes #9502
|
||||
|
||||
|
||||
<a name="1.3.0-rc.4"></a>
|
||||
|
||||
@@ -173,7 +173,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
|
||||
* **Do not use namespaces**: Instead, wrap the entire angular code base in an anonymous closure and
|
||||
export our API explicitly rather than implicitly.
|
||||
* Wrap all code at **100 characters**.
|
||||
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypical
|
||||
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypal
|
||||
inheritance only when absolutely necessary.
|
||||
* We **love functions and closures** and, whenever possible, prefer them over objects.
|
||||
* To write concise code that can be better minified, we **use aliases internally** that map to the
|
||||
|
||||
@@ -4,6 +4,7 @@ var files = require('./angularFiles').files;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
var versionInfo = require('./lib/versions/version-info');
|
||||
var path = require('path');
|
||||
var e2e = require('./test/e2e/tools');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
@@ -46,12 +47,14 @@ module.exports = function(grunt) {
|
||||
base: '.',
|
||||
keepalive: true,
|
||||
middleware: function(connect, options){
|
||||
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
|
||||
return [
|
||||
util.conditionalCsp(),
|
||||
util.rewrite(),
|
||||
e2e.middleware(),
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(options.base),
|
||||
connect.directory(options.base)
|
||||
connect.static(base),
|
||||
connect.directory(base)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -64,6 +67,7 @@ module.exports = function(grunt) {
|
||||
port: 8000,
|
||||
hostname: '0.0.0.0',
|
||||
middleware: function(connect, options){
|
||||
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
|
||||
return [
|
||||
function(req, resp, next) {
|
||||
// cache get requests to speed up tests on travis
|
||||
@@ -74,8 +78,9 @@ module.exports = function(grunt) {
|
||||
next();
|
||||
},
|
||||
util.conditionalCsp(),
|
||||
e2e.middleware(),
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(options.base)
|
||||
connect.static(base)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -287,14 +292,14 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
|
||||
shell:{
|
||||
"promises-aplus-tests":{
|
||||
options:{
|
||||
//stdout:true,
|
||||
stderr:true,
|
||||
failOnError:true
|
||||
shell: {
|
||||
"promises-aplus-tests": {
|
||||
options: {
|
||||
stdout: false,
|
||||
stderr: true,
|
||||
failOnError: true
|
||||
},
|
||||
command:path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js')
|
||||
command: path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js')
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ found at: https://github.com/angular/benchpress/blob/master/README.md.
|
||||
|
||||
In this project, there is a configured grunt task for building the benchmarks,
|
||||
`grunt bp_build`, which places the runnable benchmarks in "/build/benchmarks/".
|
||||
The existing `grunt webserver` task can be used to serve the built benchmarks at `localhost:8000/build/benchmarks/<benchmark-name>`
|
||||
The existing `grunt webserver` task can be used to serve the built benchmarks at `localhost:8000/build/benchmarks/<benchmark-name>`
|
||||
|
||||
@@ -112,7 +112,7 @@ var printSection = function(stream, title, section, printCommitLinks) {
|
||||
}
|
||||
stream.write(')\n');
|
||||
} else {
|
||||
stream.write(util.format('%s %s', prefix, commit.subject));
|
||||
stream.write(util.format('%s %s\n', prefix, commit.subject));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -188,6 +188,7 @@ var getPreviousTag = function() {
|
||||
|
||||
|
||||
var generate = function(version, file) {
|
||||
|
||||
getPreviousTag().then(function(tag) {
|
||||
console.log('Reading git log since', tag);
|
||||
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 205 KiB |
@@ -5,15 +5,15 @@ describe("doc.angularjs.org", function() {
|
||||
describe("API pages", function() {
|
||||
|
||||
it("should display links to code on GitHub", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
|
||||
});
|
||||
|
||||
it('should change the page content when clicking a link to a service', function () {
|
||||
browser.get('');
|
||||
browser.get('build/docs/index.html');
|
||||
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
@@ -24,7 +24,7 @@ describe("doc.angularjs.org", function() {
|
||||
|
||||
|
||||
it('should show the functioning input directive example', function () {
|
||||
browser.get('index-debug.html#!/api/ng/directive/input');
|
||||
browser.get('build/docs/index.html#!/api/ng/directive/input');
|
||||
|
||||
// Ensure that the page is loaded before trying to switch frames.
|
||||
browser.waitForAngular();
|
||||
@@ -39,7 +39,7 @@ describe("doc.angularjs.org", function() {
|
||||
});
|
||||
|
||||
it("should trim indentation from code blocks", function() {
|
||||
browser.get('index-debug.html#!/api/ng/type/$rootScope.Scope');
|
||||
browser.get('build/docs/index.html#!/api/ng/type/$rootScope.Scope');
|
||||
|
||||
var codeBlocks = element.all(by.css('pre > code.lang-js'));
|
||||
codeBlocks.each(function(codeBlock) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
describe("provider pages", function() {
|
||||
|
||||
it("should show the related service", function() {
|
||||
browser.get('index-debug.html#!/api/ng/provider/$compileProvider');
|
||||
browser.get('build/docs/index.html#!/api/ng/provider/$compileProvider');
|
||||
var serviceLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(serviceLink.getText()).toEqual('- $compile');
|
||||
expect(serviceLink.getAttribute('href')).toMatch(/api\/ng\/service\/\$compile/);
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
describe("service pages", function() {
|
||||
|
||||
it("should show the related provider if there is one", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$compile');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$compile');
|
||||
var providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).toEqual('- $compileProvider');
|
||||
expect(providerLink.getAttribute('href')).toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$q');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$q');
|
||||
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).not.toEqual('- $qProvider');
|
||||
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
});
|
||||
|
||||
it("should show parameter defaults", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$timeout');
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$timeout');
|
||||
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
|
||||
});
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('docs.angularjs.org', function () {
|
||||
|
||||
|
||||
it('should change the page content when clicking a link to a service', function () {
|
||||
browser.get('');
|
||||
browser.get('build/docs/index.html');
|
||||
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
@@ -51,33 +51,33 @@ describe('docs.angularjs.org', function () {
|
||||
|
||||
|
||||
it('should be resilient to trailing slashes', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/');
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index"', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/index');
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/index');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing "index/"', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/index/');
|
||||
browser.get('build/docs/index.html#!/api/ng/function/angular.noop/index/');
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('angular.noop');
|
||||
});
|
||||
|
||||
|
||||
it('should display formatted error messages on error doc pages', function() {
|
||||
browser.get('index-debug.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
|
||||
browser.get('build/docs/index.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
|
||||
expect(element(by.css('.minerr-errmsg')).getText()).toEqual("Argument 'Missing' is not a function, got undefined");
|
||||
});
|
||||
|
||||
it("should display an error if the page does not exist", function() {
|
||||
browser.get('index-debug.html#!/api/does/not/exist');
|
||||
browser.get('build/docs/index.html#!/api/does/not/exist');
|
||||
expect(element(by.css('h1')).getText()).toBe('Oops!');
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ angular.module('docsApp', [
|
||||
'ui.bootstrap.dropdown'
|
||||
])
|
||||
|
||||
|
||||
.config(['$locationProvider', function($locationProvider) {
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
}]);
|
||||
|
||||
@@ -28,5 +28,10 @@ angular.module('directives', [])
|
||||
element.html(window.prettyPrintOne(html, lang, linenums));
|
||||
}
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
.directive('scrollYOffsetElement', ['$anchorScroll', function($anchorScroll) {
|
||||
return function(scope, element) {
|
||||
$anchorScroll.yOffset = element;
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -41,10 +41,14 @@ angular.module('search', [])
|
||||
|
||||
$scope.submit = function() {
|
||||
var result;
|
||||
for(var i in $scope.results) {
|
||||
result = $scope.results[i][0];
|
||||
if(result) {
|
||||
break;
|
||||
if ($scope.results.api) {
|
||||
result = $scope.results.api[0];
|
||||
} else {
|
||||
for(var i in $scope.results) {
|
||||
result = $scope.results[i][0];
|
||||
if(result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result) {
|
||||
|
||||
@@ -19,7 +19,7 @@ angular.module('versions', [])
|
||||
};
|
||||
|
||||
$scope.jumpToDocsVersion = function(version) {
|
||||
var currentPagePath = $location.path();
|
||||
var currentPagePath = $location.path().replace(/\/$/, '');
|
||||
|
||||
// TODO: We need to do some munging of the path for different versions of the API...
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ var packagePath = __dirname;
|
||||
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
// Create and export a new Dgeni package called dgeni-example. This package depends upon
|
||||
// the jsdoc and nunjucks packages defined in the dgeni-packages npm module.
|
||||
// Create and export a new Dgeni package called angularjs. This package depends upon
|
||||
// the ngdoc,nunjucks and examples packages defined in the dgeni-packages npm module.
|
||||
module.exports = new Package('angularjs', [
|
||||
require('dgeni-packages/ngdoc'),
|
||||
require('dgeni-packages/nunjucks'),
|
||||
@@ -157,6 +157,8 @@ module.exports = new Package('angularjs', [
|
||||
jqueryDeployment
|
||||
];
|
||||
|
||||
generateProtractorTestsProcessor.basePath = 'build/docs/';
|
||||
|
||||
generateExamplesProcessor.deployments = [
|
||||
debugDeployment,
|
||||
defaultDeployment,
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<header class="header header-fixed">
|
||||
<header scroll-y-offset-element class="header header-fixed">
|
||||
<section class="navbar navbar-inverse docs-navbar-primary" ng-controller="DocsSearchCtrl">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
@@ -242,7 +242,7 @@ Use ngSanitize to securely parse and manipulate HTML data in your application.
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{@link ngTouch#filter Filters}
|
||||
{@link ngSanitize#filter Filters}
|
||||
</td>
|
||||
<td>
|
||||
The {@link ngSanitize.filter:linky linky filter} is used to turn URLs into HTML links within the provided string.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@fullName Missing Required Controller
|
||||
@description
|
||||
|
||||
This error occurs when {@link ng.$compile HTML compiler} tries to process a directive that specifies the {@link ng.$compile#description_comprehensive-directive-api_directive-definition-object `require` option} in a {@link ng.$compile#description_comprehensive-directive-api directive definition},
|
||||
This error occurs when {@link ng.$compile HTML compiler} tries to process a directive that specifies the {@link ng.$compile#directive-definition-object `require` option} in a {@link ng.$compile#comprehensive-directive-api directive definition},
|
||||
but the required directive controller is not present on the current DOM element (or its ancestor element, if `^` was specified).
|
||||
|
||||
To resolve this error ensure that there is no typo in the required controller name and that the required directive controller is present on the current element.
|
||||
|
||||
@@ -21,5 +21,5 @@ myModule.directive('directiveName', function factory() {
|
||||
});
|
||||
```
|
||||
|
||||
Please refer to the {@link ng.$compile#description_comprehensive-directive-api_directive-definition-object
|
||||
Please refer to the {@link ng.$compile#directive-definition-object
|
||||
`scope` option} of the directive definition documentation to learn more about the API.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@description
|
||||
|
||||
This error occurs when a directive defines an isolate scope property
|
||||
(using the `=` mode in the {@link ng.$compile#description_comprehensive-directive-api_directive-definition-object
|
||||
(using the `=` mode in the {@link ng.$compile#directive-definition-object
|
||||
`scope` option} of a directive definition) but the directive is used with an expression that is not-assignable.
|
||||
|
||||
In order for the two-way data-binding to work, it must be possible to write new values back into the path defined with the expression.
|
||||
|
||||
@@ -6,6 +6,22 @@
|
||||
This error occurs when a module fails to load due to some exception. The error
|
||||
message above should provide additional context.
|
||||
|
||||
### Using `ngRoute`
|
||||
|
||||
In AngularJS `1.2.0` and later, `ngRoute` has been moved to its own module.
|
||||
If you are getting this error after upgrading to `1.2.x` or later, be sure that you've
|
||||
installed {@link ngRoute `ngRoute`}.
|
||||
|
||||
### Monkey-patching Angular's `ng` module
|
||||
|
||||
This error can also occur if you have tried to add your own components to the `ng` module.
|
||||
This has never been supported and from `1.3.0` it will actually trigger this error.
|
||||
For instance the following code could trigger this error.
|
||||
|
||||
```js
|
||||
angular.module('ng').filter('tel', function (){});
|
||||
```
|
||||
|
||||
Instead create your own module and add it as a dependency to your application's top-level module.
|
||||
See [#9692](https://github.com/angular/angular.js/issues/9692) and
|
||||
[#7709](https://github.com/angular/angular.js/issues/7709) for more information
|
||||
@@ -51,4 +51,4 @@ angular.module("myApp", [])
|
||||
```
|
||||
|
||||
For more information about strict-di mode, see {@link ng.directive:ngApp ngApp}
|
||||
and {@link api/angular.bootstrap angular.bootstrap}.
|
||||
and {@link angular.bootstrap angular.bootstrap}.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@description
|
||||
|
||||
If you configure {@link ng.$location `$location`} to use
|
||||
{@link api/ng.provider.$locationProvider `html5Mode`} (`history.pushState`), you need to specify the base URL for the application with a [`<base href="">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag or configure
|
||||
{@link $locationProvider `html5Mode`} (`history.pushState`), you need to specify the base URL for the application with a [`<base href="">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag or configure
|
||||
`$locationProvider` to not require a base tag by passing a definition object with
|
||||
`requireBase:false` to `$locationProvider.html5Mode()`:
|
||||
|
||||
@@ -60,4 +60,4 @@ API](http://caniuse.com/#feat=history), the fallback mechanism provided by `$loc
|
||||
won't work well without specifying the base url of the application.
|
||||
|
||||
In order to make it easier to migrate from hashbang mode to html5 mode, we require that the base
|
||||
URL is always specified when `$location`'s `html5mode` is enabled.
|
||||
URL is always specified when `$location`'s `html5mode` is enabled.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@ngdoc error
|
||||
@name $sce:iequirks
|
||||
@fullName IE8 in quirks mode is unsupported
|
||||
@fullName IE<11 in quirks mode is unsupported
|
||||
@description
|
||||
|
||||
This error occurs when you are using AngularJS with {@link ng.$sce Strict Contextual Escaping (SCE)} mode enabled (the default) on IE8 or lower in quirks mode.
|
||||
This error occurs when you are using AngularJS with {@link ng.$sce Strict Contextual Escaping (SCE)} mode enabled (the default) on IE10 or lower in quirks mode.
|
||||
|
||||
In this mode, IE8 allows one to execute arbitrary javascript by the use of the `expression()` syntax and is not supported.
|
||||
In this mode, IE<11 allow one to execute arbitrary javascript by the use of the `expression()` syntax and is not supported.
|
||||
Refer
|
||||
[MSDN Blogs > IEBlog > Ending Expressions](http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx)
|
||||
[CSS expressions no longer supported for the Internet zone](http://msdn.microsoft.com/en-us/library/ie/dn384050(v=vs.85).aspx)
|
||||
to learn more about them.
|
||||
|
||||
To resolve this error please specify the proper doctype at the top of your main html document:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@fullName Invalid matcher (only string patterns and RegExp instances are supported)
|
||||
@description
|
||||
|
||||
Please see {@link ng.$sceDelegateProvider#resourceUrlWhitelist
|
||||
Please see {@link $sceDelegateProvider#resourceUrlWhitelist
|
||||
$sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
api/ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
|
||||
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
|
||||
list of acceptable items.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@fullName The sequence *** is not a valid pattern wildcard
|
||||
@description
|
||||
|
||||
The strings in {@link ng.$sceDelegateProvider#resourceUrlWhitelist
|
||||
The strings in {@link $sceDelegateProvider#resourceUrlWhitelist
|
||||
$sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
api/ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
|
||||
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
|
||||
contain the undefined sequence `***`. Only `*` and `**` wildcard patterns are defined.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@fullName Unsupported Selector Lookup
|
||||
@description
|
||||
|
||||
In order to keep Angular small, Angular implements only a subset of the selectors in {@link angular.element#description_angulars-jqlite jqLite}.
|
||||
In order to keep Angular small, Angular implements only a subset of the selectors in {@link angular.element#angular-s-jqlite jqLite}.
|
||||
This error occurs when a jqLite instance is invoked with a selector other than this subset.
|
||||
|
||||
In order to resolve this error, rewrite your code to only use tag name selectors and manually traverse the DOM using the APIs provided by jqLite.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@description
|
||||
|
||||
This error occurs when attempting to copy an object to itself. Calling {@link
|
||||
api/angular.copy angular.copy} with a `destination` object deletes
|
||||
angular.copy angular.copy} with a `destination` object deletes
|
||||
all of the elements or properties on `destination` before copying to it. Copying
|
||||
an object to itself is not supported. Make sure to check your calls to
|
||||
`angular.copy` and avoid copying objects or arrays to themselves.
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
@fullName Comprehension expression cannot contain both `select as` and `track by` expressions.
|
||||
@description
|
||||
|
||||
NOTE: This error was introduced in 1.3.0-rc.5, and was removed for 1.3.0-rc.6 in order to
|
||||
not break existing apps.
|
||||
|
||||
This error occurs when 'ngOptions' is passed a comprehension expression that contains both a
|
||||
`select as` expression and a `track by` expression. These two expressions are fundamentally
|
||||
incompatible.
|
||||
|
||||
@@ -15,7 +15,7 @@ For example the issue can be triggered by this *invalid* code:
|
||||
|
||||
To resolve this error either ensure that the items in the collection have unique identity or use the `track by` syntax to specify how to track the association between models and DOM.
|
||||
|
||||
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
|
||||
The example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
|
||||
|
||||
```
|
||||
<div ng-repeat="value in [4, 4] track by $index"></div>
|
||||
|
||||
@@ -332,7 +332,7 @@ reload to the original link.
|
||||
Be sure to check all relative links, images, scripts etc. Angular requires you to specify the url
|
||||
base in the head of your main html file (`<base href="/my-base">`) unless `html5Mode.requireBase` is
|
||||
set to `false` in the html5Mode definition object passed to `$locationProvider.html5Mode()`. With
|
||||
that, relative urls will always be resolved to this base url, event if the initial url of the
|
||||
that, relative urls will always be resolved to this base url, even if the initial url of the
|
||||
document was different.
|
||||
|
||||
There is one exception: Links that only contain a hash fragment (e.g. `<a href="#target">`)
|
||||
|
||||
@@ -55,6 +55,7 @@ navigation easier.
|
||||
|
||||
Accessibility best practices that apply to web apps in general also apply to Angular.
|
||||
|
||||
* [A11Y Project](http://a11yproject.com/)
|
||||
* [WebAim](http://webaim.org/)
|
||||
* [Using WAI-ARIA in HTML](http://www.w3.org/TR/2014/WD-aria-in-html-20140626/)
|
||||
* [Apps For All: Coding Accessible Web Applications](https://shop.smashingmagazine.com/apps-for-all-coding-accessible-web-applications.html)
|
||||
|
||||
@@ -245,13 +245,13 @@ The table below explains in detail which animation events are triggered
|
||||
|
||||
| Directive | Supported Animations |
|
||||
|-------------------------------------------------------------------------------------|------------------------------------------|
|
||||
| {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave, and move |
|
||||
| {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
|
||||
| {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
|
||||
| {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
|
||||
| {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
|
||||
| {@link ng.directive:ngClass#usage_animations ngClass or {{class}}} | add and remove |
|
||||
| {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
|
||||
| {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
|
||||
| {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
|
||||
| {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
|
||||
| {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
|
||||
| {@link ng.directive:ngIf#animations ngIf} | enter and leave |
|
||||
| {@link ng.directive:ngClass#animations ngClass or {{class}}} | add and remove |
|
||||
| {@link ng.directive:ngShow#animations ngShow & ngHide} | add and remove (the ng-hide class value) |
|
||||
|
||||
For a full breakdown of the steps involved during each animation event, refer to the {@link ngAnimate.$animate API docs}.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ initialization.
|
||||
<html xmlns:ng="http://angularjs.org" ng-app>
|
||||
<body>
|
||||
...
|
||||
<script src="angular.js">
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@@ -73,6 +73,23 @@ If the {@link ng.directive:ngApp `ng-app`} directive is found then Angular will:
|
||||
</html>
|
||||
```
|
||||
|
||||
As a best practice, consider adding an `ng-strict-di` directive on the same element as
|
||||
`ng-app`:
|
||||
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html ng-app="optionalModuleName" ng-strict-di>
|
||||
<body>
|
||||
I can add: {{ 1+2 }}.
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
This will ensure that all services in your application are properly annotated.
|
||||
See the {@link guide/di#using-strict-dependency-injection dependancy injection strict mode} docs
|
||||
for more.
|
||||
|
||||
|
||||
## Manual Initialization
|
||||
@@ -128,8 +145,8 @@ This is the sequence that your code should follow:
|
||||
|
||||
## Deferred Bootstrap
|
||||
|
||||
This feature enables tools like Batarang and test runners to
|
||||
hook into angular's bootstrap process and sneak in more modules
|
||||
This feature enables tools like [Batarang](github.com/angular/angularjs-batarang) and test runners
|
||||
to hook into angular's bootstrap process and sneak in more modules
|
||||
into the DI registry which can replace or augment DI services for
|
||||
the purpose of instrumentation or mocking out heavy dependencies.
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
@sortOrder 330
|
||||
@description
|
||||
|
||||
# HTML Compiler
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
|
||||
|
||||
@@ -12,7 +14,7 @@ If you want a deeper look into Angular's compilation process, you're in the righ
|
||||
</div>
|
||||
|
||||
|
||||
# Overview
|
||||
## Overview
|
||||
|
||||
Angular's {@link ng.$compile HTML compiler} allows the developer to teach the
|
||||
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
|
||||
|
||||
@@ -9,9 +9,13 @@ 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 for which a new {@link api/ng.$rootScope.Scope scope}
|
||||
- **Usage:** angular applies this class to any element for which a new {@link $rootScope scope}
|
||||
is defined. (see {@link guide/scope scope} guide for more information about scopes)
|
||||
|
||||
* `ng-isolate-scope`
|
||||
- **Usage:** angular applies this class to any element for which a new
|
||||
{@link guide/directive#isolating-the-scope-of-a-directive isolate scope} is defined.
|
||||
|
||||
* `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/databinding databinding} guide)
|
||||
|
||||
@@ -11,13 +11,227 @@ their dependencies.
|
||||
The Angular injector subsystem is in charge of creating components, resolving their dependencies,
|
||||
and providing them to other components as requested.
|
||||
|
||||
|
||||
## Using Dependency Injection
|
||||
|
||||
DI is pervasive throughout Angular. You can use it when defining components or when providing `run`
|
||||
and `config` blocks for a module.
|
||||
|
||||
- Components such as services, directives, filters, and animations are defined by an injectable
|
||||
factory method or constructor function. These components can be injected with "service" and "value"
|
||||
components as dependencies.
|
||||
|
||||
- Controllers are defined by a constructor function, which can be injected with any of the "service"
|
||||
and "value" components as dependencies, but they can also be provided with special dependencies. See
|
||||
{@link di#controllers Controllers} below for a list of these special dependencies.
|
||||
|
||||
- The `run` method accepts a function, which can be injected with "service", "value" and "constant"
|
||||
components as dependencies. Note that you cannot inject "providers" into `run` blocks.
|
||||
|
||||
- The `config` method accepts a function, which can be injected with "provider" and "constant"
|
||||
components as dependencies. Note that you cannot inject "service" or "value" components into
|
||||
configuration.
|
||||
|
||||
See {@link module#module-loading-dependencies Modules} for more details about `run` and `config`
|
||||
blocks.
|
||||
|
||||
|
||||
### Factory Methods
|
||||
|
||||
The way you define a directive, service, or filter is with a factory function.
|
||||
The factory methods are registered with modules. The recommended way of declaring factories is:
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.factory('serviceId', ['depService', function(depService) {
|
||||
// ...
|
||||
}])
|
||||
.directive('directiveName', ['depService', function(depService) {
|
||||
// ...
|
||||
}])
|
||||
.filter('filterName', ['depService', function(depService) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Module Methods
|
||||
|
||||
We can specify functions to run at configuration and run time for a module by calling the `config`
|
||||
and `run` methods. These functions are injectable with dependencies just like the factory functions
|
||||
above.
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.config(['depProvider', function(depProvider) {
|
||||
// ...
|
||||
}])
|
||||
.run(['depService', function(depService) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Controllers
|
||||
|
||||
Controllers are "classes" or "constructor functions" that are responsible for providing the
|
||||
application behavior that supports the declarative markup in the template. The recommended way of
|
||||
declaring Controllers is using the array notation:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
Unlike services, there can be many instances of the same type of controller in an application.
|
||||
|
||||
Moreover, additional dependencies are made available to Controllers:
|
||||
|
||||
* {@link scope `$scope`}: Controllers are associated with an element in the DOM and so are
|
||||
provided with access to the {@link scope scope}. Other components (like services) only have
|
||||
access to the {@link $rootScope `$rootScope`} service.
|
||||
* {@link ngRoute.$routeProvider#when resolves}: If a controller is instantiated as part of a route,
|
||||
then any values that are resolved as part of the route are made available for injection into the
|
||||
controller.
|
||||
|
||||
|
||||
## Dependency Annotation
|
||||
|
||||
Angular invokes certain functions (like service factories and controllers) via the injector.
|
||||
You need to annotate these functions so that the injector knows what services to inject into
|
||||
the function. There are three ways of annotating your code with service name information:
|
||||
|
||||
- Using the inline array annotation (preferred)
|
||||
- Using the `$inject` property annotation
|
||||
- Implicitly from the function parameter names (has caveats)
|
||||
|
||||
### Inline Array Annotation
|
||||
|
||||
This is the preferred way to annotate application components. This is how the examples in the
|
||||
documentation are written.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Here we pass an array whose elements consist of a list of strings (the names of the dependencies)
|
||||
followed by the function itself.
|
||||
|
||||
When using this type of annotation, take care to keep the annotation array in sync with the
|
||||
parameters in the function declaration.
|
||||
|
||||
### `$inject` Property Annotation
|
||||
|
||||
To allow the minifiers to rename the function parameters and still be able to inject the right services,
|
||||
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
|
||||
of service names to inject.
|
||||
|
||||
```js
|
||||
var MyController = function($scope, greeter) {
|
||||
// ...
|
||||
}
|
||||
MyController.$inject = ['$scope', 'greeter'];
|
||||
someModule.controller('MyController', MyController);
|
||||
```
|
||||
|
||||
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
|
||||
parameters in `MyController`.
|
||||
|
||||
Just like with the array annotation, you'll need to take care to keep the `$inject` in sync with
|
||||
the parameters in the function declaration.
|
||||
|
||||
### Implicit Annotation
|
||||
|
||||
<div class="alert alert-danger">
|
||||
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming))
|
||||
your code, your service names will get renamed and break your app.
|
||||
</div>
|
||||
|
||||
The simplest way to get hold of the dependencies is to assume that the function parameter names
|
||||
are the names of the dependencies.
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', function($scope, greeter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Given a function the injector can infer the names of the services to inject by examining the
|
||||
function declaration and extracting the parameter names. In the above example `$scope`, and
|
||||
`greeter` are two services which need to be injected into the function.
|
||||
|
||||
One advantage of this approach is that there's no array of names to keep in sync with the
|
||||
function parameters. You can also freely reorder dependencies.
|
||||
|
||||
However this method will not work with JavaScript minifiers/obfuscators because of how they
|
||||
rename parameters.
|
||||
|
||||
Tools like [ng-annotate](https://github.com/olov/ng-annotate) let you use implicit dependency
|
||||
annotations in your app and automatically add inline array annotations prior to minifying.
|
||||
If you decide to take this approach, you probably want to use `ng-strict-di`.
|
||||
|
||||
Because of these caveats, we recommend avoiding this style of annotation.
|
||||
|
||||
|
||||
## Using Strict Dependency Injection
|
||||
|
||||
You can add an `ng-strict-di` directive on the same element as `ng-app` to opt into strict DI mode:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html ng-app="myApp" ng-strict-di>
|
||||
<body>
|
||||
I can add: {{ 1 + 2 }}.
|
||||
<script src="angular.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Strict mode throws an error whenever a service tries to use implicit annotations.
|
||||
|
||||
Consider this module, which includes a `willBreak` service that uses implicit DI:
|
||||
|
||||
```js
|
||||
angular.module('myApp', [])
|
||||
.factory('willBreak', function($rootScope) {
|
||||
// $rootScope is implicitly injected
|
||||
})
|
||||
.run(['willBreak', function(willBreak) {
|
||||
// Angular will throw when this runs
|
||||
}]);
|
||||
```
|
||||
|
||||
When the `willBreak` service is instantiated, Angular will throw an error because of strict mode.
|
||||
This is useful when using a tool like [ng-annotate](https://github.com/olov/ng-annotate) to
|
||||
ensure that all of your application components have annotations.
|
||||
|
||||
If you're using manual bootstrapping, you can also use strict DI by providing `strictDi: true` in
|
||||
the optional config argument:
|
||||
|
||||
```js
|
||||
angular.bootstrap(document, ['myApp'], {
|
||||
strictDi: true
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Why Dependency Injection?
|
||||
|
||||
This section motivates and explains Angular's use of DI. For how to use DI, see above.
|
||||
|
||||
For in-depth discussion about DI, see
|
||||
[Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) at Wikipedia,
|
||||
[Inversion of Control](http://martinfowler.com/articles/injection.html) by Martin Fowler,
|
||||
or read about DI in your favorite software design pattern book.
|
||||
|
||||
## DI in a Nutshell
|
||||
|
||||
There are only three ways a component (object or function) can get a hold of its dependencies:
|
||||
|
||||
1. The component can create the dependency, typically using the `new` operator.
|
||||
@@ -117,186 +331,7 @@ controller ever knowing about the injector.
|
||||
This is the best outcome. The application code simply declares the dependencies it needs, without
|
||||
having to deal with the injector. This setup does not break the Law of Demeter.
|
||||
|
||||
|
||||
## Dependency Annotation
|
||||
|
||||
**How does the injector know what components need to be injected?**
|
||||
|
||||
The application developer needs to provide annotation information that the injector uses in order
|
||||
to resolve the dependencies. Throughout Angular, certain API functions are invoked using the
|
||||
injector, as per the API documentation. The injector needs to know what services to inject into
|
||||
the function. There are three equivalent ways of annotating your code with service name
|
||||
information:
|
||||
|
||||
- Implicitly from the function parameter names
|
||||
- Using the `$inject` property annotation
|
||||
- Using the inline array annotation
|
||||
|
||||
These can be used interchangeably as you see fit and are equivalent.
|
||||
|
||||
### Implicit Dependencies
|
||||
|
||||
The simplest way to get hold of the dependencies is to assume that the function parameter names
|
||||
are the names of the dependencies.
|
||||
|
||||
```js
|
||||
function MyController($scope, greeter) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Given a function the injector can infer the names of the services to inject by examining the
|
||||
function declaration and extracting the parameter names. In the above example `$scope`, and
|
||||
`greeter` are two services which need to be injected into the function.
|
||||
|
||||
While straightforward, this method will not work with JavaScript minifiers/obfuscators as they
|
||||
rename the method parameter names. This makes this way of annotating only useful for
|
||||
[pretotyping](http://www.pretotyping.org/), and demo applications.
|
||||
|
||||
### `$inject` Property Annotation
|
||||
|
||||
To allow the minifiers to rename the function parameters and still be able to inject the right services,
|
||||
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
|
||||
of service names to inject.
|
||||
|
||||
```js
|
||||
var MyController = function(renamed$scope, renamedGreeter) {
|
||||
...
|
||||
}
|
||||
MyController['$inject'] = ['$scope', 'greeter'];
|
||||
```
|
||||
|
||||
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
|
||||
arguments to inject. Using the 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.
|
||||
|
||||
This method of annotation is useful for controller declarations since it assigns the annotation
|
||||
information with the function.
|
||||
|
||||
### Inline Array Annotation
|
||||
|
||||
Sometimes using the `$inject` annotation style is not convenient such as when annotating
|
||||
directives or services defined inline by a factory function.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
someModule.factory('greeter', function($window) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Results in code bloat due to needing a temporary variable:
|
||||
|
||||
```js
|
||||
var greeterFactory = function(renamed$window) {
|
||||
// ...
|
||||
};
|
||||
|
||||
greeterFactory.$inject = ['$window'];
|
||||
|
||||
someModule.factory('greeter', greeterFactory);
|
||||
```
|
||||
|
||||
For this reason the third annotation style is provided as well.
|
||||
|
||||
```js
|
||||
someModule.factory('greeter', ['$window', function(renamed$window) {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Here, instead of simply providing the factory function, we pass an array whose elements consist of
|
||||
a list of strings (the names of the dependencies) followed by the function itself.
|
||||
|
||||
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
||||
where injection is supported.
|
||||
|
||||
## Where Can I Use DI?
|
||||
|
||||
DI is pervasive throughout Angular. You can use it when defining components or when providing `run`
|
||||
and `config` blocks for a module.
|
||||
|
||||
- Components such as services, directives, filters and animations are defined by an injectable factory
|
||||
method or constructor function. These components can be injected with "service" and "value"
|
||||
components as dependencies.
|
||||
|
||||
- The `run` method accepts a function, which can be injected with "service", "value" and "constant"
|
||||
components as dependencies. Note that you cannot inject "providers" into `run` blocks.
|
||||
|
||||
- The `config` method accepts a function, which can be injected with "provider" and "constant"
|
||||
components as dependencies. Note that you cannot inject "service" or "value" components into
|
||||
configuration
|
||||
|
||||
- Controllers are defined by a constructor function, which can be injected with any of the "service"
|
||||
and "value" components as dependencies, but they can also be provided with special dependencies. See
|
||||
{@link di#controllers Controllers} below for a list of these special dependencies.
|
||||
|
||||
See {@link module#module-loading-dependencies Modules} for more details about injecting dependencies
|
||||
into `run` and `config` blocks.
|
||||
|
||||
|
||||
### Factory Methods
|
||||
|
||||
Factory methods are responsible for creating most objects in Angular. Examples are directives,
|
||||
services, and filters. The factory methods are registered with the module, and the recommended way
|
||||
of declaring factories is:
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.factory('serviceId', ['depService', function(depService) {
|
||||
...
|
||||
}])
|
||||
.directive('directiveName', ['depService', function(depService) {
|
||||
...
|
||||
}])
|
||||
.filter('filterName', ['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Module Methods
|
||||
|
||||
We can specify functions to run at configuration and run time for a module by calling the `run` and
|
||||
`config` methods. These functions are injectable with dependencies just like the factory functions
|
||||
above.
|
||||
|
||||
```js
|
||||
angular.module('myModule', [])
|
||||
.config(['depProvider', function(depProvider){
|
||||
...
|
||||
}])
|
||||
.run(['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
### Controllers
|
||||
|
||||
Controllers are "classes" or "constructor functions" that are responsible for providing the
|
||||
application behavior that supports the declarative markup in the template. The recommended way of
|
||||
declaring Controllers is using the array notation:
|
||||
|
||||
```js
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]);
|
||||
```
|
||||
|
||||
This avoids the creation of global functions for controllers and also protects against minification.
|
||||
|
||||
Controllers are special in that, unlike services, there can be many instances of them in the
|
||||
application. For example, there would be one instance for every `ng-controller` directive in the template.
|
||||
|
||||
Moreover, additional dependencies are made available to Controllers:
|
||||
|
||||
* {@link scope `$scope`}: Controllers are always associated with a point in the DOM and so are provided with
|
||||
access to the {@link scope scope} at that point. Other components, such as services only have access to the
|
||||
singleton {@link $rootScope} service.
|
||||
* {@link $route} resolves: If a controller is instantiated as part of a route, then any values that
|
||||
are resolved as part of the route are made available for injection into the controller.
|
||||
<div class="alert alert-info">
|
||||
**Note:** Angular uses
|
||||
[**constructor injection**](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
|
||||
</div>
|
||||
|
||||
@@ -66,15 +66,9 @@ The **normalization** process is as follows:
|
||||
1. Strip `x-` and `data-` from the front of the element/attributes.
|
||||
2. Convert the `:`, `-`, or `_`-delimited name to `camelCase`.
|
||||
|
||||
Here are some equivalent examples of elements that match `ngBind`:
|
||||
For example, the following forms are all equivalent and match the {@link ngBind} directive:
|
||||
|
||||
<example module="docsBindExample">
|
||||
<file name="script.js">
|
||||
angular.module('docsBindExample', [])
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
$scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)';
|
||||
}]);
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
Hello <input ng-model='name'> <hr/>
|
||||
@@ -85,6 +79,12 @@ Here are some equivalent examples of elements that match `ngBind`:
|
||||
<span x-ng-bind="name"></span> <br/>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('docsBindExample', [])
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
$scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)';
|
||||
}]);
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should show off bindings', function() {
|
||||
expect(element(by.css('div[ng-controller="Controller"] span[ng-bind]')).getText())
|
||||
@@ -180,7 +180,7 @@ For example, we could fix the example above by instead writing:
|
||||
First let's talk about the {@link ng.$compileProvider#directive API for registering directives}. Much like
|
||||
controllers, directives are registered on modules. To register a directive, you use the
|
||||
`module.directive` API. `module.directive` takes the
|
||||
{@link guide/directive#creating-custom-directives_matching-directives normalized} directive name
|
||||
{@link guide/directive#matching-directives normalized} directive name
|
||||
followed by a **factory function.** This factory function should return an object with the different
|
||||
options to tell `$compile` how the directive should behave when matched.
|
||||
|
||||
@@ -243,7 +243,7 @@ Let's create a directive that simply replaces its contents with a static templat
|
||||
Notice that we have bindings in this directive. After `$compile` compiles and links
|
||||
`<div my-customer></div>`, it will try to match directives on the element's children. This means you
|
||||
can compose directives of other directives. We'll see how to do that in
|
||||
{@link guide/directive#creating-custom-directives_demo_creating-directives-that-communicate an example}
|
||||
{@link guide/directive#creating-directives-that-communicate an example}
|
||||
below.
|
||||
|
||||
In the example above we in-lined the value of the `template` option, but this will become annoying
|
||||
@@ -282,6 +282,46 @@ using `templateUrl` instead:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
`templateUrl` can also be a function which returns the URL of an HTML template to be loaded and
|
||||
used for the directive. Angular will call the `templateUrl` function with two parameters: the
|
||||
element that the directive was called on, and an `attr` object associated with that element.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** You do not currently have the ability to access scope variables from the `templateUrl`
|
||||
function, since the template is requested before the scope is initialized.
|
||||
</div>
|
||||
|
||||
<example module="docsTemplateUrlDirective">
|
||||
<file name="script.js">
|
||||
angular.module('docsTemplateUrlDirective', [])
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
$scope.customer = {
|
||||
name: 'Naomi',
|
||||
address: '1600 Amphitheatre'
|
||||
};
|
||||
}])
|
||||
.directive('myCustomer', function() {
|
||||
return {
|
||||
templateUrl: function(elem, attr){
|
||||
return 'customer-'+attr.type+'.html';
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<div my-customer type="name"></div>
|
||||
<div my-customer type="address"></div>
|
||||
</div>
|
||||
</file>
|
||||
<file name="customer-name.html">
|
||||
Name: {{customer.name}}
|
||||
</file>
|
||||
<file name="customer-address.html">
|
||||
Address: {{customer.address}}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** When you create a directive, it is restricted to attribute and elements only by default. In order to
|
||||
create directives that are triggered by class name, you need to use the `restrict` option.
|
||||
@@ -328,9 +368,9 @@ Let's change our directive to use `restrict: 'E'`:
|
||||
</example>
|
||||
|
||||
For more on the
|
||||
{@link ng.$compile#description_comprehensive-directive-api_directive-definition-object `restrict`}
|
||||
{@link ng.$compile#directive-definition-object `restrict`}
|
||||
property, see the
|
||||
{@link ng.$compile#description_comprehensive-directive-api_directive-definition-object API docs}.
|
||||
{@link ng.$compile#directive-definition-object API docs}.
|
||||
|
||||
<div class="alert alert-info">
|
||||
**When should I use an attribute versus an element?**
|
||||
@@ -509,7 +549,7 @@ that you explicitly pass in.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** Normally, a scope prototypically inherits from its parent. An isolated scope does not.
|
||||
See the {@link api/ng/service/$compile#directive-definition-object
|
||||
See the {@link $compile#directive-definition-object
|
||||
"Directive Definition Object - scope"} section for more information about isolate scopes.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ filter the list of items.
|
||||
|
||||
## Example
|
||||
See the [angular-seed](https://github.com/angular/angular-seed) project for more examples, or look
|
||||
at the embedded examples in the Angular documentation (For example, [$http](http://docs.angularjs.org/api/ng/service/$http)
|
||||
at the embedded examples in the Angular documentation (For example, {@link $http $http}
|
||||
has an end to end test in the example under the `protractor.js` tag).
|
||||
|
||||
## Caveats
|
||||
|
||||
@@ -167,7 +167,9 @@ expression, delegate to a JavaScript method instead.
|
||||
## `$event`
|
||||
|
||||
Directives like {@link ng.directive:ngClick `ngClick`} and {@link ng.directive:ngFocus `ngFocus`}
|
||||
expose a `$event` object within the scope of that expression.
|
||||
expose a `$event` object within the scope of that expression. The object is an instance of a [jQuery
|
||||
Event Object](http://api.jquery.com/category/events/event-object/) when jQuery is present or a
|
||||
similar jqLite object.
|
||||
|
||||
<example module="eventExampleApp">
|
||||
<file name="index.html">
|
||||
@@ -276,9 +278,9 @@ digest cycle as long as that value is not undefined. If the value of the express
|
||||
within the digest loop and later, within the same digest loop, it is set to undefined,
|
||||
then the expression is not fulfilled and will remain watched.
|
||||
|
||||
1. Given an expression that starts with `::` when a digest loop is entered and expression
|
||||
is dirty-checked store the value as V
|
||||
2. If V is not undefined mark the result of the expression as stable and schedule a task
|
||||
1. Given an expression that starts with `::`, when a digest loop is entered and expression
|
||||
is dirty-checked, store the value as V
|
||||
2. If V is not undefined, mark the result of the expression as stable and schedule a task
|
||||
to deregister the watch for this expression when we exit the digest loop
|
||||
3. Process the digest loop as normal
|
||||
4. When digest loop is done and all the values have settled process the queue of watch
|
||||
|
||||
@@ -7,15 +7,17 @@ Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
|
||||
A Form is a collection of controls for the purpose of grouping related controls together.
|
||||
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input.
|
||||
This provides a better user experience, because the user gets instant feedback on how to correct the error.
|
||||
Keep in mind that while client-side validation plays an important role in providing good user experience, it can easily be circumvented and thus can not be trusted.
|
||||
This provides a better user experience, because the user gets instant feedback on how to
|
||||
correct the error. Keep in mind that while client-side validation plays an important role
|
||||
in providing good user experience, it can easily be circumvented and thus can not be trusted.
|
||||
Server-side validation is still necessary for a secure application.
|
||||
|
||||
|
||||
# Simple form
|
||||
The key directive in understanding two-way data-binding is {@link ng.directive:ngModel ngModel}.
|
||||
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
|
||||
In addition it provides an {@link ngModel.NgModelController API} for other directives to augment its behavior.
|
||||
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view,
|
||||
as well as view to the model. In addition it provides an {@link ngModel.NgModelController API}
|
||||
for other directives to augment its behavior.
|
||||
|
||||
<example module="formExample">
|
||||
<file name="index.html">
|
||||
@@ -60,16 +62,20 @@ Note that `novalidate` is used to disable browser's native form validation.
|
||||
|
||||
To allow styling of form as well as controls, `ngModel` adds these CSS classes:
|
||||
|
||||
- `ng-valid`
|
||||
- `ng-invalid`
|
||||
- `ng-pristine`
|
||||
- `ng-dirty`
|
||||
- `ng-touched`
|
||||
- `ng-untouched`
|
||||
- `ng-valid`: the model is valid
|
||||
- `ng-invalid`: the model is invalid
|
||||
- `ng-valid-[key]`: for each valid key added by `$setValidity`
|
||||
- `ng-invalid-[key]`: for each invalid key added by `$setValidity`
|
||||
- `ng-pristine`: the control hasn't been interacted with yet
|
||||
- `ng-dirty`: the control has been interacted with
|
||||
- `ng-touched`: the control has been blurred
|
||||
- `ng-untouched`: the control hasn't been blurred
|
||||
- `ng-pending`: any `$asyncValidators` are unfulfilled
|
||||
|
||||
The following example uses the CSS to display validity of each form control.
|
||||
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
|
||||
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
|
||||
In the example both `user.name` and `user.email` are required, but are rendered
|
||||
with red background only when they are dirty. This ensures that the user is not distracted
|
||||
with an error until after interacting with the control, and failing to satisfy its validity.
|
||||
|
||||
<example module="formExample">
|
||||
<file name="index.html">
|
||||
@@ -122,9 +128,9 @@ A form is an instance of {@link form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
|
||||
Similarly, an input control that has the {@link ng.directive:ngModel ngModel} directive holds an
|
||||
instance of {@link ngModel.NgModelController NgModelController}.
|
||||
Such a control instance can be published as a property of the form instance using the `name` attribute
|
||||
on the input control. The name attribute specifies the name of the property on the form instance.
|
||||
instance of {@link ngModel.NgModelController NgModelController}.Such a control instance
|
||||
can be published as a property of the form instance using the `name` attribute on the input control.
|
||||
The name attribute specifies the name of the property on the form instance.
|
||||
|
||||
This implies that the internal state of both the form and the control is available for binding in
|
||||
the view using the standard binding primitives.
|
||||
@@ -187,7 +193,7 @@ This allows us to extend the above example with these features:
|
||||
|
||||
|
||||
|
||||
# Custom triggers
|
||||
# Custom model update triggers
|
||||
|
||||
By default, any change to the content will trigger a model update and form validation. You can
|
||||
override this behavior using the {@link ng.directive:ngModelOptions ngModelOptions} directive to
|
||||
@@ -195,13 +201,15 @@ bind only to specified list of events. I.e. `ng-model-options="{ updateOn: 'blur
|
||||
and validate only after the control loses focus. You can set several events using a space delimited
|
||||
list. I.e. `ng-model-options="{ updateOn: 'mousedown blur' }"`
|
||||
|
||||
<img alt="animation showing debounced input" src="img/guide/forms-update-on-blur.gif">
|
||||
|
||||
If you want to keep the default behavior and just add new events that may trigger the model update
|
||||
and validation, add "default" as one of the specified events.
|
||||
|
||||
I.e. `ng-model-options="{ updateOn: 'default blur' }"`
|
||||
|
||||
The following example shows how to override immediate updates. Changes on the inputs within the form will update the model
|
||||
only when the control loses focus (blur event).
|
||||
The following example shows how to override immediate updates. Changes on the inputs within the form
|
||||
will update the model only when the control loses focus (blur event).
|
||||
|
||||
<example module="customTriggerExample">
|
||||
<file name="index.html">
|
||||
@@ -232,6 +240,8 @@ You can delay the model update/validation by using the `debounce` key with the
|
||||
{@link ng.directive:ngModelOptions ngModelOptions} directive. This delay will also apply to
|
||||
parsers, validators and model flags like `$dirty` or `$pristine`.
|
||||
|
||||
<img alt="animation showing debounced input" src="img/guide/forms-debounce.gif">
|
||||
|
||||
I.e. `ng-model-options="{ debounce: 500 }"` will wait for half a second since
|
||||
the last content change before triggering the model update and form validation.
|
||||
|
||||
@@ -241,10 +251,11 @@ in `debounce`. This can be useful to force immediate updates on some specific ci
|
||||
|
||||
I.e. `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"`
|
||||
|
||||
If those attributes are added to an element, they will be applied to all the child elements and controls that inherit from it unless they are
|
||||
overridden.
|
||||
If those attributes are added to an element, they will be applied to all the child elements and
|
||||
controls that inherit from it unless they are overridden.
|
||||
|
||||
This example shows how to debounce model changes. Model will be updated only 250 milliseconds after last change.
|
||||
This example shows how to debounce model changes. Model will be updated only 250 milliseconds
|
||||
after last change.
|
||||
|
||||
<example module="debounceExample">
|
||||
<file name="index.html">
|
||||
@@ -264,35 +275,40 @@ This example shows how to debounce model changes. Model will be updated only 250
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
|
||||
# Custom Validation
|
||||
|
||||
Angular provides basic implementation for most common html5 {@link ng.directive:input input}
|
||||
types: ({@link input[text] text}, {@link input[number] number}, {@link input[url] url}, {@link input[email] email}, {@link input[radio] radio}, {@link input[checkbox] checkbox}), as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`, `min`, `max`).
|
||||
Angular provides basic implementation for most common HTML5 {@link ng.directive:input input}
|
||||
types: ({@link input[text] text}, {@link input[number] number}, {@link input[url] url},
|
||||
{@link input[email] email}, {@link input[radio] radio}, {@link input[checkbox] checkbox}),
|
||||
as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`,
|
||||
`min`, `max`).
|
||||
|
||||
Defining your own validator can be done by defining your own directive which adds a custom validation function to the `ngModel` {@link ngModel.NgModelController controller}.
|
||||
To get a hold of the controller the directive specifies a dependency as shown in the example below.
|
||||
The validation can occur in two places:
|
||||
With a custom directive, you can add your own validation functions to the `$validators` object on
|
||||
the {@link ngModel.NgModelController `ngModelController`}. To get a hold of the controller,
|
||||
you require it in the directive as shown in the example below.
|
||||
|
||||
* **Model to View update** -
|
||||
Whenever the bound model changes, all functions in {@link ngModel.NgModelController#properties_$formatters NgModelController#$formatters} array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through {@link ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
Each function in the `$validators` object receives the `modelValue` and the `viewValue`
|
||||
as parameters. Angular will then call `$setValidity` internally with the function's return value
|
||||
(`true`: valid, `false`: invalid). The validation functions are executed every time an input
|
||||
is changed (`$setViewValue` is called) or whenever the bound `model` changes.
|
||||
Validation happens after successfully running `$parsers` and `$formatters`, respectively.
|
||||
Failed validators are stored by key in
|
||||
{@link ngModel.NgModelController#$error `ngModelController.$error`}.
|
||||
|
||||
* **View to Model update** -
|
||||
In a similar way, whenever a user interacts with a control it calls {@link ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
|
||||
This in turn pipelines all functions in the {@link ngModel.NgModelController#properties_$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
Additionally, there is the `$asyncValidators` object which handles asynchronous validation,
|
||||
such as making an `$http` request to the backend. Functions added to the object must return
|
||||
a promise that must be `resolved` when valid or `rejected` when invalid.
|
||||
In-progress async validations are stored by key in
|
||||
{@link ngModel.NgModelController#$pending `ngModelController.$pending`}.
|
||||
|
||||
In the following example we create two directives.
|
||||
|
||||
* The first one is `integer` and it validates whether the input is a valid integer.
|
||||
For example `1.23` is an invalid value, since it contains a fraction.
|
||||
Note that we unshift the array instead of pushing.
|
||||
This is because we want it to be the first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
|
||||
|
||||
* The second directive is a `smart-float`.
|
||||
It parses both `1.2` and `1,2` into a valid float number `1.2`.
|
||||
Note that we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
|
||||
In the following example we create two directives:
|
||||
* An `integer` directive that validates whether the input is a valid integer. For example,
|
||||
`1.23` is an invalid value, since it contains a fraction. Note that we validate the viewValue
|
||||
(the string value of the control), and not the modelValue. This is because input[number] converts
|
||||
the viewValue to a number when running the `$parsers`.
|
||||
|
||||
* A `username` directive that asynchronously checks if a user-entered value is already taken.
|
||||
We mock the server request with a `$q` deferred.
|
||||
|
||||
<example module="form-example1">
|
||||
<file name="index.html">
|
||||
@@ -301,18 +317,18 @@ In the following example we create two directives.
|
||||
Size (integer 0 - 10):
|
||||
<input type="number" ng-model="size" name="size"
|
||||
min="0" max="10" integer />{{size}}<br />
|
||||
<span ng-show="form.size.$error.integer">This is not valid integer!</span>
|
||||
<span ng-show="form.size.$error.integer">The value is not a valid integer!</span>
|
||||
<span ng-show="form.size.$error.min || form.size.$error.max">
|
||||
The value must be in range 0 to 10!</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Length (float):
|
||||
<input type="text" ng-model="length" name="length" smart-float />
|
||||
{{length}}<br />
|
||||
<span ng-show="form.length.$error.float">
|
||||
This is not a valid float number!</span>
|
||||
Username:
|
||||
<input type="text" ng-model="name" name="name" username />{{name}}<br />
|
||||
<span ng-show="form.name.$pending.username">Checking if this name is available ...</span>
|
||||
<span ng-show="form.name.$error.username">This username is already taken!</span>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</file>
|
||||
|
||||
@@ -324,35 +340,96 @@ In the following example we create two directives.
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
ctrl.$parsers.unshift(function(viewValue) {
|
||||
ctrl.$validators.integer = function(modelValue, viewValue) {
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
// consider empty models to be valid
|
||||
return true;
|
||||
}
|
||||
|
||||
if (INTEGER_REGEXP.test(viewValue)) {
|
||||
// it is valid
|
||||
ctrl.$setValidity('integer', true);
|
||||
return viewValue;
|
||||
} else {
|
||||
// it is invalid, return undefined (no model update)
|
||||
ctrl.$setValidity('integer', false);
|
||||
return undefined;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// it is invalid
|
||||
return false;
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var FLOAT_REGEXP = /^\-?\d+((\.|\,)\d+)?$/;
|
||||
app.directive('smartFloat', function() {
|
||||
app.directive('username', function($q, $timeout) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
ctrl.$parsers.unshift(function(viewValue) {
|
||||
if (FLOAT_REGEXP.test(viewValue)) {
|
||||
ctrl.$setValidity('float', true);
|
||||
return parseFloat(viewValue.replace(',', '.'));
|
||||
} else {
|
||||
ctrl.$setValidity('float', false);
|
||||
return undefined;
|
||||
var usernames = ['Jim', 'John', 'Jill', 'Jackie'];
|
||||
|
||||
ctrl.$asyncValidators.username = function(modelValue, viewValue) {
|
||||
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
// consider empty model valid
|
||||
return $q.when();
|
||||
}
|
||||
});
|
||||
|
||||
var def = $q.defer();
|
||||
|
||||
$timeout(function() {
|
||||
// Mock a delayed response
|
||||
if (usernames.indexOf(modelValue) === -1) {
|
||||
// The username is available
|
||||
def.resolve();
|
||||
} else {
|
||||
def.reject();
|
||||
}
|
||||
|
||||
}, 2000);
|
||||
|
||||
return def.promise;
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
# Modifying built-in validators
|
||||
|
||||
Since Angular itself uses `$validators`, you can easily replace or remove built-in validators,
|
||||
should you find it necessary. The following example shows you how to overwrite the email validator
|
||||
in `input[email]` from a custom directive so that it requires a specific top-level domain,
|
||||
`example.com` to be present.
|
||||
Note that you can alternatively use `ng-pattern` to further restrict the validation.
|
||||
|
||||
<example module="form-example-modify-validators">
|
||||
<file name="index.html">
|
||||
<form name="form" class="css-form" novalidate>
|
||||
<div>
|
||||
Overwritten Email:
|
||||
<input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" />
|
||||
<span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br>
|
||||
Model: {{myEmail}}
|
||||
</div>
|
||||
</form>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
var app = angular.module('form-example-modify-validators', []);
|
||||
|
||||
app.directive('overwriteEmail', function() {
|
||||
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;
|
||||
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: '',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
// only apply the validator if ngModel is present and Angular has added the email validator
|
||||
if (ctrl && ctrl.$validators.email) {
|
||||
|
||||
// this will overwrite the default Angular email validator
|
||||
ctrl.$validators.email = function(modelValue) {
|
||||
return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -361,15 +438,19 @@ In the following example we create two directives.
|
||||
|
||||
|
||||
# Implementing custom form controls (using `ngModel`)
|
||||
Angular implements all of the basic HTML form controls ({@link ng.directive:input input}, {@link ng.directive:select select}, {@link ng.directive:textarea textarea}), which should be sufficient for most cases.
|
||||
However, if you need more flexibility, you can write your own form control as a directive.
|
||||
Angular implements all of the basic HTML form controls ({@link ng.directive:input input},
|
||||
{@link ng.directive:select select}, {@link ng.directive:textarea textarea}),
|
||||
which should be sufficient for most cases. However, if you need more flexibility,
|
||||
you can write your own form control as a directive.
|
||||
|
||||
In order for custom control to work with `ngModel` and to achieve two-way data-binding it needs to:
|
||||
|
||||
- implement `$render` method, which is responsible for rendering the data after it passed the {@link api/ng.directive:ngModel.NgModelController#properties_$formatters NgModelController#$formatters},
|
||||
- call `$setViewValue` method, whenever the user interacts with the control and model needs to be updated. This is usually done inside a DOM Event listener.
|
||||
- implement `$render` method, which is responsible for rendering the data after it passed the
|
||||
{@link ngModel.NgModelController#$formatters `NgModelController.$formatters`},
|
||||
- call `$setViewValue` method, whenever the user interacts with the control and model
|
||||
needs to be updated. This is usually done inside a DOM Event listener.
|
||||
|
||||
See {@link guide/directive $compileProvider.directive} for more info.
|
||||
See {@link guide/directive `$compileProvider.directive`} for more info.
|
||||
|
||||
The following example shows how to add two-way data-binding to contentEditable elements.
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
* **MEAN Stack: **[Blog post](http://blog.mongodb.org/post/49262866911/the-mean-stack-mongodb-expressjs-angularjs-and), [Setup](http://thecodebarbarian.wordpress.com/2013/07/22/introduction-to-the-mean-stack-part-one-setting-up-your-tools/), [GDL Video](https://developers.google.com/live/shows/913996610)
|
||||
* **Rails: **[Tutorial](http://coderberry.me/blog/2013/04/22/angularjs-on-rails-4-part-1/), [AngularJS with Rails4](https://shellycloud.com/blog/2013/10/how-to-integrate-angularjs-with-rails-4), [angularjs-rails](https://github.com/hiravgandhi/angularjs-rails)
|
||||
* **PHP: **[Building a RESTful web service](http://blog.brunoscopelliti.com/building-a-restful-web-service-with-angularjs-and-php-more-power-with-resource), [End to End with Laravel 4 (video)](http://www.youtube.com/watch?v=hqAyiqUs93c)
|
||||
* **Meteor: **[angular-meteor package](https://github.com/Urigo/angular-meteor)
|
||||
|
||||
## Learning Resources
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ browser new syntax through a construct we call directives. Examples include:
|
||||
* Data binding, as in `{{}}`.
|
||||
* DOM control structures for repeating/hiding DOM fragments.
|
||||
* Support for forms and form validation.
|
||||
* Attaching code-behind to DOM elements.
|
||||
* Attaching new behavior to DOM elements, such as DOM event handling.
|
||||
* Grouping of HTML into reusable components.
|
||||
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ $httpProvider.interceptors.push('myHttpInterceptor');
|
||||
```
|
||||
|
||||
More details on the new interceptors API (which has been around as of v1.1.4) can be found at
|
||||
https://docs.angularjs.org/api/ng/service/$http#interceptors
|
||||
{@link $http#interceptors interceptors}
|
||||
|
||||
|
||||
- **injector:** due to [c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
|
||||
@@ -401,16 +401,16 @@ below should still apply, but you may want to consult the
|
||||
<li class="nav-header">Summary of Breaking Changes</li>
|
||||
<li>{@link guide/migration#ngroute-has-been-moved-into-its-own-module ngRoute has been moved into its own module}</li>
|
||||
<li>{@link guide/migration#templates-no-longer-automatically-unwrap-promises Templates no longer automatically unwrap promises}</li>
|
||||
<li>{@link guide/migration#syntax-for-named-wildcard-parameters-changed-in Syntax for named wildcard parameters changed in <code>$route</code>}</li>
|
||||
<li>{@link guide/migration#you-can-only-bind-one-expression-to You can only bind one expression to <code>*[src]</code>, <code>*[ng-src]</code> or <code>action</code>}</li>
|
||||
<li>{@link guide/migration#syntax-for-named-wildcard-parameters-changed-in-route- Syntax for named wildcard parameters changed in <code>$route</code>}</li>
|
||||
<li>{@link guide/migration#you-can-only-bind-one-expression-to-src-ng-src-or-action- You can only bind one expression to <code>*[src]</code>, <code>*[ng-src]</code> or <code>action</code>}</li>
|
||||
<li>{@link guide/migration#interpolations-inside-dom-event-handlers-are-now-disallowed Interpolations inside DOM event handlers are now disallowed}</li>
|
||||
<li>{@link guide/migration#directives-cannot-end-with--start-or--end Directives cannot end with -start or -end}</li>
|
||||
<li>{@link guide/migration#in-$q,-promisealways-has-been-renamed-promisefinally In $q, promise.always has been renamed promise.finally}</li>
|
||||
<li>{@link guide/migration#directives-cannot-end-with-start-or-end Directives cannot end with -start or -end}</li>
|
||||
<li>{@link guide/migration#in-q-promise-always-has-been-renamed-promise-finally In $q, promise.always has been renamed promise.finally}</li>
|
||||
<li>{@link guide/migration#ngmobile-is-now-ngtouch ngMobile is now ngTouch}</li>
|
||||
<li>{@link guide/migration#resource$then-has-been-removed resource.$then has been removed}</li>
|
||||
<li>{@link guide/migration#resource-then-has-been-removed resource.$then has been removed}</li>
|
||||
<li>{@link guide/migration#resource-methods-return-the-promise Resource methods return the promise}</li>
|
||||
<li>{@link guide/migration#resource-promises-are-resolved-with-the-resource-instance Resource promises are resolved with the resource instance}</li>
|
||||
<li>{@link guide/migration#$locationsearch-supports-multiple-keys $location.search supports multiple keys}</li>
|
||||
<li>{@link guide/migration#-location-search-supports-multiple-keys $location.search supports multiple keys}</li>
|
||||
<li>{@link guide/migration#ngbindhtmlunsafe-has-been-removed-and-replaced-by-ngbindhtml ngBindHtmlUnsafe has been removed and replaced by ngBindHtml}</li>
|
||||
<li>{@link guide/migration#form-names-that-are-expressions-are-evaluated Form names that are expressions are evaluated}</li>
|
||||
<li>{@link guide/migration#hasownproperty-disallowed-as-an-input-name hasOwnProperty disallowed as an input name}</li>
|
||||
@@ -421,11 +421,10 @@ below should still apply, but you may want to consult the
|
||||
<li>{@link guide/migration#urls-are-now-sanitized-against-a-whitelist URLs are now sanitized against a whitelist}</li>
|
||||
<li>{@link guide/migration#isolate-scope-only-exposed-to-directives-with-scope-property Isolate scope only exposed to directives with <code>scope</code> property}</li>
|
||||
<li>{@link guide/migration#change-to-interpolation-priority Change to interpolation priority}</li>
|
||||
<li>{@link guide/migration#underscore-prefixed/suffixed-properties-are-non-bindable Underscore-prefixed/suffixed properties are non-bindable}</li>
|
||||
<li>{@link guide/migration#you-cannot-bind-to-select[multiple] You cannot bind to select[multiple]}</li>
|
||||
<li>{@link guide/migration#underscore-prefixed-suffixed-properties-are-non-bindable Underscore-prefixed/suffixed properties are non-bindable}</li>
|
||||
<li>{@link guide/migration#you-cannot-bind-to-select-multiple- You cannot bind to select[multiple]}</li>
|
||||
<li>{@link guide/migration#uncommon-region-specific-local-files-were-removed-from-i18n Uncommon region-specific local files were removed from i18n}</li>
|
||||
<li>{@link guide/migration#services-can-now-return-functions Services can now return functions}</li>
|
||||
<li>{@link guide/migration#modifying-the-dom-outside-digest-cycle Modifying the DOM outside digest cycle}</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Where the compiler has created a new scope, the scope and either `ng-scope` or `
|
||||
CSS class are attached to the corresponding element. These scope references can then be accessed via
|
||||
`element.scope()` and `element.isolateScope()`.
|
||||
|
||||
Tools like [Protractor](github.com/angular/protractor) and
|
||||
Tools like [Protractor](https://github.com/angular/protractor) and
|
||||
[Batarang](https://github.com/angular/angularjs-batarang) need this information to run,
|
||||
but you can disable this in production for a significant performance boost with:
|
||||
|
||||
@@ -40,4 +40,4 @@ angular.reloadWithDebugInfo();
|
||||
The page should reload and the debug information should now be available.
|
||||
|
||||
For more see the docs pages on {@link ng.$compileProvider#debugInfoEnabled `$compileProvider`}
|
||||
and {@link ng/function/angular.reloadWithDebugInfo `angular.reloadWithDebugInfo`}.
|
||||
and {@link angular.reloadWithDebugInfo `angular.reloadWithDebugInfo`}.
|
||||
|
||||
@@ -23,7 +23,7 @@ watch {@link guide/expression expressions} and propagate events.
|
||||
access to shared model properties. Nested scopes are either "child scopes" or "isolate scopes".
|
||||
A "child scope" (prototypically) inherits properties from its parent scope. An "isolate scope"
|
||||
does not. See {@link
|
||||
guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive isolated
|
||||
guide/directive#isolating-the-scope-of-a-directive isolated
|
||||
scopes} for more information.
|
||||
|
||||
- Scopes provide context against which {@link guide/expression expressions} are evaluated. For
|
||||
@@ -39,7 +39,7 @@ linking} phase the {@link ng.$compileProvider#directive directives} set up
|
||||
render the updated value to the DOM.
|
||||
|
||||
Both controllers and directives have reference to the scope, but not to each other. This
|
||||
arrangement isolates the controller from the directive as well as from DOM. This is an important
|
||||
arrangement isolates the controller from the directive as well as from the DOM. This is an important
|
||||
point since it makes the controllers view agnostic, which greatly improves the testing story of
|
||||
the applications.
|
||||
|
||||
@@ -313,7 +313,7 @@ ng.directive:ngController ng-controller} and {@link
|
||||
ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||
and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM
|
||||
element by using an `angular.element(aDomElement).scope()` method call.
|
||||
See the {@link guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
See the {@link guide/directive#isolating-the-scope-of-a-directive
|
||||
directives guide} for more information about isolate scopes.
|
||||
|
||||
### Controllers and Scopes
|
||||
|
||||
@@ -19,7 +19,7 @@ Angular offers several useful services (like {@link ng.$http `$http`}), but for
|
||||
you'll also want to {@link services#creating-services create your own}.
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** Like other core Angular identifiers built-in services always start with `$`
|
||||
**Note:** Like other core Angular identifiers, built-in services always start with `$`
|
||||
(e.g. `$http`).
|
||||
</div>
|
||||
|
||||
@@ -68,79 +68,6 @@ subsystem takes care of the rest.
|
||||
</file>
|
||||
</example>
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** Angular uses
|
||||
[**constructor injection**](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
|
||||
</div>
|
||||
|
||||
### Explicit Dependency Injection
|
||||
|
||||
A component should explicitly define its dependencies using one of the {@link di injection
|
||||
annotation} methods:
|
||||
|
||||
1. Inline array injection annotation (preferred):
|
||||
```js
|
||||
myModule.controller('MyController', ['$location', function($location) { ... }]);
|
||||
```
|
||||
|
||||
2. `$inject` property:
|
||||
```js
|
||||
var MyController = function($location) { ... };
|
||||
MyController.$inject = ['$location'];
|
||||
myModule.controller('MyController', MyController);
|
||||
```
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** Use the array annotation shown above.
|
||||
</div>
|
||||
|
||||
### Implicit Dependency Injection
|
||||
|
||||
Even if you don't annotate your dependencies, Angular's DI can determine the dependency from the
|
||||
name of the parameter. Let's rewrite the above example to show the use of this implicit dependency
|
||||
injection of `$window`, `$scope`, and our `notify` service:
|
||||
|
||||
<example module="myServiceModuleDI">
|
||||
<file name="index.html">
|
||||
<div id="implicit" ng-controller="MyController">
|
||||
<p>Let's try the notify service, that is implicitly injected into the controller...</p>
|
||||
<input ng-init="message='test'" ng-model="message">
|
||||
<button ng-click="callNotify(message);">NOTIFY</button>
|
||||
<p>(you have to click 3 times to see an alert)</p>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('myServiceModuleDI', []).
|
||||
factory('notify', function($window) {
|
||||
var msgs = [];
|
||||
return function(msg) {
|
||||
msgs.push(msg);
|
||||
if (msgs.length == 3) {
|
||||
$window.alert(msgs.join("\n"));
|
||||
msgs = [];
|
||||
}
|
||||
};
|
||||
}).
|
||||
controller('MyController', function($scope, notify) {
|
||||
$scope.callNotify = function(msg) {
|
||||
notify(msg);
|
||||
};
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming)) your
|
||||
code, your variable names will get renamed unless you use one of the annotation techniques above.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
If you use a tool like [ng-annotate](https://github.com/olov/ng-annotate) in your workflow you can
|
||||
use implicit dependency notation within your codebase and let **ng-annotate** automatically convert such
|
||||
injectable functions to the array notation prior to minifying.
|
||||
</div>
|
||||
|
||||
|
||||
## Creating Services
|
||||
|
||||
@@ -157,11 +84,11 @@ on the service.
|
||||
Services are registered to modules via the {@link angular.Module Module API}.
|
||||
Typically you use the {@link angular.module Module#factory} API to register a service:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
var myModule = angular.module('myModule', []);
|
||||
myModule.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
// factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
```
|
||||
@@ -174,6 +101,8 @@ will create this instance when called.
|
||||
Services can have their own dependencies. Just like declaring dependencies in a controller, you
|
||||
declare dependencies by specifying them in the service's factory function signature.
|
||||
|
||||
For more on dependencies, see the {@link guide/di dependency injection} docs.
|
||||
|
||||
The example module below has two services, each with various dependencies:
|
||||
|
||||
```js
|
||||
@@ -231,14 +160,14 @@ In the example, note that:
|
||||
You can also register services via the {@link auto.$provide `$provide`} service inside of a
|
||||
module's `config` function:
|
||||
|
||||
```javascript
|
||||
angular.module('myModule', []).config(function($provide) {
|
||||
```js
|
||||
angular.module('myModule', []).config(['$provide', function($provide) {
|
||||
$provide.factory('serviceId', function() {
|
||||
var shinyNewServiceInstance;
|
||||
//factory function body that constructs shinyNewServiceInstance
|
||||
// factory function body that constructs shinyNewServiceInstance
|
||||
return shinyNewServiceInstance;
|
||||
});
|
||||
});
|
||||
}]);
|
||||
```
|
||||
|
||||
This technique is often used in unit tests to mock out a service's dependencies.
|
||||
|
||||
@@ -268,8 +268,8 @@ logic, further simplifying the application logic.
|
||||
|
||||
```js
|
||||
myModule.filter('length', function() {
|
||||
return function(text){
|
||||
return (''+(text||'')).length;
|
||||
return function(text) {
|
||||
return ('' + (text || '')).length;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ development web server, run tests, and generate distributable files. Depending o
|
||||
pre-packaged bundle.
|
||||
|
||||
* [Java](http://www.java.com): We minify JavaScript using our
|
||||
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 6 or higher) installed
|
||||
[Closure Tools](https://developers.google.com/closure/) jar. Make sure you have Java (version 7 or higher) installed
|
||||
and included in your [PATH](http://docs.oracle.com/javase/tutorial/essential/environment/paths.html) variable.
|
||||
|
||||
* [Grunt](http://gruntjs.com): We use Grunt as our build system. Install the grunt command-line tool globally with:
|
||||
|
||||
@@ -50,7 +50,7 @@ Yes. See instructions in {@link downloading}.
|
||||
|
||||
### What browsers does Angular work with?
|
||||
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera 15,
|
||||
IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
|
||||
Explorer Compatibility} for more details in supporting legacy IE browsers.
|
||||
|
||||
|
||||
@@ -110,8 +110,9 @@ suggested solution is to also install the `nodejs-legacy` apt package, which ren
|
||||
`nodejs`.
|
||||
|
||||
```
|
||||
apt-get install nodejs-legacy
|
||||
apt-get install nodejs-legacy npm
|
||||
nodejs --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ __`app/index.html`:__
|
||||
|
||||
<ul>
|
||||
<li ng-repeat="phone in phones">
|
||||
{{phone.name}}
|
||||
<span>{{phone.name}}</span>
|
||||
<p>{{phone.snippet}}</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -150,7 +150,7 @@ __`test/e2e/scenarios.js`:__
|
||||
...
|
||||
it('should be possible to control phone order via the drop down select box', function() {
|
||||
|
||||
var phoneNameColumn = element.all(by.repeater('phone in phones').column('{{phone.name}}'));
|
||||
var phoneNameColumn = element.all(by.repeater('phone in phones').column('phone.name'));
|
||||
var query = element(by.model('query'));
|
||||
|
||||
function getNames() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
In this step, you will learn how to create a layout template and how to build an app that has
|
||||
multiple views by adding routing, using an Angular module called 'ngRoute'.
|
||||
|
||||
* When you now navigate to `app/index.html`, you are redirected to `app/index.html#/phones`
|
||||
* When you now navigate to `app/index.html`, you are redirected to `app/index.html/#/phones`
|
||||
and the phone list appears in the browser.
|
||||
* When you click on a phone link the url changes to one specific to that phone and the stub of a
|
||||
phone detail page is displayed.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
In this step, you will change the way our app fetches data.
|
||||
|
||||
* We defined a custom service that represents a [RESTful][restful] client. Using this client we
|
||||
* We define a custom service that represents a [RESTful][restful] client. Using this client we
|
||||
can make requests to the server for data in an easier way, without having to deal with the
|
||||
lower-level {@link ng.$http $http} API, HTTP methods and URLs.
|
||||
|
||||
@@ -66,7 +66,7 @@ npm install
|
||||
|
||||
Our custom resource service will be defined in `app/js/services.js` so we need to include this file
|
||||
in our layout template. Additionally, we also need to load the `angular-resource.js` file, which
|
||||
contains the {@link api/ngResource ngResource} module:
|
||||
contains the {@link module:ngResource ngResource} module:
|
||||
|
||||
__`app/index.html`.__
|
||||
|
||||
@@ -171,7 +171,7 @@ we require, so in these cases, we can add a callback to process the server respo
|
||||
|
||||
## Test
|
||||
|
||||
Because we're now using the {@link ngResource ngResource} module, it's necessary to also need to
|
||||
Because we're now using the {@link ngResource ngResource} module, it's necessary to
|
||||
update the Karma config file with angular-resource so the new tests will pass.
|
||||
|
||||
__`test/karma.conf.js`:__
|
||||
@@ -276,12 +276,12 @@ describe('PhoneCat controllers', function() {
|
||||
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
<pre>Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)</pre>
|
||||
<pre>Chrome 22.0: Executed 5 of 5 SUCCESS (0.038 secs / 0.01 secs)</pre>
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
With the phone image swapper in place, we're ready for {@link step_12 step 12} (the last step!) to
|
||||
Now that we've seen how to build a custom service as a RESTful client, we're ready for {@link step_12 step 12} (the last step!) to
|
||||
learn how to improve this application with animations.
|
||||
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ animations on top of the template code we created before.
|
||||
* Common `ng` directives automatically trigger hooks for animations to tap into.
|
||||
* When an animation is found then the animation will run in between the standard DOM operation that
|
||||
is being issued on the element at the given time (e.g. inserting and removing nodes on
|
||||
{@link api/ng.directive:ngRepeat `ngRepeat`} or adding and removing classes on
|
||||
{@link api/ng.directive:ngClass `ngClass`}).
|
||||
{@link ngRepeat `ngRepeat`} or adding and removing classes on
|
||||
{@link ngClass `ngClass`}).
|
||||
|
||||
<div doc-tutorial-reset="12"></div>
|
||||
|
||||
@@ -81,7 +81,7 @@ To get an idea of how animations work with AngularJS, please read the
|
||||
## Template
|
||||
|
||||
The changes required within the HTML template code is to link the asset files which define the animations as
|
||||
well as the `angular-animate.js` file. The animation module, known as {@link api/ngAnimate `ngAnimate`}, is
|
||||
well as the `angular-animate.js` file. The animation module, known as {@link module:ngAnimate `ngAnimate`}, is
|
||||
defined within `angular-animate.js` and contains the code necessary to make your application become animation
|
||||
aware.
|
||||
|
||||
@@ -252,7 +252,7 @@ which are described in detail below.
|
||||
|
||||
## Animating `ngView` with CSS Keyframe Animations
|
||||
|
||||
Next let's add an animation for transitions between route changes in {@link api/ngRoute.directive:ngView `ngView`}.
|
||||
Next let's add an animation for transitions between route changes in {@link ngRoute.directive:ngView `ngView`}.
|
||||
|
||||
To start, let's add a new CSS class to our HTML like we did in the example above.
|
||||
This time, instead of the `ng-repeat` element, let's add it to the element containing the `ng-view` directive.
|
||||
|
||||
@@ -63,8 +63,8 @@ gulp.task('build-app', function() {
|
||||
gulp.task('assets', ['bower'], function() {
|
||||
var JS_EXT = /\.js$/;
|
||||
return merge(
|
||||
gulp.src([assets])
|
||||
.pipe(gulp.dest(outputFolder)),
|
||||
gulp.src(['img/**/*']).pipe(gulp.dest(outputFolder + '/img')),
|
||||
gulp.src([assets]).pipe(gulp.dest(outputFolder)),
|
||||
gulp.src([assets])
|
||||
.pipe(foreach(function(stream, file) {
|
||||
if (JS_EXT.test(file.relative)) {
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0" y="0" width="687px" height="176px" viewBox="0 0 687 176" overflow="visible" enable-background="new 0 0 687 176"
|
||||
xml:space="preserve">
|
||||
<defs>
|
||||
</defs>
|
||||
<path fill="#FFFFFF" d="M179.011,125.328V54.527h9.158l43.322,57.035V54.527h8.666v70.801h-9.158l-43.326-57.536v57.536H179.011z
|
||||
M179.011,125.328"/>
|
||||
<path fill="#FFFFFF" d="M310.46,122.554c-5.708,2.182-11.864,3.269-18.467,3.269c-25.644,0-38.469-12.294-38.469-36.887
|
||||
c0-23.27,12.378-34.908,37.134-34.908c7.096,0,13.7,0.994,19.802,2.976v7.921c-6.103-2.311-12.378-3.468-18.813-3.468
|
||||
c-19.306,0-28.96,9.162-28.96,27.479c0,19.639,9.504,29.463,28.517,29.463c3.034,0,6.404-0.396,10.103-1.193V93.145h9.154V122.554z
|
||||
M310.46,122.554"/>
|
||||
<path fill="#FFFFFF" d="M325.067,97.996V54.523h9.154v43.473c0,13.598,6.768,20.4,20.303,20.4c13.531,0,20.301-6.803,20.301-20.4
|
||||
V54.523h9.158v43.473c0,18.556-9.82,27.825-29.459,27.825C334.886,125.821,325.067,116.552,325.067,97.996L325.067,97.996z
|
||||
M325.067,97.996"/>
|
||||
<path fill="#FFFFFF" d="M409.48,54.523v63.376h37.037v7.425h-46.191V54.523H409.48z M409.48,54.523"/>
|
||||
<path fill="#FFFFFF" d="M459.736,125.327h-9.504l35.201-80.146l35.199,80.146h-10.15l-9.158-22.282h-23.418l2.527-7.424h17.82
|
||||
l-13.217-32.088L459.736,125.327z M459.736,125.327"/>
|
||||
<path fill="#FFFFFF" d="M530.289,125.328V54.527h30.203c13.469,0,20.197,5.659,20.197,16.982c0,9.207-6.578,16.028-19.75,20.445
|
||||
l24.309,33.374h-12.086l-22.521-31.835v-5.992c13.531-2.151,20.301-7.344,20.301-15.598c0-6.533-3.766-9.801-11.293-9.801h-20.201
|
||||
v63.226H530.289z M530.289,125.328"/>
|
||||
<path fill="#B52E31" d="M619.561,54.523v50.405c0,13.603-8.006,20.396-24.016,20.396V117.9c9.902,0,14.857-4.329,14.857-12.973
|
||||
V54.523H619.561z M619.561,54.523"/>
|
||||
<path fill="#B52E31" d="M635.896,122.849v-8.418c7.428,2.639,15.447,3.965,24.064,3.965c12.178,0,18.271-4.457,18.271-13.372
|
||||
c0-7.584-4.492-11.385-13.469-11.385h-9.113c-14.818,0-22.234-6.435-22.234-19.31c0-13.531,9.492-20.303,28.479-20.303
|
||||
c8.25,0,15.922,0.998,23.021,2.976v8.418c-7.1-2.644-14.771-3.965-23.021-3.965c-12.875,0-19.311,4.293-19.311,12.875
|
||||
c0,7.588,4.352,11.385,13.066,11.385h9.113c15.08,0,22.627,6.439,22.627,19.31c0,13.864-9.141,20.796-27.43,20.796
|
||||
C651.344,125.819,643.324,124.826,635.896,122.849L635.896,122.849z M635.896,122.849"/>
|
||||
<path fill="#B2B2B2" d="M82.688,0L0,29.1l13.066,108.335l69.71,38.314l70.069-38.834l13.062-108.331L82.688,0z M82.688,0"/>
|
||||
<path fill="#B52E31" d="M157.66,34.846L82.496,9.214v157.381l62.991-34.861L157.66,34.846z M157.66,34.846"/>
|
||||
<path fill="#E23237" d="M9.279,35.308l11.196,96.889l62.019,34.398V9.211L9.279,35.308z M9.279,35.308"/>
|
||||
<path fill="#F2F2F2" d="M99.918,87.493L82.632,51.396L67.415,87.493H99.918z M106.508,102.672h-45.82l-10.251,25.64l-19.067,0.352
|
||||
L82.496,14.929l52.908,113.734h-17.673L106.508,102.672z M106.508,102.672"/>
|
||||
<path fill="#B2B2B2" d="M82.496,14.929l0.136,36.467l17.268,36.125H82.534l-0.039,15.127l24.012,0.023l11.223,25.996l18.245,0.339
|
||||
L82.496,14.929z M82.496,14.929"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
@@ -267,7 +267,7 @@ goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
|
||||
* 18: two decimals precision (2), currency sign last (16), no space (0)
|
||||
* 50: two decimals precision (2), currency sign last (16), space (32)
|
||||
*
|
||||
* @type {!Object.<!Array>}
|
||||
* @type {!Object.<!Array.<?>>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfo = {
|
||||
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
|
||||
@@ -334,7 +334,7 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
|
||||
/**
|
||||
* Tier 2 currency information.
|
||||
* @type {!Object.<!Array>}
|
||||
* @type {!Object.<!Array.<?>>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'AFN': [48, 'Af.', 'AFN'],
|
||||
|
||||
@@ -56,7 +56,7 @@ function newTestLocaleInfo() {
|
||||
}
|
||||
|
||||
|
||||
describe("findLocaleId", function () {
|
||||
describe("findLocaleId", function() {
|
||||
it("should find the id from numbers", function() {
|
||||
expect(findLocaleId("NumberFormatSymbols_en_GB", "num")).toEqual("en_GB");
|
||||
});
|
||||
@@ -74,7 +74,7 @@ describe("findLocaleId", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractNumberSymbols", function () {
|
||||
describe("extractNumberSymbols", function() {
|
||||
it("should extract number data", function() {
|
||||
var CONTENT = [
|
||||
"goog.provide('goog.i18n.NumberFormatSymbols_en_GB');",
|
||||
@@ -117,7 +117,7 @@ describe("extractNumberSymbols", function () {
|
||||
})
|
||||
});
|
||||
|
||||
describe("extractCurrencySymbols", function () {
|
||||
describe("extractCurrencySymbols", function() {
|
||||
it("should extract currency data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.currency.CurrencyInfo = {",
|
||||
@@ -137,7 +137,7 @@ describe("extractCurrencySymbols", function () {
|
||||
});
|
||||
|
||||
|
||||
describe("extractDateTimeSymbols", function () {
|
||||
describe("extractDateTimeSymbols", function() {
|
||||
it("should extract date time data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.DateTimeSymbols_fr_CA = {",
|
||||
|
||||