Compare commits

...

377 Commits

Author SHA1 Message Date
Matias Niemelä 78ba429e6a chore(CHANGELOG): remove reverted commits from 1.2.4 2013-12-06 13:14:56 -05:00
Matias Niemelä dbf8c3c745 revert: chore(Angular.js): Use call and === instead of apply and == in type check functions 2013-12-06 13:14:08 -05:00
Matias Niemelä 3602c9785b revert: chore($resource): Use shallow copy instead of angular.copy 2013-12-06 13:13:48 -05:00
Matias Niemelä acaac21fd1 chore(release): cut 1.2.4 wormhole-blaster release 2013-12-06 12:46:25 -05:00
Matias Niemelä c98ef94706 docs(CHANGELOG): add v1.2.4 changes 2013-12-06 12:46:01 -05:00
Tobias Bosch b0972a2e75 fix($compile): update cloned elements if the template arrives after the cloning
If an element has a directive whose content is loaded using `templateUrl`,
and the element is cloned using a linking function before the template arrives,
the clone needs to be updated as well.

This also updates `ngIf` and `ngRepeat` to keep the connection to the clone
of a tranclude function, so that they know about the changes a directive with
`templateUrl` does to the element in the future.

Fixes to #4930.
2013-12-05 22:16:25 -08:00
Caitlin Potter 2dbb6f9a54 fix(isElement): return boolean value rather than truthy value.
angular.isElement currently returns a truthy object/function, or false. This
patch aims to correct this behaviour by casting the result of the isElement
expression to a boolean value via double-negation.

Closes #4519
Closes #4534
2013-12-05 17:14:05 -08:00
Karl Seamon 785a5fd7c1 chore(Angular.js): Use call and === instead of apply and == in type check functions
Updates isDate et al to use call instead of apply and === instead of ==.
The change to call brings minor performance improvement and === is just
better practice than ==.
http://jsperf.com/call-vs-apply-tostring

Closes #5295
2013-12-05 16:43:11 -08:00
Karl Seamon a55c1e79cf chore($resource): Use shallow copy instead of angular.copy
Replace calls to angular.copy with calls to a new function, shallowClearAndCopy.
Add calls to copy for cache access in $http in order to prevent modification of cached data.
Results in a measurable improvement to the startup time of complex apps within Google.

Closes #5300
2013-12-05 16:13:04 -08:00
Karl Seamon d070450cd2 chore(Scope): short-circuit after dirty-checking last dirty watcher
Stop dirty-checking during $digest after the last dirty watcher has been re-checked.

This prevents unneeded re-checking of the remaining watchers (They were already
checked in the previous iteration), bringing a substantial performance improvement
to the average case run time of $digest.

Closes #5272
Closes #5287
2013-12-05 15:37:37 -08:00
Andres Kalle 09648e4888 docs(tutorial/step-6): remove unused class="diagram"
Closes #5197
2013-12-05 22:17:07 +00:00
Pete Bacon Darwin 2adbcf189b docs(tutorial/step-3): remember to install karma plugins 2013-12-05 22:06:38 +00:00
Pete Bacon Darwin 39c5ffb2a6 docs(tutorial/step-2): remember to install karma plugins 2013-12-05 22:06:28 +00:00
Tobias Bosch 04a570d31c docs(TRIAGING): Initial doc about triaging issues in Angular 2013-12-05 09:36:14 -08:00
Matias Niemelä 958d3d56b1 fix($animate): ensure animations work with directives that share a transclusion
Closes #4716
Closes #4871
Closes #5021
Closes #5278
2013-12-05 10:54:19 -05:00
Caitlin Potter 0e50810c53 fix(ngInit): evaluate ngInit before ngInclude
The priority of ngInit is adjusted to occur before ngInclude, and after
ngController. This enables ngInit to initiallize values in a controller's
scope, and also to initiallize values before ngInclude executes.

Closes #5167
Closes #5208
2013-12-04 23:26:56 -08:00
Vojta Jina 21e48abbc1 chore(travis): move checks from before_scripts to scripts
If jshint (or any other ci-check) fails, Travis marks the build as "Errored" which I don't think is desider:
https://travis-ci.org/angular/angular.js/builds/14938896
2013-12-04 22:53:54 -08:00
Daniel Tabuenca b6d5439343 fix(input): ensure ngModelWatch() triggers second digest pass when appropriate
Due to an earlier change, ngModelWatch() no longer returns a value to the
caller. This means the digest loop has no way to tell if the watch actually
modified anything and so can not schedule another pass.

This means any watches that watch form or model controller changes
(e.g. watches on form.$valid) that are scheduled prior to an ngModelWatch()
will not be able to see any changes made therin.

This commit fixes this behavior by returning the latest evaluated ng-model
value.

Closes #5258
Closes #5282
2013-12-04 22:49:11 -08:00
Matias Niemelä 93901bdde4 fix($animate): ensure ms durations are properly rounded
Closes #5113
Closes #5162
2013-12-04 19:26:40 -05:00
Jeff Cross d802ed1b36 fix($rootScope): broadcast $destroy event on $rootScope
Fixes #5169
2013-12-04 15:29:19 -08:00
Sorin Gitlan e8f4305e9d docs($interpolate): demonstrate a filter in the interpolated expression
Closes #5186
2013-12-04 22:36:42 +00:00
Iwona Lalik b38a2287f2 docs(tutorial/step-3): add module to ng-app directive in code sample
Closes #5184
2013-12-04 22:36:42 +00:00
Julien Bouquillon 1e7675ad4c docs(input): remove deprecated isolated scope pitfall
The 1.2 release fixed the documented pitfall at 909cabd36d
by isolating only the isolated directive's scope.

Closes #5179
2013-12-04 22:36:41 +00:00
David Bennett 280b5ce3c0 chore(closure): add $routeProvider#redirectTo function parameters
Closes #5173
2013-12-04 22:36:41 +00:00
Elwin Arens fbc5cf514b docs(tutorial/step-12): fix refernce to incorrect jquery version
Closes #5156
2013-12-04 22:36:40 +00:00
Mateusz Jedruch f01087f802 fix(closure): closure compiler shouldn't rename .defaults.transformRequest 2013-12-04 14:01:34 -08:00
Yves Richard 4ac6424e87 docs(animate.js): fix copy/paste typo in leave docs
fix the copy/paste typo within $animate.leave method inside of the $animate docs.
2013-12-04 14:28:32 -05:00
Thomas Guillory d3c486dd6d fix($rootScope): clear phase if an exception is raised by a watcher
Add calls to clearPhase() when an exception is raised by a watcher
while a digest cycle, in order to not be stuck on `$digest` scope phase
2013-12-04 10:11:29 -08:00
Daniel Tabuenca 2d0f6ccba8 fix($compile): ensure isolated local watches' lastValue is always in sync
When using two-way binding with isolate scope, under some circumstances
the lastValue variable captured in the parentValueWatch function can get
out of sync.

Specifically, if both the value in the origin scope as well as the value
in the isolate scope get independently updated to the same value within
one digest cycle, the lastValue is never updated. This potentially causes
the watch to make the wrong decision as to which side to update on subsequent
passes.

This fixes things by ensuring lastValue is always set to the last seen
value even if the watch's logic was short circuited because there was no
difference between the values in the original and isolate scopes.

Closes #5182
2013-12-04 09:45:20 -08:00
Vojta Jina 9a81b8668a chore(travis): give browsers more time to respond 2013-12-03 19:32:32 -08:00
Vojta Jina 9481d69d1c chore(travis): add IE 11 (SL) to the build 2013-12-03 19:32:32 -08:00
Vojta Jina 7615723547 chore: make it simpler to run tests on SL/BS during local development 2013-12-03 16:07:13 -08:00
Vojta Jina 338f949259 chore(travis): set SauceLabs build id 2013-12-03 15:49:19 -08:00
Vojta Jina d0192b31a3 chore(travis): disable IE11
For some reason it's broken on SL.
2013-12-03 15:49:19 -08:00
Vojta Jina 6127528b50 chore(travis): switch back to SauceLabs
I think we are pretty close to be able to use both.

The xhr-polling seems to be pretty stable, but I'm having problems with multiple SSH tunnels (on BS), so let's try to switch back to SL.
2013-12-03 15:49:19 -08:00
Vojta Jina 0410572322 chore(travis): define a launcher for IE11 (SauceLabs) 2013-12-03 15:49:19 -08:00
Vojta Jina fd2371cfc2 chore(travis): report both build number and id to BS 2013-12-03 15:49:19 -08:00
Vojta Jina 267fcc999c chore(travis): log used ports 2013-12-03 15:49:18 -08:00
Vojta Jina 84187b6d94 chore(travis): use different port numbers per build
We can't establish multiple SSH tunnels for the same port (for BrowserStack).
This makes it possible to run multiple parallel builds using BrowserStack.
2013-12-03 15:49:18 -08:00
Vojta Jina 5d6482bb3b chore(karma): correct the 404 ignoring 2013-12-03 15:49:18 -08:00
Naomi Black 023765c593 docs: fixed a typo and made a minor edit to docs section of CONTRIBUTING.md 2013-12-03 15:44:56 -08:00
Igor Minar 4a401bbcf3 style(Scope): remove extra ws 2013-12-03 15:44:13 -08:00
Igor Minar 7401c70718 style(Scope): rename child scope type from Child to ChildScope
This change makes it easier to debug angular, especiall when dealing with heap snapshots
and hunting for memory leaks.
2013-12-03 15:44:13 -08:00
Igor Minar bb36bc7edf style(Angular.js): fix typo in comment 2013-12-03 15:44:13 -08:00
Michał Gołębiowski bf1972dc1e fix(ngSanitize): prefer textContent to innerText to avoid layout trashing
innerText depends on styling as it doesn't display hidden elements.
Therefore, it's better to use textContent not to cause unnecessary
reflows. However, IE<9 don't support textContent so the innerText
fallback is necessary.
2013-12-03 14:45:30 -08:00
Karl Seamon 689dfb1679 chore($parse): micro-optimization for ensureSafeObject function
This version matches the "alternate 2.2" version here: http://jsperf.com/ensuresafeobject/2

alternate 2.3 is a bit faster and simpler, but would break backwards compatibility.

Closes #5246
2013-12-03 11:10:48 -08:00
Hubert SABLONNIÈRE 1169b54456 fix(jqLite): ignore incompatible nodes on find()
When a jqLite collection contains text nodes, find() does not work :-(

This fix ignores all nodes than can't do getElementsByTagName()

It seems a little bit faster than testing nodeType : http://jsperf.com/nodetype-vs-duck-typing

Closes #4120
2013-12-03 09:45:06 -08:00
Pete Bacon Darwin 81b81856ee fix($sanitize): don't rely on YARR regex engine executing immediately
In Safari 7 (and other browsers potentially using the latest YARR JIT library)
regular expressions are not always executed immediately that they are called.
The regex is only evaluated (lazily) when you first access properties on the `matches`
result object returned from the regex call.

In the case of `decodeEntities()`, we were updating this returned object, `parts[0] = ''`,
before accessing it, `if (parts[2])', and so our change was overwritten by the result
of executing the regex.

The solution here is not to modify the match result object at all. We only need to make use
of the three match results directly in code.

Developers should be aware, in the future, when using regex, to read from the result object
before making modifications to it.

There is no additional test committed here, because when run against Safari 7, this
bug caused numerous specs to fail, which are all fixed by this commit.

Closes #5193
Closes #5192
2013-12-03 13:35:09 +00:00
Vojta Jina fd4b99936e chore(travis): increase BrowserStack timeout to 10min
Because IE is retarded.
2013-12-02 22:51:15 -08:00
Vojta Jina 09271a8ab9 chore(travis): ignore 404 warnings, debug log into file
This is a terrible hack/workaround, however I don't think there is any better way to achieve this
with log4js.
2013-12-02 22:51:15 -08:00
Naomi Black 5a8d9acacb docs: update CONTRIBUTING.MD with process for doc fixes 2013-12-02 16:23:59 -08:00
Vojta Jina 04d5a5072f chore(travis): fix the build id on browser stack
This just improves the way BrowserStack groups the sessions.
2013-12-02 14:43:44 -08:00
Vojta Jina 55c30e1be6 chore: use karma-browserstack-launcher from master 2013-12-02 14:20:14 -08:00
Vojta Jina 97fc84c151 chore(deps): use regular junit-reporter
We don't need the special branch anymore.
2013-12-02 14:20:06 -08:00
Vojta Jina 4ee0687f3f chore(travis): tolerate 2 disconnects to make the build more stable 2013-12-02 14:19:56 -08:00
Vojta Jina ddff347b91 chore(travis): use only websockets and xhr-polling
I wanna see more info about BrowserStack...
2013-12-02 14:19:46 -08:00
James Brewer 05ef1bd853 chore(grunt): update to latest jshint task
Upgrade JSHint task from ~0.6.4 to ~0.7.2. Two useful changes: ability
to set jshintrc option to use jshint's native ability for finding .jshintrc
files relative to the linted files and update jshint to 2.3.0.

Closes #5143
2013-12-02 21:20:07 +00:00
Blaise Kal d0f8bd30a6 docs($animate): require ngAnimate in example, syntax fixes
The example in the section "JavaScript-defined Animations" would not run without the ngAnimate dependency. Also added a missing comma and semicolons.
2013-12-02 14:55:34 -05:00
Peter Bacon Darwin 1a8d3c8b3a chore(docs): fix back-to-top anchor in angularjs.org doc pages
Closes https://github.com/angular/angularjs.org/issues/45
2013-11-28 12:16:07 +00:00
Levi Weiss 753687e5c2 docs(tutorial/step-10): fix typo
Closes #5171
2013-11-27 23:21:46 +00:00
Stéphane Reynaud 1a15c01b64 docs($compile): fix missing space 2013-11-27 23:20:09 +00:00
Ammar 7f33e1ca89 docs(tutorial/step-12): fix typo
Closes #5148
2013-11-27 23:19:02 +00:00
magoswiat 28d00945ba docs(tutorial/step-0): add target="_blank" to open app in new page
Closes #5145
2013-11-27 23:17:28 +00:00
Blaise Kal 6f40c88f47 docs(form): provide a list of Angular's built-in validation tokens
As requested by a top-rated Disqus comment: http://docs.angularjs.org/api/ng.directive:form.FormController#comment-655325797

Closes #5121
2013-11-27 23:06:19 +00:00
deepak-kapoor 68dd621082 docs(guide/concepts): fix incorrect module name in example
Closes #5116
2013-11-27 22:59:13 +00:00
wjtk 3abfb4ef51 docs($window): move use of $window to controller
Move use of `$window` from template to controller, because accessing `$window`
in expressions is now disallowed and doesn't work.

Closes #5110
2013-11-27 22:54:45 +00:00
Pete Bacon Darwin 1014e52349 docs($injector): use square bracket notation for $inject annotation
Closes #5104
2013-11-27 22:52:10 +00:00
Evan Winslow cda061f723 docs(guide/di): use square bracket notation for $inject annotation
Closes #5104
2013-11-27 22:48:02 +00:00
Pavel Pomerantsev 1497c6c1fb docs(guide/providers): fix typo
Closes #5102
2013-11-27 22:41:53 +00:00
Marc Lipovsky e41e445b51 docs(guide/compiler): add fourth step on appending the compiled template to the DOM
Closes #5087
2013-11-27 22:41:10 +00:00
rodyhaddad 7ab73190b7 docs(migration): add a note about "private" properties being reverted
Closes #5086
2013-11-27 22:35:09 +00:00
Peter Bacon Darwin 450b3a5460 chore(release): start 1.2.4 wormhole-baster iteration 2013-11-27 20:21:06 +00:00
Peter Bacon Darwin 38fb542838 chore(release): cut 1.2.3 unicorn-zapper release 2013-11-27 10:04:59 +00:00
Peter Bacon Darwin 7ab5098c14 docs(CHANGELOG): add v1.2.3 changes 2013-11-27 09:58:59 +00:00
Jeff Cross bcca80548d feat($attrs): add $attrs.$attr to externs so that it isn't renamed
This fixes the issue that any usage of $attr is broken after js compilation.
2013-11-26 18:34:11 -08:00
Jeff Cross 736c8fbbae refactor($location): move file://+win path fix to $location
The urlResolve method was fixed to automatically remove the
volume label from path names to fix issues with the file
protocol on windows where $location.path() was returning
paths where the first segment would be the volume name,
such as "/C:/mypath". See #4942 and #4928

However, the solution was specific to the $location non-
HTML5 mode, and was implemented at a lower level of
abstraction than it should have been. This refactor moves
the fix to inside of the LocationHashBangUrl $$parse method.

Closes #5041
2013-11-26 18:31:27 -08:00
Igor Minar 947562220d chore(release): fix cdn version in package.json 2013-11-26 17:38:23 -08:00
Tobias Bosch 333523483f fix($sanitize): Use same whitelist mechanism as $compile does.
`$sanitize` now uses the same mechanism as `$compile` to validate uris.
By this, the validation in `$sanitize` is more general and can be
configured in the same way as the one in `$compile`.

Changes
- Creates the new private service `$$sanitizeUri`.
- Moves related specs from `compileSpec.js` into `sanitizeUriSpec.js`.
- Refactors the `linky` filter to be less dependent on `$sanitize`
  internal functions.

Fixes #3748.
2013-11-26 14:29:38 -08:00
corrupt 68ceb17272 chore($httpBackend): preserve original non-zero http status code for file:// apps
Previously if an app was running from file:// origin we would always return either
http 200 or 404 depending on whether the response was present.

This changes the behavior so that we do this only if the protocol of the request
(not the origin) is file:// and only if the status code is 0.

Closes #4436
Closes #4587
Closes #4514
2013-11-26 12:36:41 -08:00
David Mosher 5bd6596856 chore(mocks): wrap angular-mocks.js in closure
Closes #5080
2013-11-26 13:22:29 +00:00
Peter Bacon Darwin b3f2a20832 chore(changelog): remove tmp file 2013-11-26 09:36:13 +00:00
adam77 e8d8c7a8d7 docs(compile): fix typo
Closes #5133
2013-11-26 06:56:38 +00:00
Deepak Kapoor 7a91d7fa7e docs(CONTRIBUTING): fix broken link to GitHub PR Helper
Closes #5134
2013-11-26 06:46:39 +00:00
smarigowda c6bd58eb58 docs(guide/scope): access the current element's scope in the console.
Closes #4884
2013-11-26 06:45:48 +00:00
sunnylost c2e45c769e refactor(angular.js): improve trim performance
According to Flagrant Badassery's blog
http://blog.stevenlevithan.com/archives/faster-trim-javascript
and this comparison http://jsperf.com/trim-function, this trim method is faster.

Closes #4406
2013-11-26 06:45:47 +00:00
Vojta Jina b08427dde9 chore(travis): add some more info for BrowserStack sessions 2013-11-25 18:04:35 -08:00
Vojta Jina ffd075b440 chore(travis): let's give BrowserStack a try
Switch the build to use BrowserStack instead of SauceLabs.

This also adds IE11 to our build.
2013-11-25 15:19:28 -08:00
Brian Ford 3fcd228441 chore: add script for updating bower repos 2013-11-25 13:09:50 -08:00
Pete Bacon Darwin 8383ecfcdf docs(CONTRIBUTING): add link to github-pr-helper 2013-11-25 20:18:36 +00:00
Matias Niemelä eed2333298 fix(ngAnimate): ensure animations are disabled upon bootstrap for structrual animations
Closes #5130
2013-11-25 15:00:50 -05:00
Pete Bacon Darwin a2809dacc4 docs(CONTRIBUTING): fix typo 2013-11-25 15:55:24 +00:00
Pete Bacon Darwin b837a31afa docs(CONTRIBUTING): highlight what makes a good issue submission 2013-11-25 14:33:51 +00:00
Pete Bacon Darwin 66b0fcd3c0 docs(CONTRIBUTING): consolidated submitting PRs sections 2013-11-25 14:15:24 +00:00
Matias Niemelä 2efe82309a fix($animate): ensure blocked keyframe animations are unblocked before the DOM operation
Closes #5106
2013-11-23 22:05:04 -05:00
Tobias Bosch a090400f09 fix(input): Support form auto complete on modern browser
Although modern browser support the "input" event, they still only fire
the "change" event when they auto complete form elements
other than the currently selected one.

Related to #1460
2013-11-22 17:02:21 -08:00
Brian Ford 84e0eea164 chore(docs): remove Disqus comments
We don't actively moderate these comments, and they range from
out of date, to inflammatory, to spam. Going forward, improvements
to the docs should be done via a PR, and questions should go on
StackOverflow where they can be curated and kept up to date by
AngularJS developers who help out there.
2013-11-22 16:27:05 -08:00
Igor Minar bcf12e70e5 chore: update copyright year in file headers 2013-11-22 13:16:23 -08:00
Igor Minar 1ca98b2c09 chore(release): start 1.2.3 unicorn-zapper iteration 2013-11-22 12:43:52 -08:00
Igor Minar 3efdeebcb7 chore(release): cut 1.2.2 consciousness-inertia release 2013-11-22 09:05:42 -08:00
Igor Minar 16febf8357 docs(CHANGELOG): add release notes for 1.2.2 consciousness-inertia 2013-11-22 09:03:40 -08:00
Caitlin Potter 0f7c4ca671 chore(style): fix missing indentation in httpBackend from a3172a2 2013-11-22 15:03:12 +00:00
Pete Bacon Darwin a3172a285f fix($httpBackend): only IE8 and below can't use script.onload for JSONP
IE8, IE9 and IE10 can use `script.onreadystate` so up till now we have been using this
if the sniffer says we are on IE.
But IE11 now does not support `script.onreadystate` and only supports the more standard
`script.onload` and `script.onerror`.
IE9 and IE10 do support `script.onload` and `script.onerror`. So now we only test whether
we are on IE8 or earlier before using `script.onreadystate`.
See http://pieisgood.org/test/script-link-events/

jQuery just uses all these handlers at once and hopes for the best, but since IE9 and IE10
support both sets of handlers, this could cause the handlers to be run more than once.

jQuery also notes that there is a potential memory leak in IE unless we remove the handlers
from the script object once they are run.  So we are doing this too, now.

Closes #4523
Closes #4527
Closes #4922
2013-11-22 13:45:55 +00:00
Igor Minar 84c408ce63 test($compile): correct the assertion to make test pass on IE11 2013-11-22 00:52:57 -08:00
rodyhaddad 40647b179c fix($parse): allow for new lines in expr when promise unwrapping is on
Previously, when unwrapping promises was set to `true`,
an error would occur if a parsed expression had a
new line in it.
This was because when generating the `evaledFnGetter` code,
a new line in an parsed expression would create a new line
in a JS string in that code, which is illegal. That is:
```js
pw("A+
B")
```

Closes #4718
2013-11-22 00:19:08 -08:00
Chirayu Krishnappa 0421cb4200 fix($compile): secure form[action] & iframe[srcdoc]
Require bindings to form[action] to be $sce.RESOURCE_URL and bindings to
iframe[srcdoc] to be $sce.HTML

Closes #4927
Closes #4933
2013-11-21 23:15:15 -08:00
Gonzalo Ruiz de Villa 6f1050df4f fix(httpBackend): should not read response data when request is aborted
When a request is aborted, it makes no sense to read the response headers or text.
Also in IE9, trying to read data (either response headers or text) from an aborted request
throws an Error c00c023f.

Fixes #4913
Closes #4940
2013-11-21 23:09:46 -08:00
Corey Burrows 4d16472b91 fix(ngMock): fixes httpBackend expectation with body object
Fixes an issue with httpBackend expectations where a given body object
may not match the actual request body if its keys are serialized in a
different order.

Closes #4956
2013-11-21 22:57:15 -08:00
Pete Bacon Darwin 9e89a31b12 fix(loader): expose $$minErr to modules such asngResource
This is highlighted in angular-phonecat when you try to use the index-async.html
which needs to load the ngResource module asynchronously but fails when it tries
to call `angular.$$minErr` to create the $resourceMinErr object.

Closes #5050
2013-11-21 22:51:26 -08:00
Tobias Bosch e6521e7491 fix(ngView): Don't throw when the ngView element contains content with directives.
Fixes #5069
2013-11-21 22:20:11 -08:00
Tobias Bosch 0a7cbb33b0 fix(ngInclude): Don't throw when the ngInclude element contains content with directives.
Related to #5069
2013-11-21 22:20:11 -08:00
Tobias Bosch 579242346c fix(tests): Correct tests for IE11
Some tests were wrong. However, src/* did not contain problems.

Fixes #5046
2013-11-21 21:53:09 -08:00
Peter Deak c42d0a0418 fix(ngAnimate): correctly retain and restore existing styles during and after animation
Closes #4869
2013-11-21 23:37:01 -05:00
Matias Niemelä 3fbb25e25c chore($animate): remove unnecessary reflective dereferencing 2013-11-21 20:48:21 -05:00
Matias Niemelä 6760d7a315 fix($animate): ensure keyframe animations are blocked around the reflow
Keyframe animations trigger on the first CSS class and not the second.
This may cause a slight flicker during a stagger animation since the
animation has already started before the stagger delay is considered.
This fix ensures that the animation is blocked until the active animation
starts which allows for staggering animations to take over properly.

Closes #5018
2013-11-21 20:48:15 -05:00
Matias Niemelä 062fbed8fc fix($animate): ensure transition animations are unblocked before the dom operation occurs
Transitions are blocked when the base CSS class is added at the start of the animation. This
causes an issue if the followup CSS class contains animatable-styles. Now, once the animation
active state is triggered (when the animation CSS dom operation occurs) the animation itself
will always trigger an animate without a quick jump.

Closes #5014
Closes #4265
2013-11-21 20:48:07 -05:00
Matias Niemelä 76e4db6f3d fix($animate): ensure addClass/removeClass animations do not snap during reflow
Closes #4892
2013-11-21 20:47:55 -05:00
Matias Niemelä 0cd7e8f227 fix($compile): ensure CSS classes are added and removed only when necessary
When $compile interpolates a CSS class attribute expression it will
do so by comparing the CSS class value already present on the element.
This may lead to unexpected results when dealing with ngClass values being
added and removed therefore it is best that both compile and ngClass delegate
addClass/removeClass operations to the same block of code.
2013-11-21 20:47:44 -05:00
Vojta Jina ba1b47f85b test(docs): fix the failing specs
Because Grunt was not failing the build, we didn't noticed these failing specs.
2013-11-21 12:41:57 -08:00
Vojta Jina 0a3481e23a chore: use temporary version of grunt-jasmine-node
This should be reverted once https://github.com/jasmine-contrib/grunt-jasmine-node/pull/33 gets merged in the upstream repo.

It fixes the problem where Grunt does not fail the build, even though there are failures.
See https://travis-ci.org/angular/angular.js/builds/14329011#L2366
2013-11-21 12:41:48 -08:00
jody tate e33c365144 docs(guide/unit-testing): minor style and grammar changes
Closes #5057
2013-11-21 20:37:57 +00:00
gdi2290 e3ceb50b73 docs(faq): update compressed and minified file size
Closes #5058
2013-11-21 20:27:27 +00:00
scottywakefield 6b5772bbbd docs(guide/ie): add info about what IE versions are supported
Added text from https://github.com/angular/angular.js/issues/4974

Closes #5070
2013-11-21 20:25:41 +00:00
Andrew Silluron-Gonzalez 6288cf5ca4 fix(ngController): fix issue with ngInclude on the same element
This changes the priority of ngController to 500 so that it takes precedence
over ngInclude.

Closes #4431, #4521
2013-11-21 09:52:34 -08:00
Tobias Bosch f6ecf9a3c9 fix($resource): Always return a resource instance when calling class methods on resources.
Previously, calling `MyResource.save(myResourceInstance)`returned
a promise, in contrast to the docs for `$resource`. However,
calling `MyResource.save({name: 'Tobias"})`already correctly
returned a resource instance.

Fixes #4545.
Closes #5061.
2013-11-21 09:51:02 -08:00
Chia-liang Kao a4e6d962d7 feat(input): hold listener during text composition
When composing text in CJKV, intermediate buffer for unfinished text should not
be updating the bound scope variables.

Closes #4684
2013-11-21 09:46:33 -08:00
Igor Minar 7874a4d007 docs(guide/migration): fix typo ngHtmlBind -> ngBindHtml 2013-11-21 07:29:18 -08:00
Matias Niemelä 1d50663b38 fix(ngAnimate): use a fallback CSS property that doesn't break existing styles
The clip property seems to remove the box-shadow property when an absolute
positioned animation is ongoing. This fix changes the property to be border-spacing
which is also very underused. The border-spacing CSS property is only visible
when border-collapse is set to separate.

Closes #4902
Closes #5030
2013-11-20 20:54:07 -05:00
Tobias Bosch ec3c4f94c7 refactor($sce): Use $sniffer instead of $document for feature detection.
Also adds `$sniffer.msieDocumentMode` property.

Closes #4931
Closes #5045
2013-11-20 23:12:39 +00:00
Matias Niemelä 6b8bbe4d90 fix(ngClass): ensure that ngClass only adds/removes the changed classes
ngClass works by removing all the former classes and then adding all the
new classes to the element during each watch change operation. This may
cause transition animations to never render. The ngClass directive will
now only add and remove the classes that change during each watch operation.

Closes #4960
Closes #4944
2013-11-20 17:15:56 -05:00
Matias Niemelä 7067a8fb0b fix($animate): ensure the DOM operation isn't run twice
Depending on the animations placed on ngClass, the DOM operation may
run twice causing a race condition between addClass and removeClass.
Depending on what classes are removed and added via $compile this may
cause all CSS classes to be removed accidentally from the element
being animated.

Closes #4949
2013-11-20 17:08:03 -05:00
Brian Ford c47abd0dd7 fix(ngInclude): allow ngInclude to load scripts when jQuery is included
In 1.2, the behavior of ngInclude was modified to use DOM APIs rather than jqLite. This means that
even when jQuery was loaded, ngInclude was not calling into it, and thus scripts were not eval'd
as they had been before. Although the use of ngInclude to eval scripts as a lazy-loading strategy
was never an intentional feature, this patch restores the ability to do so.

Closes #3756
2013-11-20 13:58:54 -08:00
Michel Salib 68d71bbc01 docs($log): the documented default log behavior was incorrect
Closes #4953
2013-11-20 21:02:02 +00:00
Jarrett Harris 334303e485 docs(ngAnimate): fixed two small typos
Line 162: 'defiend' should be 'defined'
Line 225: 'callback function be excuted' should be 'callback function will be executed'.

Closes #5048
2013-11-20 14:32:30 +00:00
gdennie b95fd53c6e docs(booleanAtts): explain the motivation for boolean attributes
It was not explicitly and consistently stated that the transient nature of boolean
attributes precludes them from hosting binding expressions.
This change make that more clear and reinforces the simplicity and elegance of the solution.

Closes #5031
2013-11-20 14:30:37 +00:00
Ashutosh Das c77dd040b4 docs(tutorial/step-2): correct the link to jasmine docs
Closes #5029
2013-11-20 14:21:49 +00:00
Stéphane Reynaud dc027f22e5 docs(ngRepeat): fix typo
Replace "ian" in "in"

Closes #5027
2013-11-20 14:10:23 +00:00
Stéphane Reynaud 043500fb27 docs(ngPluralize): Fix missing space before parentheses
There should be a space between "braces" and "(`{}`)"

Closes #5026
2013-11-20 11:38:29 +00:00
Maksim 3ceb6ab477 docs(guide/directive): use hideDialog handler in example
The handler is in the controller but was not being used in the template.

Closes #5020
2013-11-20 11:37:00 +00:00
gipsy86147 999fa44616 docs(guide/ie): fix typo
Closes #5006
2013-11-20 11:31:56 +00:00
Dave Gaeddert 5f9121ad56 docs(guide/providers): remove extra closing parenthesis in example
Closes #5005
2013-11-20 11:30:45 +00:00
Tyler Eich b4cf8483d7 docs(guide/migration): fix typo
Closes #5002
2013-11-20 11:26:57 +00:00
Yves Richard 8a9816e06b docs(guide/compiler): fix typo in isolate scope def
Closes #4999
2013-11-20 11:25:20 +00:00
jbnizet c0e10683a6 docs(api): example for $provide.value() uses $provide.value()
The example code for `$provide.value()` actually used `$provide.constant()`.
It now uses `$provide.value()`.

Closes #4983
Closes #4990
2013-11-20 11:21:09 +00:00
Pete Bacon Darwin cad5a367c3 docs(ngRoute): make it easier to find the example
Closes #4975
2013-11-20 11:18:21 +00:00
Stéphane Reynaud f2453eabb3 docs(tutorial): minimum node.js version is 0.10 (Windows too)
The doc has been modified by the following commit: bcc6e8d4f6
But the change was not made ​​for the part of Windows.

Closes #4967
2013-11-20 11:02:30 +00:00
Jayson Harshbarger aa0b11d794 docs(guide/migration): fix typo
Closes #4965
2013-11-20 11:00:01 +00:00
Matias Niemelä b9fa5c5a67 docs($animate): update the docs explaining enable/disable for specific elements 2013-11-19 17:50:24 -05:00
Vojta Jina 751f058f30 chore(travis): increase disconnect timeout
I still see some disconnection issues with IE9, hopefully this will help a bit.
2013-11-18 16:14:09 -08:00
Pete Bacon Darwin 29274e1d8d docs(ngApp): improve description and example 2013-11-18 16:21:59 +00:00
Jens Berthold 23ba287897 docs(guide/directive): clarify code example for isolated scopes bindings
Use different names for the attribute on the element (`info`) and the property (`customerInfo`)
on the isolate scope. Before `customer` was used for both which made it harder to understand.

Closes #4825
2013-11-18 15:03:35 +00:00
Pete Bacon Darwin 8f1e3606dd docs(guide/directive): add note about HTML case-insensitivity
Closes #4719
2013-11-18 12:58:53 +00:00
Chance ac56d1c9d9 docs(tutorial/step-4): controllers are no longer global functions
The docs did not line up with the codebase / previous steps of the tutorial.

Closes #4988
2013-11-18 12:49:19 +00:00
Pete Bacon Darwin de2919cb9a docs(guide/i18n): fix link to i18n files in the project
Closes #4998
2013-11-18 11:55:30 +00:00
Christoph Burgdorf 61943276f0 chore(*): remove accidentally created file
Closes #4963
2013-11-15 21:46:13 +00:00
Vojta Jina 88ce00a3cf chore(release): start a new release iteration 2013-11-15 00:03:03 -08:00
Vojta Jina a3eb6baf58 chore(release): cut the 1.2.1 underscore-empathy release 2013-11-14 22:33:20 -08:00
Vojta Jina f4fcaa8757 docs: fix the "show source" button
Closes #4904
2013-11-14 21:38:53 -08:00
Jeff Cross 40e34a924b docs(ngResource): removed buzz client example
The Buzz Client example on the ngResource
doc was causing parse errors.

While the root cause is being investigated,
the example has been removed, and should be
replaced by a more relevant example anyhow.
2013-11-14 21:22:11 -08:00
Tobias Bosch 90f87072e8 fix($compile): accessing controllers of transcluded directives from children
Additional API (backwards compatible)
- Injects `$transclude` (see directive controllers) as 5th argument to directive link functions.
- `$transclude` takes an optional scope as first parameter that overrides the
  bound scope.

Deprecations:
- `transclude` parameter of directive compile functions (use the new parameter for link functions instead).

Refactorings:
- Don't use comment node to temporarily store controllers
- `ngIf`, `ngRepeat`, ... now all use `$transclude`

Closes #4935.
2013-11-14 20:59:50 -08:00
Tobias Bosch c785918cbd refactor($compile): move function def out of loop 2013-11-14 20:53:30 -08:00
Vojta Jina 8425e9fe38 fix(loader): don't rely on internal APIs
This significantly increases the size of the loader:
- minified: 1031bytes -> 1509bytes (+46%)
- minified + gzip: 593bytes -> 810bytes (+36%)

I'm not entirely sold on the idea of shipping minErr with the loade. With the current state, the angular-loader behavior is completely broken - this is just a quick fix, we can revisit this change in the future.


Closes #4437
Closes #4874
2013-11-14 15:05:39 -08:00
Vojta Jina 94764ee089 fix(minErr): remove references to internals APIs
So that we can use minErr with angular-loader, before full angular is loaded.

This also fixes replacing the version during the build.
2013-11-14 15:00:53 -08:00
James deBoer 04492ef227 chore(mocks): Remove reference to flushNext
Closes #4885
2013-11-14 16:07:36 +00:00
victorbjelkholm c6016a6a85 docs(tutorial): change controllers to not have name twice
While giving the controller function a name helps with debugging,
since otherwise your controller will be anonymous in stack traces,
passing the name to both the `controller()` method and as the function name
is confusing for beginners.

Closes #4415
2013-11-14 14:47:01 +00:00
Pete Bacon Darwin 977e2f55de docs(ngClass): fix e2e test for example
Broken by fd7bca22e1
2013-11-14 14:20:31 +00:00
Caitlin Potter 4184ff8ff7 docs(NgModelController): document $viewChangeListeners property
Closes #4948
2013-11-14 14:13:22 +00:00
Stéphane Reynaud f3d4fe6209 docs(FormController): remove unnecessary parenthesis
Closes #4936
2013-11-14 14:09:09 +00:00
andre 9e5cd92fa9 docs(misc/faq): fix invalid escaping of character
Backslash is acting as escape character so text is not properly formatted.

Closes #4923
2013-11-14 14:06:01 +00:00
smarigowda c07f1e1c9f docs(guide/concepts): controllers can also access scope
Closes #4918
2013-11-14 14:04:09 +00:00
Pete Bacon Darwin fd7bca22e1 docs(ngClass): distinguish between CSS classes and scope properties
Closes #4914
2013-11-14 14:00:06 +00:00
Mathis Hofer 8f283fe473 docs(NgModelController): clarify documentation of $setViewValue
$setViewValue does not really "Read a value from view".
It should be called to trigger the ngModel to be updated when the value in the view changes.

Closes #4907
2013-11-14 13:48:22 +00:00
Phillip Alexander cb8061c75c docs(guide/concepts): improve sentence wording
Before:

> Let's add some more logic to the example to
allow to enter and calculate the costs in different currencies and also pay the invoice.

After:

> Let's add some more logic to the example that
allows us to enter and calculate the costs in different currencies and also pay the invoice.

Closes #4903
2013-11-14 13:36:40 +00:00
rsnapp b1366c32d4 docs($q): add missing closing parentheses in code example
Closes #4900
2013-11-14 13:27:11 +00:00
Mauro Carrero b122194425 docs(tutorial/step-2): remove repeated "the"
Closes #4854
2013-11-14 13:24:26 +00:00
Pete Bacon Darwin 089bf5f0e3 docs(guide/directive): split long lines 2013-11-14 13:22:39 +00:00
xdhmoore f6fa7c9c95 docs(guide/directive): clarify sentence meaning
Closes #4873
2013-11-14 13:16:47 +00:00
mkolodny 938b2e1217 docs(resource): fix grammatical issue
'Case' should be the plural 'cases' since it is talking about multiple possible cases rather
than a single case. For slightly more info, see the section 'When words like "none" are the
subject' in this article: http://writing.wisc.edu/Handbook/SubjectVerb.html
2013-11-14 13:12:36 +00:00
Peter Kosa dbc6696b68 docs(tutorial/step-12): fix incorrect code filename
Closes #4860
2013-11-14 13:10:29 +00:00
gdi2290 5d632af926 docs(misc/contribute): fix internal links
Closes #4848
2013-11-14 13:07:32 +00:00
PatrickJS ed9e570a12 docs(downloading): fix invalid filenames and add missing modules
Closes #4846
2013-11-14 13:03:03 +00:00
Pete Bacon Darwin d7ed885984 docs(ngBindHtml): fix dependency for Plunker and JSFiddle in example
The `<doc:example>` directive does not load up the dependencies correctly.
Using the `<example>` directive, with `<file>` elements fixes this.

Closes #4951
2013-11-14 12:28:53 +00:00
Vojta Jina 4ab16aaaf7 feat($parse): revert hiding "private" properties
Hiding `_*` properties was a feature primarily for developers using Closure compiler and Google JS
style. We didn't realize how many people will be affected by this change.

We might introduce this feature in the future, probably under a config option, but it needs more
research and so I'm reverting the change for now.

This reverts commit 3d6a89e888.

Closes #4926
Closes #4842
Closes #4865
Closes #4859
Closes #4849

Conflicts:
	src/ng/parse.js
2013-11-13 23:25:09 -08:00
Jeff Cross 89f435de84 fix(urlUtils): made removal of windows drive from path safer
Prior to this fix, the urlResolve method would automatically
strip the first segment of a path if the segment ends in a colon.
This was to correct undesired behavior in the $location service
using the file protocol on windows in multiple browsers (see #4680).

However, there could be cases where users intentionally 
have first path segments that end in a colon 
(although this conflicts with section 3.3 of rfc3986).

The solution to this problem is an extra check to make sure
the first path segment of the input url does not end with a colon,
to make sure we're only removing undesired path segments.

Fixes #4939
2013-11-13 15:53:20 -08:00
Pete Bacon Darwin bcc6e8d4f6 docs(tutorial): minimum required node.js version is 0.10 2013-11-13 22:43:34 +00:00
Martin Field b2137c9fdf docs($compile): Explain that post-link functions run in reverse order.
Update the $compile docs to mention the change introduced in #4266.

Closes #4843
2013-11-13 21:58:04 +00:00
andre bee56a82b0 docs(guide/scope): correct scopes example
Remove reference to `employee` property as it's not used in the example.
Inject and use `$rootScope` applying `department` property as mentioned in text.

Closes #4839
2013-11-13 21:48:30 +00:00
Pete Bacon Darwin bcdbfdfeae docs(guide/scope): ensure demo CSS styles work in JSFiddle and Plunker
The CSS styling in the ng-scope demo was using CSS classes (`.doc-example-live` and
`.show-scope') to prevent the styling for the demo from affecting the entire page.
Unfortunately elements containing these classes did not appear in JSFiddle or Plunker
when you click edit.

This fix moves the `.show-scope' class inside the demo (renaming it `.show-scope-demo`)
and removes the reliance on `.doc-example-live` altogether.

Closes #4838
2013-11-13 21:45:07 +00:00
Tatham Oddie afbed10feb docs(contribute): justify note about elevation on Windows
This message needs a justification. Without one, it's like asking somebody
on *nix to run everything under sudo 'just because'.

Closes #4832
2013-11-13 21:24:08 +00:00
Ben Wiklund f69ee170ed docs($httpBackendSpec): fix typo in spy name
Closes #4830
2013-11-13 21:21:50 +00:00
Eddie Monge Jr a59976be18 docs(errors/compile/tplrt): display html block as code
HTML elements were getting parsed by as HTML elements

Closes #4827
2013-11-13 21:06:37 +00:00
Derek Peterson 40d1e10520 docs(guide): fix typo
Closes #4821
2013-11-13 20:55:25 +00:00
Aaditya Talwai 5bf81bc111 docs(guide/understanding_controller): fix incorrect property reference
Correct " model property `spice` " to " model property `customSpice` " to match the code sample

Closes #4812
2013-11-13 20:51:29 +00:00
Pete Bacon Darwin 96ad0c7594 docs(ngdoc): clarify extra module installation options
Closes #4811
2013-11-13 20:43:32 +00:00
Julien Sanchez 717a6705e2 docs($http): improve $http's caching documentation
Make the possibility to pass a custom cache instance to $http more obvious.

Closes #4803
2013-11-13 20:20:59 +00:00
Ari 37ac4724ba docs(guide): add ng-newsletter to weekly updates link
Closes #4793
2013-11-13 19:52:36 +00:00
Ari 8c18ef67cf docs(guide): add ng-book link to books
Closes #4792
2013-11-13 19:50:25 +00:00
Pete Bacon Darwin dfe6400537 docs(ngdoc): fix version picker grouping
The grouping of the different versions was not correct for the new 1.2.0+ releases.
Now versions are marked as stable only if they have an even number it the minor version
position (e.g. 1.0.8, 1.2.1, 1.2.0-abcde) and they are not an RC version, (e.g. 1.0.0rc3,
1.2.0-rc2).

Closes #4908
2013-11-12 23:28:27 -08:00
ROUL f925e8caa6 fix(urlUtils): urlUtils doesn't return right path for file:// on win
Chrome and other browsers on Windows often
append the drive name to the pathname,
as described in #4680. This would cause
the location service to browse to odd
URLs, such as /C:/myfile.html,
when opening apps using file://.

Fixes  #4680
2013-11-12 22:41:06 -08:00
Tobias Bosch e1254b266d fix($compile): correctly handle interpolated style in replace templates
A directive with a template with `replace: true` and an interpolated style at the root element should work correctly.

Closes #4882.
2013-11-12 16:51:16 -08:00
Andrei Korzhevskii fa82a31fa6 fix(grunt): Fix NG_VERSION_MINOR typo 2013-11-12 13:05:27 -08:00
Tobias Bosch 4612705ec2 fix(ngIf): don't create multiple elements when changing from a truthy to another thruthy value.
Fixes #4852.
2013-11-11 17:05:43 -08:00
Chirayu Krishnappa 9577702e8d fix($resource): don't use $parse for @dotted.member
params and paramDefaults support looking up the parameter value from the
data object.  The syntax for that is `@nested.property.name`.
Currently, $resource uses $parse to do this.  This is too liberal
(you can use values like `@a=b` or `@a | filter` and have it work -
which doesn't really make sense).  It also puts up a dependency on
$parse which is has restrictions to secure expressions used in
templates.  The value here, though a string, is specified in Javascript
code and shouldn't have those restrictions.
2013-11-11 16:17:34 -08:00
Peter Bacon Darwin a61b65d01b fix(angular-bootstrap): make IE8 happy 2013-11-11 00:09:15 +00:00
Miško Hevery fb483d56a7 docs($sce): ng-bind-html takes an expression {{}} 2013-11-10 23:27:13 +00:00
Pete Bacon Darwin c5c75386e4 docs(guide/migration): fix internal link 2013-11-10 00:09:25 +00:00
Caitlin Potter 2734b9f560 chore(package.json): revert to marked@0.2.9 to fix CI builds
The marked npm library brought in a breaking change at 0.2.10.
This commit ensures that we get exactly the version we want.

Closes #4822
2013-11-09 23:16:11 +00:00
Pete Bacon Darwin dcdbcaf2b5 chore(release): update version number for next round of development 2013-11-08 21:26:49 +00:00
Pete Bacon Darwin 9a8179d311 docs(guide/migration): fix up internal links 2013-11-08 21:25:48 +00:00
Brian Ford 44fe7b6dbb docs(guide/migration): fix link to #2500 2013-11-08 12:54:06 -08:00
Brian Ford 95102a5afe chore(docs): allow periods in doc shortNames 2013-11-08 12:22:21 -08:00
Brian Ford ae2cdeb2de docs(guide/migration): add migration guide 2013-11-08 12:21:34 -08:00
Brian Ford 6a0aff84c4 docs(changelog): release notes for 1.2.0 2013-11-08 12:02:37 -08:00
Igor Minar e4181182dd chore(release): update cdn version 2013-11-08 11:32:51 -08:00
Igor Minar 907f71597a chore(release): cut the v1.2.0 timely-delivery release 2013-11-08 09:40:09 -08:00
Pete Bacon Darwin aea76f0d5c fix(animateSpec): run digest to enable animations before tests 2013-11-08 01:03:18 -08:00
Pete Bacon Darwin ffa9d0a6db fix(ngClassSpec): clear animation enable fn from postDigestQueue 2013-11-08 01:03:17 -08:00
Pete Bacon Darwin 9d00458563 fix(ngScenario): correctly disable animations for end 2 end tests 2013-11-08 01:03:17 -08:00
Igor Minar 98adc9e038 fix($animate): don't force animations to be enabled
The way that enabling of animations was set up, made it impossible to inject a
module into the bootstrap to disable animations for things like end 2 end tests.
Now animations are temporarily blocked by setting the animation state to RUNNING
during bootstrap, which allows the developer to permanently disable at any point
by calling $animate.enabled(false).
2013-11-08 01:03:17 -08:00
Igor Minar 5cfacec499 refactor($animate): speed up animationsDisabled check 2013-11-08 01:03:17 -08:00
Igor Minar 1df3da361d fix(bootstrap-prettify): share $animate and $$postDigestQueue with demo apps
Although demo apps run in an isolated environment, we need to be able to tell them to disable
animations when we are running end-to-end tests.  By sharing the same instance of $animate
between the two environments we can disable animation across the board.

The $animate service uses the $$postDigestQueue to run animations.  The outer $animate
service uses the outer $$postDigestQueue and to queue up these animations.  This means that
when we run a digest inside the embedded scope, the animations are never performed - they
just sit in the outer scope's queue and are only run when a digest is run on the outer scope.
By sharing this queue across the two scopes the animations are performed correctly.
2013-11-08 01:03:17 -08:00
Igor Minar 27e9340b3c feat(jqLite): expose isolateScope() getter similar to scope()
See doc update in the diff for more info.

BREAKING CHANGE: jqLite#scope() does not return the isolate scope on the element
that triggered directive with isolate scope. Use jqLite#isolateScope() instead.
2013-11-07 22:08:22 -08:00
Igor Minar b5af198f0d fix($compile): don't leak isolate scope state when replaced directive is used multiple times
When an isolate scope directive is also a "replace" directive and at the root of its template
it has other directives, we need to keep track remember to use isolate scope when linking
these.

This commit fixes the leakage of this state when this directive is used again later inside
or outside of the isolate directive template.
2013-11-07 22:08:05 -08:00
Igor Minar 3fe4491a6b fix($compile): correct isolate scope distribution to controllers
Fixes an issue when we didn't share the isolate scope with the controller
of the directive from the isolate directive's template when this directive
was replaced onto the isolate directive element.
2013-11-07 22:08:05 -08:00
Misko Hevery 97c7a4e379 fix($compile): replaced element has isolate scope 2013-11-07 22:08:05 -08:00
Vojta Jina d0efd5eefc fix($compile): only pass isolate scope to children that belong to the isolate directive
I had to fix one unit test, as it assumed the broken behavior, where application template gets the
isolate scope of other (isolate) directive, rather than the regular scope.

BREAKING CHANGE: Child elements that are defined either in the application template or in some other
directives template do not get the isolate scope. In theory, nobody should rely on this behavior, as
it is very rare - in most cases the isolate directive has a template.
2013-11-07 22:08:04 -08:00
Vojta Jina 909cabd36d fix($compile): make isolate scope truly isolate
Fixes issue with isolate scope leaking all over the place into other directives on the same element.

Isolate scope is now available only to the isolate directive that requested it and its template.

A non-isolate directive should not get the isolate scope of an isolate directive on the same element,
instead they will receive the original scope (which is the parent scope of the newly created isolate scope).

Paired with Tobias.

BREAKING CHANGE: Directives without isolate scope do not get the isolate scope from an isolate directive on the same element. If your code depends on this behavior (non-isolate directive needs to access state from within the isolate scope), change the isolate directive to use scope locals to pass these explicitly.

// before
<input ng-model="$parent.value" ng-isolate>

.directive('ngIsolate', function() {
  return {
    scope: {},
    template: '{{value}}'
  };
});

// after
<input ng-model="value" ng-isolate>

.directive('ngIsolate', function() {
  return {
    scope: {value: '=ngModel'},
    template: '{{value}}
  };
});

Closes #1924
Closes #2500
2013-11-07 22:03:19 -08:00
Tobias Bosch 3662140201 docs(guide/filter): Refactor filter guide docs
This refactors the filter guide docs into a single file.
Also removes out of date references to the fact that Angular used to enhance Arrays while evaluating expressions.
2013-11-07 14:14:57 -08:00
Brad Green ed8640b964 docs(guide): delete ancient video
We have links to better videos now on the guide/index page.  This one's time has past.
2013-11-06 20:51:39 -08:00
Matias Niemelä 8a5daaed42 chore(docs): add -webkit-transition for ngClass example 2013-11-06 20:29:03 -05:00
Tobias Bosch fc060dfc08 docs(guide/overview): Refactor overview and mvc docs
Before, there we multiple overview docs:
- guide/overview
- guide/introduction
- guide/dev_guide.mvc
- guide/dev_guide.mvc.understanding_model
- guide/dev_guide.mvc.understanding_view
- guide/concepts

Now we have:
- guide/introduction: High level description of Angular with the key benefits but without code or any concrete concepts
- guide/concepts: explains all important concepts with a simple example and contains deep links to the other parts of the guide.

 All the old information was moved into existing documents or deleted when they were duplicates.
2013-11-06 17:11:44 -08:00
Matias Niemelä 947a44d1ee chore(docs): specify how ngClass deals with natural CSS transitions 2013-11-06 18:11:59 -05:00
Jeff Cross eb51b024c9 fix(docModuleComponents): implement anchor scroll when content added
When navigating to URLs such as
docs.angularjs.org/api/ng#filter, the browser
was not able to navigate to the named anchor,
"filter," because the anchor did not yet exist
in the DOM.

This fix uses the $anchorScroll service
to automatically scroll to the right place when
the content has been added to the page.

Fixes #4703
2013-11-06 10:24:22 -08:00
Brian Ford 56d0917799 docs(guide/directive): link to directives API from the top of the page 2013-11-06 09:50:56 -08:00
Brian Ford c1260716de chore(ngdoc): add dynamic anchors to anchor list
Fixes some warnings during docs generation.

Closes #4673
2013-11-06 09:32:09 -08:00
Brian Ford 5614fd283a docs(guide/providers): add providers documentation 2013-11-06 08:47:06 -08:00
Jeff Cross da344daa40 fix(ngView): only run anchorScroll after animation is done 2013-11-06 00:14:11 -08:00
Jeff Cross 6fb191570e fix(ngMock): throw more descriptive errors for $animate.flushNext() 2013-11-06 00:14:11 -08:00
Pete Bacon Darwin d378f5500a fix(ngInclude): only run anchorScroll after animation is done
We need to wait until animations have added the content to the document before
trying to `autoscroll` to anchors that may have been inserted.

Fixes #4723
2013-11-06 00:14:11 -08:00
Matias Niemelä 9470080762 fix($animate): only apply the fallback property if any transition animations are detected 2013-11-06 02:01:19 -05:00
Matias Niemelä aba0fe6830 chore(docs): refactor/improve new CSS transition code in examples 2013-11-05 21:21:18 -08:00
Matias Niemelä b1d4d580e5 chore(docs): update $animate and ngAnimate docs 2013-11-05 21:21:17 -08:00
Matias Niemelä 9d69a0a7c7 feat($animate): ensure CSS transitions can work with inherited CSS class definitions
BREAKING CHANGE

ngAnimate addClass / removeClass animations are now applied right away. This means
that as soon as the animation starts the class will be added (addClass) or removed
(removeClass) to the element being animated instead of after the -add-active /
-remove-active animations are completed. This allows for animations outside of
ngAnimate to not conflict with $animate.

This commit introduces beforeAddClass and beforeRemoveClass animation event functions and
executes any addClass and removeClass event functions AFTER the class has been added or
removed (this is opposite functionality of how ngAnimate used to work when performing
JS-enabled animations addClass / removeClass animations). If your animation code relies on
any animations being performed prior to the class change then simply use the new
beforeAddClass and beforeRemoveClass animation event functions.

Finally, when animating show and hide animations using CSS transitions or keyframe animations,
ng-hide-remove doesn't require `display:block!important` for ng-hide-add anymore.
2013-11-05 21:15:59 -08:00
Matias Niemelä 7d2d2575a2 chore(animateSpec): provide meaningful CSS class names in animation tests 2013-11-05 21:46:07 -05:00
Matias Niemelä b89584db10 fix($animate): avoid hanging animations if the active CSS transition class is missing
Closes #4732
Closes #4490
2013-11-05 21:45:36 -05:00
Matias Niemelä 41a2d5b30f fix($animate): ensure staggering animations understand multiple delay values 2013-11-05 21:44:25 -05:00
Matias Niemelä e53ff431e1 fix($animate): ensure the active class is not applied if cancelled during reflow
Closes #4699
2013-11-05 21:44:02 -05:00
Matias Niemelä 974b6d4a5b chore($sniffer): make msie variable public
The msie variable is a global variable used within the ng core which contains the
version number for the current Internet Explorer browser that is rendering the
application. Other modules outside of the ng core could make use of this variable
instead of having to rollout duplicate detection code. This code makes it easy to
reuse this simple property within the $sniffer service.
2013-11-05 21:43:31 -05:00
Matias Niemelä 952fea69fb chore(ngAnimate): ensure elapsedTime values are in seconds and millseconds 2013-11-05 21:42:42 -05:00
Pete Bacon Darwin 0fca288224 chore(grunt): add test:docsgen to ci checks 2013-11-05 21:22:04 +00:00
Pete Bacon Darwin d4493fda2c fix(ngdocs): create mock Doc objects correctly 2013-11-05 21:20:46 +00:00
Pete Bacon Darwin 4c8fa35324 fix(ngdocs): shortDescription() should not error if no description 2013-11-05 21:16:52 +00:00
Michal Bendowski e196413df6 docs(guide/directive): fix transclusion example
The example about transclusion and scopes worked only because the order of `scope` and `element`
arguments is wrong, which means that the `name' property of the scope is not really being updated.
To really work, the directive has to define its own scope, either a new child scope or, as is more
common with transclusion, an isolated scope.

Closes #4774
2013-11-05 13:38:09 +00:00
G Lormeau 727b232fb2 docs(guide): add SEO4Ajax to the SEO tools list
Closes #4748
2013-11-04 22:34:11 +00:00
Tim Graham 6dcdb4e306 docs(input): fix typo
Closes #4734
2013-11-04 22:31:51 +00:00
Dmitry Kichenko 8cfaeb0e82 docs($http): note that default $http headers can be overridden
Closes #4750
2013-11-04 22:28:34 +00:00
joshbowdoin 159a63f538 docs(guide/understanding-controllers): fix typo in example
Broken - $scope.spicy = 'very';
Works - $scope.spice = 'very';

Closes #4752
2013-11-04 22:24:18 +00:00
Jesse Palmer 5b1c972723 docs(overview): improve readability
Inserted a couple of line breaks to increase readability.

Closes #4756
2013-11-04 22:23:02 +00:00
granteagon c82058ad57 docs($log): add the word "safely" to clarify
I was reading the doc and had to read the code to be sure it was safe.  Spelling it out seems easier.

Closes #4760
2013-11-04 22:21:49 +00:00
Brian Ford a92b419551 chore(docs): fix ordering of docs in the guide 2013-11-04 11:43:41 -08:00
Igor Minar 8f989d652f fix(ngModel): deregister from the form on scope not DOM destruction
Due to animations, DOM might get destroyed much later than scope and so the element $destroy event
might get fired outside of $digest, which causes changes to the validation model go unobserved
until the next digest. By deregistering on scope  event, the deregistration always happens
in $digest and the form validation model changes will be observed.

Closes #4226
Closes #4779
2013-11-04 10:35:51 -08:00
Igor Minar 9483373c33 fix(ngIf): destroy child scope when destroying DOM 2013-11-04 10:35:51 -08:00
Igor Minar c6923d2df4 style: remove ws 2013-11-04 10:35:51 -08:00
Brian Ford de2cced192 docs(guide/contribute): remove redundancy and link to CONTRIBUTING.md 2013-11-04 10:35:21 -08:00
Jordan Klassen 84166029ec docs($parse): Fix typo 2013-11-04 09:59:31 -08:00
Freek Wielstra 8d4e3fdd31 docs($location): update paramValue description for search()
search() supports an array for paramValue, but this is not described in the docs.
2013-11-02 21:40:15 -07:00
Tobias Bosch 9a828738cd fix(ngEventDirectives): parse expression only once during compile phase. 2013-10-31 12:56:49 -07:00
Chirayu Krishnappa 3d6a89e888 feat($parse): secure expressions by hiding "private" properties
BREAKING CHANGE:
This commit introduces the notion of "private" properties (properties
whose names begin and/or end with an underscore) on the scope chain.
These properties will not be available to Angular expressions (i.e. {{
}} interpolation in templates and strings passed to `$parse`)  They are
freely available to JavaScript code (as before).

Motivation
----------
Angular expressions execute in a limited context.  They do not have
direct access to the global scope, Window, Document or the Function
constructor.  However, they have direct access to names/properties on
the scope chain.  It has been a long standing best practice to keep
sensitive APIs outside of the scope chain (in a closure or your
controller.)  That's easier said that done for two reasons: (1)
JavaScript does not have a notion of private properties so if you need
someone on the scope chain for JavaScript use, you also expose it to
Angular expressions, and (2) the new "controller as" syntax that's now
in increased usage exposes the entire controller on the scope chain
greatly increaing the exposed surface.  Though Angular expressions are
written and controlled by the developer, they (1) typically deal with
user input and (2) don't get the kind of test coverage that JavaScript
code would.  This commit provides a way, via a naming convention, to
allow publishing/restricting properties from controllers/scopes to
Angular expressions enabling one to only expose those properties that
are actually needed by the expressions.
2013-10-30 17:01:51 -07:00
Brian Ford 5b620653f6 chore($compile): remove special case for ngIf and ngRepeat 2013-10-30 16:21:02 -07:00
Brian Ford 6578bd0c82 chore: move getBlockElements to Angular.js 2013-10-30 16:21:02 -07:00
Brian Ford e19067c9bb fix(ngIf): ngIf removes elements dynamically added to it
When using ngIf with ngInclude on the same element, ngIf previously did not remove
elements added by ngInclude. Similarly, when using ngIfStart/End, ngIf will miss
elements added between the start/end markers added after ngIf is linked.

This commit changes the behavior of ngIf to add a comment node at the end of its
elements such that elements between the starting comment and this ending comment
are removed when ngIf's predicate does not hold.
2013-10-30 16:21:02 -07:00
Martin Probst 9d0a69772c feat(Angular.js): add externs file for Closure Compiler
This adds an (incomplete) externs file for use with the Closure Compiler. Users
can pass this as -extern to the compiler pass to get type checking and protect
their AngularJS use against property renaming in advanced compilation mode.
2013-10-30 15:15:03 -07:00
Pete Bacon Darwin 117de8e6e2 docs(api): fix broken links 2013-10-30 21:24:20 +00:00
Fred Sauer 2ae29b1ce3 docs(api): fix broken links
Closes #4705
2013-10-30 21:16:38 +00:00
Adam Bowen 89a67ca77c docs(guide/injecting-services): fix indentation in example
Closes #4714
2013-10-30 21:08:33 +00:00
Pete Bacon Darwin 627f9ba091 docs($route): split over-length line 2013-10-30 21:03:10 +00:00
Renan Ivo e53e2c2d58 docs(tutorial): add instructions to install karma plugins 2013-10-30 21:00:11 +00:00
Andrew Jackson 217feda041 docs($route): change example module name
The name of the example module is `ngView`, which might cause needless confusion.
Changed name to `ngViewExample`, which should make it clearer.

Closes #4702
2013-10-30 20:58:10 +00:00
El Juli 6e77f80827 docs(guide/e2e-testing): fix typo
Closes #4700
2013-10-30 20:56:38 +00:00
JoeLeCodeur d355b6c48e docs(api): improve grammar
Closes #4690
2013-10-30 20:55:43 +00:00
Pete Bacon Darwin a1c9a41639 docs(CONTRIBUTING.md): add more info for contributors
Closes #4636
2013-10-30 20:53:34 +00:00
andre 8a3aba7358 docs(guide/understanding_controller): correct grammar
Add the word "to" to improve grammar.

Closes #4698
2013-10-30 20:52:18 +00:00
Matias Niemelä d434eabec3 fix($animate): use direct DOM comparison when checking for $rootElement
Closes #4679
2013-10-28 22:47:47 -07:00
Matias Niemelä 7f0767acab fix($animate): ensure former nodes are fully cleaned up when a follow-up structural animation takes place
Closes #4435
2013-10-28 21:26:35 -07:00
Gabor Csizmadia 3d4c80cc3e docs(guide/directive): fix myDraggable for zoomed page
If you have zoomed into the page in your browser then the screen coordinate system no longer
matches the page coordinate system.  To ensure that dragged elements work correctly when zoomed
we should use pageX/pageY rather than screenX/screenY.

Closes #4687
2013-10-28 22:01:15 +00:00
Pete Bacon Darwin d3b38dda06 docs(guide): improve links to books
Nested bullet points don't appear very nicely so resorted to nested
heading for the Learning Resources and in particular Books sections.

Closes #4677
2013-10-28 21:27:30 +00:00
Christopher Hiller 32b3494aa1 docs(guide): add link to book 2013-10-28 21:27:29 +00:00
Pete Bacon Darwin cf54510b2c docs($provide): fix link to factory section 2013-10-28 21:27:28 +00:00
Matias Niemelä 6818542c69 fix($animate): ensure enable/disable animations work when the document node is used
Closes #4669
2013-10-28 14:26:07 -07:00
Matias Niemelä 7484830744 feat(ngAnimate): provide support for staggering animations with CSS 2013-10-28 15:00:47 -06:00
royling 29e40c1f1c docs(guide/compiler): fixed a typo
Closes #4674
2013-10-28 20:30:06 +00:00
Derek Hammer 6d23591c31 fix(angular-mocks): add inline dependency annotation
Annotation allows the angular-mocks to be minified, which sometimes happens with frameworks that
automatically process files before running tests.
Also, some developers have been using this library in code for their applications.
This is not recommended as the library is only designed to support testing and not production
applications.  If you are likely to want to use the code here in production you would be best
forking and maintaining your own version of the code as we will not guarantee that we won't
break the annotation of the code in the future.

Closes #4448
2013-10-28 19:45:00 +00:00
Igor Minar 18ae985c3a fix($compile): don't instantiate controllers twice for element transclude directives
This is a fix for regression introduced last week by faf5b980.

Closes #4654
2013-10-28 01:11:18 -07:00
Igor Minar 797c99eabe style(compileSpec): reorder and cleanup tests for $compile's transclusion feature 2013-10-28 01:11:17 -07:00
Pete Bacon Darwin f3e3a65e29 docs(tutorial/index): fix git clone URL
Closes #4536
2013-10-27 21:54:51 +00:00
Jarrett Harris c9a1df3ae9 docs($resource): fix typo
Closes #4670
2013-10-27 21:51:53 +00:00
netpoetica c36e73de03 docs(guide/e2e-testing): callout ngmodel vs attr
Add note that `input()` fn matches ng-model instead of HTML name attribute.
About five users on forums were snagged by this assumption:
http://docs.angularjs.org/guide/dev_guide.e2e-testing#comment-898079915

Closes #4655
2013-10-27 21:48:50 +00:00
Yuriy Bilogub 0429f6c7f5 docs(form): fix typo
Close #4671
2013-10-27 21:42:23 +00:00
Matias Niemelä 7c5e2511fd chore(ngdocs): improve the docs search placeholder text 2013-10-27 21:30:54 +00:00
Leif Halvard Silli 8e5e641c0e docs(guide/ie): fix typo
The escaping of the colon in the example CSS is incorrect.
Replace `ng\\:view {` with `ng\:view {`

Closes #4570
2013-10-27 21:27:49 +00:00
Valentyn Shybanov dfccdd5b86 docs($location): document $location's events
Closes #1569
Closes #4446
2013-10-26 20:20:42 +01:00
gabriel-tessier 2cdb588b86 docs(guide/unit-testing): fix typo
Closes #4601
2013-10-26 20:15:50 +01:00
Pete Bacon Darwin 0bbb9e6258 docs(error/compile/tplrt): split long lines 2013-10-26 20:14:08 +01:00
gdennie 81d5bc860d docs(error/compile/tplrt): clarify and grammar
Closes #4503
2013-10-26 20:14:08 +01:00
gdennie 9f2c8e935a Clarification stemming from my own issues
It is instructive to give literal examples that reflect common (my) experience of the problem. :)
2013-10-26 20:09:09 +01:00
Pete Bacon Darwin 256fcb6884 docs(guide/compiler): clarify wording
Closes #4668
2013-10-26 20:07:00 +01:00
douglascalhoun 9453c61093 docs(guide/compiler): fix typo
Closes #4667
2013-10-26 19:58:05 +01:00
Preston Marshall 8b74738568 docs(guide/e2e-testing): add note about Protractor replacement
Add a note to warn people starting new projects about Protractor replacing the
current ngScenario way of doing E2E testing.

Closes #4644
2013-10-26 19:50:43 +01:00
@supercobra 96da4c14a7 docs(api/index): improve grammar
Closes #4648
2013-10-26 19:49:14 +01:00
Joe Grund a4d3146ee9 docs(guide/directive): correct reference to myDir rather than ngBind
Closes #4647
2013-10-26 19:47:43 +01:00
George Bonner d1a285e5d3 docs(guide/overview): improve grammar and readability
Closes #4639
2013-10-26 19:43:35 +01:00
Andrew Stuart 3cfe9575e9 docs(guide/understanding_controller): apply a more intuitive metaphor
The BabyCtrl was a bit confusing and GrandChildCtrl seems to make more sense
with the whole "scope inheritance" concept.

Closes #4634
2013-10-26 19:36:53 +01:00
Sean Fahey 05bc53d34d docs(tutorial/step-11): add missing dependencies
Closes #4633
2013-10-26 19:33:16 +01:00
rjferguson21 28ab4b600a docs($q): promises are no longer automatically unwrapped, by default
Although it is still possible to turn this on, the feature is deprecated and it is
best to remove this mention completely here.

Closes #4632
2013-10-26 19:29:27 +01:00
Pete Bacon Darwin fca7bcaf43 docs(guide/directive): improve wording 2013-10-26 19:24:03 +01:00
thorn0 9f0d4085e7 docs(Angular.js): angular.equals calls itself recursively on objects
Closes #4622
2013-10-26 18:57:59 +01:00
mgechev af34a4a2c0 docs(http): add missing brace in the 2nd interceptors example
Closes #4621
2013-10-26 18:53:41 +01:00
Joey Organisak a1806bb460 docs(guide/directive): we are registering directives, not controllers
Closes #4615
2013-10-26 18:51:44 +01:00
David Bennett 31ebeeef7d docs(ngForm): ensure correct attribute name in usage example
Closes #4611
2013-10-26 18:18:53 +01:00
David Bennett e73bd40e85 docs(ngdoc.js): fix usage to display attributes as dash-case
Closes 4611
2013-10-26 18:17:54 +01:00
micole ab3a3bf07a docs(CONTRIBUTING.md): explain we cannot accept localization changes
Angular uses the I18N code from Closure library to generate its own localization
files. So there is no point submitting pull requests for these files, since
all changes would be lost when we next generate these files.

Closes #4610
2013-10-26 18:10:44 +01:00
Caio Cunha 0a84739776 docs($rootScope): added $eval locals parameter documentation
Added documentation for `locals` parameter of `$eval` method.
2013-10-25 23:53:15 -04:00
Igor Minar 79223eae50 fix($compile): attribute bindings should not break due to terminal directives
Recently we changed the priority of attribute interpolation directive to -100
to ensure that it executes early in the post linking phase. This causes issues
with when terminal directives are placed on elements with attribute bindings
because the terminal directive will usually have 0 or higher priority which
results in attr interpolation directive not being applied to the element.

To fix this issue I'm switching the priority back to 100 and making moving the
binding setup into the pre-linking function.

This means that:

- terminal directives with priority lower than 100 will not affect the attribute
  binding
- if a directive wants to add or alter bindings it can do so in the pre-linking
  phase, as long as the priority of this directive is more than 100
- all post-linking functions will execute after the attribute binding has been
  set up
- all pre-linking functions with directive priority lower than 100 will execute
  after the attribute bindings have been setup

BREAKING CHANGE: the attribute interpolation (binding) executes as a directive
with priority 100 and the binding is set up in the pre-linking phase. It used
to be that the priority was -100 in rc.2 (100 before rc.2) and that the binding
was setup in the post-linking phase.

Closes #4525
Closes #4528
Closes #4649
2013-10-25 14:19:58 -07:00
BrainCrumbz 9bf9c236cf docs(compile): fix typo in 'Attributes' description
Closes #4589
2013-10-25 22:16:35 +01:00
Artemy Tregubenko 28bf357553 docs(guide/bootstrap): fix typo
Closes #4578
2013-10-25 22:11:08 +01:00
Jesse Palmer 34b1ceb42e docs(tutorial/step-7): add doctype directive to example
Closes #4552
2013-10-25 22:09:38 +01:00
Balázs Suhajda 924abdae9f docs(ngIf): fix typo
Closes #4512
2013-10-25 22:06:37 +01:00
DanS c1e6afca11 docs(tutorial/step-2): add beforeEach to load module
The non-global controller test throws an error because the test does not
know about the module and so can not find the controller. This change
tells the test about the module so the test can find the controller.

Closes #4489
2013-10-25 22:03:10 +01:00
Arun Israel 280354c3f9 style(injectorSpec): fix typo in "it" description
Closes #4483
2013-10-25 21:52:46 +01:00
phamdt 4645c95702 docs(tutorial/step-5): fix wrong link to services guide
Closes #4477
2013-10-25 21:51:23 +01:00
Brad Green c47a366bc4 docs(guide): rewrite guide landing page
Change landing page to include a set of curated links with subject
headings as a guide through Angular's docs and other resources.

Closes #4470
2013-10-25 21:47:29 +01:00
Maarten Stolte bb1395b452 docs(guide/e2e-testing): remove superfluous block of text
The removed block is repeated from the unit-testing guide and appears
in an awkward place in this text.

Closes #4456
2013-10-25 21:46:32 +01:00
mmieszek e7177d3159 docs(guide/expression): fix duplicate key error in example
The example that demonstrates how to parse expressions can fail if you
pass in the same expression twice.  By using "track by $index" we can
fix this.

Closes #4472
2013-10-25 21:46:31 +01:00
Pete Bacon Darwin 3e79c9b098 chore(grunt): add jshint to the test task
It is very easy to let jshint failures slip into the master build if
the jshint task is not part of the standard local grunt tasks.
2013-10-24 23:26:37 +01:00
Sam Dornan e8a3569be6 docs(ngClass): fix typo
Closes #4471
2013-10-24 23:22:36 +01:00
Wesley Cho 459e85bfea docs(rootScope): add example of using a listener function for $watch
Closes #4451
2013-10-24 23:13:30 +01:00
Igor Minar 1ae34aac81 chore(validate-commit-msg.js): increase the max line limit for commit messages from 70 to 100 2013-10-24 15:09:30 -07:00
Pete Bacon Darwin 82dec9b81e style($route): fix line length 2013-10-24 22:36:40 +01:00
Matias Niemelä 76b628bcb3 fix($animate): skip unnecessary addClass/removeClass animations
Skip addClass animations if the element already contains the class that is being
added to element. Also skip removeClass animations if the element does not contain
the class that is being removed.

Closes #4401
Closes #2332
2013-10-24 17:35:57 -04:00
basarat 46d396df72 docs(ngModelController): $parent can help isolate scope directives 2013-10-24 22:26:39 +01:00
CloudDueling.com db9c6a3528 docs(error/multidir): improve the sentence fluency
Closes #4449
2013-10-24 22:21:27 +01:00
Josh Schumacher 3b046c9eaa docs($routeProvider): document route.resolve rejection
Add documentation that the $routeChangeError event is fired when a
route resolve promise is rejected

Closes #4447
2013-10-24 22:17:50 +01:00
wiebl 3c05e36e79 docs(select): fix typo
Closes #4433
2013-10-24 22:12:51 +01:00
Walter Higgins 88e35fa8d6 docs(tutorial/step_00): reword sentence to make sense
Closes #4429
2013-10-24 22:11:56 +01:00
Nicolas Brugneaux 93132b96bf docs(ngBindHtml): add example
Closes #4427
2013-10-24 22:11:56 +01:00
Igor Minar faf5b980da fix($compile): instantiate controlers when re-entering compilation
When we re-enter compilation either due to async directive templates or element transclude directive
we need to keep track of controllers to instantiate during linking.

This piece of info was missing when re-entering compilation and that's what this commit fixes.

I also reordered the properties in the previousCompileContext object.

Closes #4434
Closes #4616
2013-10-24 13:54:15 -07:00
Dave Peticolas e57d5b89ca docs(ngNonBindable): fix punctuation
Closes #4424
2013-10-24 21:08:42 +01:00
Pete Bacon Darwin e690eaae53 docs($provide): Fix typo
Closes #4420
2013-10-24 20:54:26 +01:00
G.H. Naylor d3930fdfd9 docs(modulerr): fix typo
Closes #4418
2013-10-24 20:51:32 +01:00
Josh McAdams 1c621bdf23 docs(tutorial/step-07): fix typo
Closes #4410
2013-10-24 20:43:32 +01:00
Tyler McGinnis bf29cbc53f docs(ngController): do not attach a controller twice
A common mistake for beginners is to attach a controller in both the
$routeProvider and also in the html document using the ng-controller
directive. This change highlights this, to help prevent developers from
doing so in the future.

Closes #4409
2013-10-24 20:42:02 +01:00
Matias Niemelä 261057db9b chore(ngdocs): ensure the docs menu changes when browsing a different section
Closes #4619
2013-10-24 09:27:45 -04:00
Dmitry Shirokov 4b653aeac1 fix(input): keep track of min/max attars on-the-fly
Now input[type=button] keeps track of both min and max attrs even if they change over time.
2013-10-24 09:19:55 -04:00
Matias Niemelä 269bc7e51f chore(docs): fix jsHint errors with long lines 2013-10-23 17:44:37 -04:00
Brian Ford e69c287293 docs(guide/directive,guide/compiler,): drastically improve 2013-10-23 14:17:27 -07:00
Matias Niemelä 32ab648c79 chore(ngMocks): shorten the length of the description line to avoid jsHint errors 2013-10-23 17:06:14 -04:00
Matias Niemelä a7e12b7959 feat(docs): provide index pages for each angular module 2013-10-23 17:00:12 -04:00
Matias Niemelä 3f568b22f9 fix(ngView): ensure the new view element is placed after the old view element
Closes #4362
2013-10-23 10:30:45 -07:00
Matias Niemelä 2623de1426 fix($animate): ensure animations work properly when the $rootElement is being animated
Closes #4397
Closes #4231
2013-10-23 07:26:41 -04:00
Matias Niemelä f5289fe84f fix($animate): only cancel class-based animations if the follow-up class contains CSS transition/keyframe animation code
Closes #4463
Closes #3784
2013-10-23 07:08:03 -04:00
Matias Niemelä 74912802c6 feat(ngdocs): add forward slash shortcut key for search bar 2013-10-22 21:23:59 -04:00
Matias Niemelä 6c20ec193f fix(ngdocs): remove the side search bar
BREAKING CHANGE

The side search bar on the docs page has been removed in favor of the
top search bar.
2013-10-22 21:23:59 -04:00
Vojta Jina 06557aab44 chore(travis): run jshint task on Travis 2013-10-22 15:32:41 -07:00
Vojta Jina f2fab49830 style: make jshint happy 2013-10-22 15:32:41 -07:00
Pete Bacon Darwin 934a95d3ef chore(grunt): add jshint tasks 2013-10-22 15:32:40 -07:00
Igor Minar 2d8d6dd192 chore(Grunt): use the latest Content-Security-Policy header in csp mode 2013-10-22 15:21:24 -07:00
tigbro a86cf20e67 fix: don't inline css in csp mode.
Also add `angular-csp.css` to the resulting build.
2013-10-22 15:21:23 -07:00
Grzegorz Lachowski b9557b0a86 fix(ngAnimate): fix cancelChildAnimations throwing exception
fix ngAnimate throwing exception in cancelChildAnimations on deletion of
element (ngAnimate's leave decorator) of repeated element when using
ng-include on this element.

Closes #4548
2013-10-22 15:09:52 -04:00
Igor Minar 280e33d22a docs(ngCsp): pretty-format docs 2013-10-21 17:39:05 -07:00
Daniel Lamb 3661bab202 revert(validate-commit-msg): fix incorrect comment
Revert 581ec6be7d since it was not valid.

Closes #3952
2013-10-21 16:26:05 +01:00
Igor Minar 08f376f2ea fix(csp): fix csp auto-detection and stylesheet injection
When we refactored , we broke the csp mode because the previous implementation
relied on the fact that it was ok to lazy initialize the .csp property, this
is not the case any more.

Besides, we need to know about csp mode during bootstrap and avoid injecting the
stylesheet when csp is active, so I refactored the code to fix both issues.

PR #4411 will follow up on this commit and add more improvements.

Closes #917
Closes #2963
Closes #4394
Closes #4444

BREAKING CHANGE: triggering ngCsp directive via `ng:csp` attribute is not
supported any more. Please use data-ng-csp instead.
2013-10-18 17:33:53 -07:00
Vojta Jina 14438058da docs: correct broken links
This also contains some whitespace corrections by my editor.
2013-10-18 15:35:41 -07:00
Vojta Jina e8cc85f733 chore(docs): generate header ids for better linking
- generate ids for all headers
- collect defined anchors
- check broken links (even if the page exists, but the anchor/id does not)
2013-10-18 15:35:41 -07:00
Vojta Jina c22adbf160 fix($injector): allow a constructor function to return a function
This change makes `$injector.instantiate` (and thus `$provide.service`) to behave the same as native
`new` operator.
2013-10-18 15:26:51 -07:00
Igor Minar dba566a96d docs($rootScope): better document infinite digest and ttl 2013-10-15 11:28:47 -07:00
Chirayu Krishnappa 6d324c76f0 fix($parse): check function call context to be safe
Closes #4417
2013-10-15 06:43:19 -07:00
Igor Minar 3aefd3a4f0 chore(release): start 1.2.0 iteration 2013-10-15 06:24:37 -07:00
Igor Minar ff923a5d45 docs(changelog): release notes for 1.2.0-rc.3 2013-10-15 06:12:43 -07:00
475 changed files with 21453 additions and 10644 deletions
+1
View File
@@ -17,3 +17,4 @@ angular.xcodeproj
libpeerconnection.log
npm-debug.log
/tmp/
/scripts/bower/bower-*
+3 -1
View File
@@ -7,6 +7,8 @@ env:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
- BROWSER_STACK_USERNAME=VojtaJina
- BROWSER_STACK_ACCESS_KEY=HAfHZaypxAc3PEUrUU9a
- LOGS_DIR=/tmp/angular-build/logs
before_script:
@@ -16,10 +18,10 @@ before_script:
- grunt bower
- grunt bower
- grunt package-without-bower
- grunt ci-checks
- ./lib/sauce/sauce_connect_block.sh
script:
- grunt ci-checks
- ./travis_build.sh
after_script:
+734
View File
@@ -1,3 +1,737 @@
<a name="1.2.4"></a>
# 1.2.4 wormhole-blaster (2013-12-06)
## Bug Fixes
- **$animate:**
- ensure animations work with directives that share a transclusion
([958d3d56](https://github.com/angular/angular.js/commit/958d3d56b1899a2cfc7b18c0292e5a1d8c64d0a5),
[#4716](https://github.com/angular/angular.js/issues/4716), [#4871](https://github.com/angular/angular.js/issues/4871), [#5021](https://github.com/angular/angular.js/issues/5021), [#5278](https://github.com/angular/angular.js/issues/5278))
- ensure ms durations are properly rounded
([93901bdd](https://github.com/angular/angular.js/commit/93901bdde4bb9f0ba114ebb33b8885808e1823e1),
[#5113](https://github.com/angular/angular.js/issues/5113), [#5162](https://github.com/angular/angular.js/issues/5162))
- **$compile:**
- update cloned elements if the template arrives after the cloning
([b0972a2e](https://github.com/angular/angular.js/commit/b0972a2e75909e41dbac6e4413ada7df2d51df3a))
- ensure the isolated local watch `lastValue` is always in sync
([2d0f6ccb](https://github.com/angular/angular.js/commit/2d0f6ccba896fe34141d6d4f59eef6fba580c5c2),
[#5182](https://github.com/angular/angular.js/issues/5182))
- **$rootScope:**
- ensure that when the $destroy event is broadcast on $rootScope that it does something
([d802ed1b](https://github.com/angular/angular.js/commit/d802ed1b3680cfc1751777fac465b92ee29944dc),
[#5169](https://github.com/angular/angular.js/issues/5169))
- ensure the phase is cleared within a digest if an exception is raised by a watcher
([d3c486dd](https://github.com/angular/angular.js/commit/d3c486dd6dfa8d5dca32a3e28aa685fb7260c878))
- **$sanitize:** don't rely on YARR regex engine executing immediately in order to prevent object mutation
([81b81856](https://github.com/angular/angular.js/commit/81b81856ee43d2876927c4e1f774affa87e99707),
[#5193](https://github.com/angular/angular.js/issues/5193), [#5192](https://github.com/angular/angular.js/issues/5192))
- **closure:** closure compiler shouldn't rename .defaults.transformRequest
([f01087f8](https://github.com/angular/angular.js/commit/f01087f802839637843115cbcf99702e09d866f6))
- **input:** ensure ngModelWatch() triggers second digest pass when appropriate
([b6d54393](https://github.com/angular/angular.js/commit/b6d5439343b9801f7f2a009d0de09cba9aa21a1d),
[#5258](https://github.com/angular/angular.js/issues/5258), [#5282](https://github.com/angular/angular.js/issues/5282))
- **isElement:** return boolean value rather than `truthy` value.
([2dbb6f9a](https://github.com/angular/angular.js/commit/2dbb6f9a54eb5ff5847eed11c85ac4cf119eb41c),
[#4519](https://github.com/angular/angular.js/issues/4519), [#4534](https://github.com/angular/angular.js/issues/4534))
- **jqLite:** ignore incompatible nodes on find()
([1169b544](https://github.com/angular/angular.js/commit/1169b5445691e1495354d235a3badf05240e3904),
[#4120](https://github.com/angular/angular.js/issues/4120))
- **ngInit:** evaluate ngInit before ngInclude
([0e50810c](https://github.com/angular/angular.js/commit/0e50810c53428f4c1f5bfdba9599df54cb7a6c6e),
[#5167](https://github.com/angular/angular.js/issues/5167), [#5208](https://github.com/angular/angular.js/issues/5208))
- **ngSanitize:** prefer textContent to innerText to avoid layout trashing
([bf1972dc](https://github.com/angular/angular.js/commit/bf1972dc1e8ffbeaddfa53df1d49bc5a2177f09c))
## Performance Improvements
- **$parse:** micro-optimization for ensureSafeObject function
([689dfb16](https://github.com/angular/angular.js/commit/689dfb167924a61aef444ce7587fb987d8080990),
[#5246](https://github.com/angular/angular.js/issues/5246))
- **Scope:** short-circuit after dirty-checking last dirty watcher
([d070450c](https://github.com/angular/angular.js/commit/d070450cd2b3b3a3aa34b69d3fa1f4cc3be025dd),
[#5272](https://github.com/angular/angular.js/issues/5272), [#5287](https://github.com/angular/angular.js/issues/5287))
<a name="1.2.3"></a>
# 1.2.3 unicorn-zapper (2013-11-27)
## Bug Fixes
- **$animate:**
- ensure blocked keyframe animations are unblocked before the DOM operation
([2efe8230](https://github.com/angular/angular.js/commit/2efe82309ac8ff4f67df8b6e40a539ea31e15804),
[#5106](https://github.com/angular/angular.js/issues/5106))
- ensure animations are disabled during bootstrap to prevent unwanted structural animations
([eed23332](https://github.com/angular/angular.js/commit/eed2333298412fbad04eda97ded3487c845b9eb9),
[#5130](https://github.com/angular/angular.js/issues/5130))
- **$sanitize:** use the same whitelist mechanism as `$compile` does
([33352348](https://github.com/angular/angular.js/commit/333523483f3ce6dd3177b697a5e5a7177ca364c8),
[#3748](https://github.com/angular/angular.js/issues/3748))
- **input:** react to form auto completion, through the `change` event, on modern browsers
([a090400f](https://github.com/angular/angular.js/commit/a090400f09d7993d102f527609879cdc74abae60),
[#1460](https://github.com/angular/angular.js/issues/1460))
- **$attrs:** add `$attrs.$attr` to externs so that it isn't renamed on js minification
([bcca8054](https://github.com/angular/angular.js/commit/bcca80548dde85ffe3838c943ba8e5c2deb1c721))
## Features
No new features in this release
## Breaking Changes
There are no breaking changes in this release (promise!)
<a name="1.2.2"></a>
# 1.2.2 consciousness-inertia (2013-11-22)
## Bug Fixes
- **$animate:**
- ensure keyframe animations are blocked around the reflow
([6760d7a3](https://github.com/angular/angular.js/commit/6760d7a315d7ea5cbd4f8ab74b200f754a2041f4),
[#5018](https://github.com/angular/angular.js/issues/5018))
- ensure transition animations are unblocked before the dom operation occurs
([062fbed8](https://github.com/angular/angular.js/commit/062fbed8fc3f7bc55433f8c6915c27520e6f63c5),
[#5014](https://github.com/angular/angular.js/issues/5014),
[#4265](https://github.com/angular/angular.js/issues/4265))
- ensure addClass/removeClass animations do not snap during reflow
([76e4db6f](https://github.com/angular/angular.js/commit/76e4db6f3d15199ac1fbe85f9cfa6079a1c4fa56),
[#4892](https://github.com/angular/angular.js/issues/4892))
- ensure the DOM operation isn't run twice
([7067a8fb](https://github.com/angular/angular.js/commit/7067a8fb0b18d5b5489006e1960cee721a88b4d2),
[#4949](https://github.com/angular/angular.js/issues/4949))
- **$compile:**
- secure form[action] & iframe[srcdoc]
([0421cb42](https://github.com/angular/angular.js/commit/0421cb4200e672818ed10996e92311404c150c3a),
[#4927](https://github.com/angular/angular.js/issues/4927),
[#4933](https://github.com/angular/angular.js/issues/4933))
- ensure CSS classes are added and removed only when necessary
([0cd7e8f2](https://github.com/angular/angular.js/commit/0cd7e8f22721f62b62440bb059ae764ebbe7b42a))
- **$httpBackend:** only IE8 and below can't use `script.onload` for JSONP
([a3172a28](https://github.com/angular/angular.js/commit/a3172a285fd74b5aa6c8d68a4988c767c06f549c),
[#4523](https://github.com/angular/angular.js/issues/4523),
[#4527](https://github.com/angular/angular.js/issues/4527),
[#4922](https://github.com/angular/angular.js/issues/4922))
- **$parse:** allow for new lines in expr when promise unwrapping is on
([40647b17](https://github.com/angular/angular.js/commit/40647b179c473f3f470bb1b3237d6f006269582f),
[#4718](https://github.com/angular/angular.js/issues/4718))
- **$resource:** Always return a resource instance when calling class methods on resources.
([f6ecf9a3](https://github.com/angular/angular.js/commit/f6ecf9a3c9090593faf5fa50586c99a56b51c776),
[#4545](https://github.com/angular/angular.js/issues/4545),
[#5061](https://github.com/angular/angular.js/issues/5061))
- **httpBackend:** should not read response data when request is aborted
([6f1050df](https://github.com/angular/angular.js/commit/6f1050df4fa885bd59ce85adbef7350ea93911a3),
[#4913](https://github.com/angular/angular.js/issues/4913),
[#4940](https://github.com/angular/angular.js/issues/4940))
- **loader:** expose `$$minErr` to modules such as`ngResource`
([9e89a31b](https://github.com/angular/angular.js/commit/9e89a31b129e40c805178535c244899ffafb77d8),
[#5050](https://github.com/angular/angular.js/issues/5050))
- **ngAnimate:**
- correctly retain and restore existing styles during and after animation
([c42d0a04](https://github.com/angular/angular.js/commit/c42d0a041890b39fc98afd357ec1307a3a36208d),
[#4869](https://github.com/angular/angular.js/issues/4869))
- use a fallback CSS property that doesn't break existing styles
([1d50663b](https://github.com/angular/angular.js/commit/1d50663b38ba042e8d748ffa6d48cfb5e93cfd7e),
[#4902](https://github.com/angular/angular.js/issues/4902),
[#5030](https://github.com/angular/angular.js/issues/5030))
- **ngClass:** ensure that ngClass only adds/removes the changed classes
([6b8bbe4d](https://github.com/angular/angular.js/commit/6b8bbe4d90640542eed5607a8c91f6b977b1d6c0),
[#4960](https://github.com/angular/angular.js/issues/4960),
[#4944](https://github.com/angular/angular.js/issues/4944))
- **ngController:** fix issue with ngInclude on the same element
([6288cf5c](https://github.com/angular/angular.js/commit/6288cf5ca471b0615a026fdb4db3ba242c9d8f88),
[#4431](https://github.com/angular/angular.js/issues/4431))
- **ngInclude:**
- Don't throw when the ngInclude element contains content with directives.
([0a7cbb33](https://github.com/angular/angular.js/commit/0a7cbb33b06778833a4d99b1868cc07690a827a7))
- allow ngInclude to load scripts when jQuery is included
([c47abd0d](https://github.com/angular/angular.js/commit/c47abd0dd7490576f4b84ee51ebaca385c1036da),
[#3756](https://github.com/angular/angular.js/issues/3756))
- **ngMock:** fixes httpBackend expectation with body object
([4d16472b](https://github.com/angular/angular.js/commit/4d16472b918a3482942d76f1e273a5aa01f65e83),
[#4956](https://github.com/angular/angular.js/issues/4956))
- **ngView:** Don't throw when the ngView element contains content with directives.
([e6521e74](https://github.com/angular/angular.js/commit/e6521e7491242504250b57dd0ee66af49e653c33),
[#5069](https://github.com/angular/angular.js/issues/5069))
- **tests:** Correct tests for IE11
([57924234](https://github.com/angular/angular.js/commit/579242346c4202ea58fc2cae6df232289cbea0bb),
[#5046](https://github.com/angular/angular.js/issues/5046))
- **input:** hold listener during text composition
([a4e6d962](https://github.com/angular/angular.js/commit/a4e6d962d78b26f5112d48c4f88c1e6234d0cae7),
[#4684](https://github.com/angular/angular.js/issues/4684))
<a name="1.2.1"></a>
# 1.2.1 underscore-empathy (2013-11-14)
## Bug Fixes
- **$compile:**
- accessing controllers of transcluded directives from children
([90f87072](https://github.com/angular/angular.js/commit/90f87072e83234ae366cfeb3c281503c31dad738),
[#4935](https://github.com/angular/angular.js/issues/4935))
- correctly handle interpolated style in replace templates
([e1254b26](https://github.com/angular/angular.js/commit/e1254b266dfa2d4e3756e4317152dbdbcabe44be),
[#4882](https://github.com/angular/angular.js/issues/4882))
- **$resource:** don't use $parse for @dotted.member
([9577702e](https://github.com/angular/angular.js/commit/9577702e8d2519c1a60f5ac4058e63bd7b919815))
- **bootstrap:** make IE8 happy
([a61b65d0](https://github.com/angular/angular.js/commit/a61b65d01b468502fe53d68818949d3fcc9f20f6))
- **loader:** don't rely on internal APIs
([8425e9fe](https://github.com/angular/angular.js/commit/8425e9fe383c17f6a5589c778658c5fc0570ae8f),
[#4437](https://github.com/angular/angular.js/issues/4437), [#4874](https://github.com/angular/angular.js/issues/4874))
- **minErr:** remove references to internal APIs
([94764ee0](https://github.com/angular/angular.js/commit/94764ee08910726db1db7a1101c3001500306dea))
- **ngIf:** don't create multiple elements when changing from a truthy value to another thruthy value
([4612705e](https://github.com/angular/angular.js/commit/4612705ec297bc6ba714cb7a98f1be6aff77c4b8),
[#4852](https://github.com/angular/angular.js/issues/4852))
- **urlUtils:**
- make removal of windows drive from path safer
([89f435de](https://github.com/angular/angular.js/commit/89f435de847635e3ec339726e6f83cf3f0ee9091),
[#4939](https://github.com/angular/angular.js/issues/4939))
- return right path for file:// on windows
([f925e8ca](https://github.com/angular/angular.js/commit/f925e8caa6c51a7d45ca9ead30601ec2e9d4464c),
[#4680](https://github.com/angular/angular.js/issues/4680))
## Features
- **$parse:** revert hiding "private" properties
([4ab16aaa](https://github.com/angular/angular.js/commit/4ab16aaaf762e9038803da1f967ac8cb6650727d),
[#4926](https://github.com/angular/angular.js/issues/4926), [#4842](https://github.com/angular/angular.js/issues/4842), [#4865](https://github.com/angular/angular.js/issues/4865), [#4859](https://github.com/angular/angular.js/issues/4859), [#4849](https://github.com/angular/angular.js/issues/4849))
<a name="1.2.0"></a>
# 1.2.0 timely-delivery (2013-11-08)
## Features
- **animations:**
- ensure CSS transitions can work with inherited CSS class definitions
([9d69a0a7](https://github.com/angular/angular.js/commit/9d69a0a7c75c937c0a49bb705d31252326b052df))
- provide support for staggering animations with CSS
([74848307](https://github.com/angular/angular.js/commit/74848307443c00ab07552336c56ddfa1e9ef6eff))
- **$parse:** secure expressions by hiding "private" properties
([3d6a89e8](https://github.com/angular/angular.js/commit/3d6a89e8888b14ae5cb5640464e12b7811853c7e))
- **docs:**
- provide index pages for each angular module
([a7e12b79](https://github.com/angular/angular.js/commit/a7e12b7959212f2fa88fe17d5a045cc9d8b22922))
- add forward slash shortcut key for search bar
([74912802](https://github.com/angular/angular.js/commit/74912802c644ca929e39a7583cb7a9a05f12e91f))
- **jqLite:** expose isolateScope() getter similar to scope()
([27e9340b](https://github.com/angular/angular.js/commit/27e9340b3c25b512e45213b39811098d07e12e3b))
- **misc:** add externs file for Closure Compiler
([9d0a6977](https://github.com/angular/angular.js/commit/9d0a69772c39bfc751ca2000c3b4b3381e51fe93))
## Bug Fixes
- **$animate:**
- don't force animations to be enabled
([98adc9e0](https://github.com/angular/angular.js/commit/98adc9e0383dc05efad168f30a0725cb67f5eda8))
- only apply the fallback property if any transition animations are detected
([94700807](https://github.com/angular/angular.js/commit/9470080762aecca5285d0f5cac4ae01540bbad4c))
- avoid hanging animations if the active CSS transition class is missing
([b89584db](https://github.com/angular/angular.js/commit/b89584db10b63f346cbfd03f67fb92504e5bf362),
[#4732](https://github.com/angular/angular.js/issues/4732), [#4490](https://github.com/angular/angular.js/issues/4490))
- ensure staggering animations understand multiple delay values
([41a2d5b3](https://github.com/angular/angular.js/commit/41a2d5b30f4feb90651eb577cf44852a6d2be72c))
- ensure the active class is not applied if cancelled during reflow
([e53ff431](https://github.com/angular/angular.js/commit/e53ff431e1472c0b2d5405d267d4e403ca31087e),
[#4699](https://github.com/angular/angular.js/issues/4699))
- use direct DOM comparison when checking for $rootElement
([d434eabe](https://github.com/angular/angular.js/commit/d434eabec3955f8d56c859c93befe711bfa1de27),
[#4679](https://github.com/angular/angular.js/issues/4679))
- ensure former nodes are fully cleaned up when a follow-up structural animation takes place
([7f0767ac](https://github.com/angular/angular.js/commit/7f0767acaba1ec3c8849244a604b0d1c8c376446),
[#4435](https://github.com/angular/angular.js/issues/4435))
- ensure enable/disable animations work when the document node is used
([6818542c](https://github.com/angular/angular.js/commit/6818542c694aec6c811fb2fe2f86f7d16544c39b),
[#4669](https://github.com/angular/angular.js/issues/4669))
- skip unnecessary addClass/removeClass animations
([76b628bc](https://github.com/angular/angular.js/commit/76b628bcb3511210d312ed667e5c14d908a9fed1),
[#4401](https://github.com/angular/angular.js/issues/4401), [#2332](https://github.com/angular/angular.js/issues/2332))
- ensure animations work properly when the $rootElement is being animated
([2623de14](https://github.com/angular/angular.js/commit/2623de1426219dc799f63a3d155911f93fc03461),
[#4397](https://github.com/angular/angular.js/issues/4397), [#4231](https://github.com/angular/angular.js/issues/4231))
- only cancel class-based animations if the follow-up class contains CSS transition/keyframe animation code
([f5289fe8](https://github.com/angular/angular.js/commit/f5289fe84ffc1f2368dae7bd14c420abbe76749e),
[#4463](https://github.com/angular/angular.js/issues/4463), [#3784](https://github.com/angular/angular.js/issues/3784))
- **$compile:**
- don't leak isolate scope state when replaced directive is used multiple times
([b5af198f](https://github.com/angular/angular.js/commit/b5af198f0d5b0f2b3ddb31ea12f700f3e0616271))
- correct isolate scope distribution to controllers
([3fe4491a](https://github.com/angular/angular.js/commit/3fe4491a6bf57ddeb312b8a30cf1706f6f1d2355))
- replaced element has isolate scope
([97c7a4e3](https://github.com/angular/angular.js/commit/97c7a4e3791d7cb05c3317cc5f0c49ab93810bf6))
- only pass isolate scope to children that belong to the isolate directive
([d0efd5ee](https://github.com/angular/angular.js/commit/d0efd5eefcc0aaf167c766513e152b74dd31bafe))
- make isolate scope truly isolate
([909cabd3](https://github.com/angular/angular.js/commit/909cabd36d779598763cc358979ecd85bb40d4d7),
[#1924](https://github.com/angular/angular.js/issues/1924), [#2500](https://github.com/angular/angular.js/issues/2500))
- don't instantiate controllers twice for element transclude directives
([18ae985c](https://github.com/angular/angular.js/commit/18ae985c3a3147b589c22f6ec21bacad2f578e2b),
[#4654](https://github.com/angular/angular.js/issues/4654))
- attribute bindings should not break due to terminal directives
([79223eae](https://github.com/angular/angular.js/commit/79223eae5022838893342c42dacad5eca83fabe8),
[#4525](https://github.com/angular/angular.js/issues/4525), [#4528](https://github.com/angular/angular.js/issues/4528), [#4649](https://github.com/angular/angular.js/issues/4649))
- instantiate controlers when re-entering compilation
([faf5b980](https://github.com/angular/angular.js/commit/faf5b980da09da2b4c28f1feab33f87269f9f0ba),
[#4434](https://github.com/angular/angular.js/issues/4434), [#4616](https://github.com/angular/angular.js/issues/4616))
- **$injector:** allow a constructor function to return a function
([c22adbf1](https://github.com/angular/angular.js/commit/c22adbf160f32c1839fbb35382b7a8c6bcec2927))
- **$parse:** check function call context to be safe
([6d324c76](https://github.com/angular/angular.js/commit/6d324c76f0d3ad7dae69ce01b14e0564938fb15e),
[#4417](https://github.com/angular/angular.js/issues/4417))
- **angular-mocks:** add inline dependency annotation
([6d23591c](https://github.com/angular/angular.js/commit/6d23591c31f2b41097ceaa380af09998e4a62f09),
[#4448](https://github.com/angular/angular.js/issues/4448))
- **animateSpec:** run digest to enable animations before tests
([aea76f0d](https://github.com/angular/angular.js/commit/aea76f0d5c43dc17f1319d0a45d2ce50fddf72e4))
- **bootstrap-prettify:** share $animate and $$postDigestQueue with demo apps
([1df3da36](https://github.com/angular/angular.js/commit/1df3da361d62726bf1dafe629a7fca845b6a8733))
- **csp:**
- fix csp auto-detection and stylesheet injection
([08f376f2](https://github.com/angular/angular.js/commit/08f376f2ea3d3bb384f10e3c01f7d48ed21ce351),
[#917](https://github.com/angular/angular.js/issues/917), [#2963](https://github.com/angular/angular.js/issues/2963), [#4394](https://github.com/angular/angular.js/issues/4394), [#4444](https://github.com/angular/angular.js/issues/4444))
- don't inline css in csp mode
([a86cf20e](https://github.com/angular/angular.js/commit/a86cf20e67202d614bbcaf038c5e04db94483256)
- **docModuleComponents:** implement anchor scroll when content added
([eb51b024](https://github.com/angular/angular.js/commit/eb51b024c9b77527420014cdf7dbb292b5b9dd6b),
[#4703](https://github.com/angular/angular.js/issues/4703))
- **input:** keep track of min/max attars on-the-fly
([4b653aea](https://github.com/angular/angular.js/commit/4b653aeac1aca7ac551738870a2446b6810ca0df))
- **ngAnimate:** fix cancelChildAnimations throwing exception
([b9557b0a](https://github.com/angular/angular.js/commit/b9557b0a86206d938a738ea470736d011dff7e1a),
[#4548](https://github.com/angular/angular.js/issues/4548))
- **ngClassSpec:** clear animation enable fn from postDigestQueue
([ffa9d0a6](https://github.com/angular/angular.js/commit/ffa9d0a6db137cba4090e569b8ed4e25a711314e))
- **ngEventDirectives:** parse expression only once during compile phase.
([9a828738](https://github.com/angular/angular.js/commit/9a828738cd2e959bc2a198989e96c8e416d28b71))
- **ngIf:**
- destroy child scope when destroying DOM
([9483373c](https://github.com/angular/angular.js/commit/9483373c331343648e079420b3eb1f564d410ff2))
- ngIf removes elements dynamically added to it
([e19067c9](https://github.com/angular/angular.js/commit/e19067c9bbac3c3bb450c80f73eb5518bd0db1a1))
- **ngInclude:** only run anchorScroll after animation is done
([d378f550](https://github.com/angular/angular.js/commit/d378f5500ab2eef0779338336c6a95656505ebb8),
[#4723](https://github.com/angular/angular.js/issues/4723))
- **ngMock:** throw more descriptive errors for $animate.flushNext()
([6fb19157](https://github.com/angular/angular.js/commit/6fb191570ee72f087e8bb6b1d8f5eea0f585886c))
- **ngModel:** deregister from the form on scope not DOM destruction
([8f989d65](https://github.com/angular/angular.js/commit/8f989d652f70fd147f66a18411070c7b939e242e),
[#4226](https://github.com/angular/angular.js/issues/4226), [#4779](https://github.com/angular/angular.js/issues/4779))
- **ngScenario:** correctly disable animations for end 2 end tests
([9d004585](https://github.com/angular/angular.js/commit/9d0045856351e9db48ddf66f66e210d9cc53d24a))
- **ngView:**
- only run anchorScroll after animation is done
([da344daa](https://github.com/angular/angular.js/commit/da344daa4023556f8abbef6d8ad87a16362b5861))
- ensure the new view element is placed after the old view element
([3f568b22](https://github.com/angular/angular.js/commit/3f568b22f9bec09192588e3cae937db5c2e757f9),
[#4362](https://github.com/angular/angular.js/issues/4362))
- **ngdocs:**
- create mock Doc objects correctly
([d4493fda](https://github.com/angular/angular.js/commit/d4493fda2c4c2ff1fdfc264bfb479741abc781c7))
- `shortDescription()` should not error if no `description`
([4c8fa353](https://github.com/angular/angular.js/commit/4c8fa353245b9c32261860caff18f002d294e19f))
- remove the side search bar
([6c20ec19](https://github.com/angular/angular.js/commit/6c20ec193f11aa647be1b2ad2ac5b3e7c2894bd7))
## Breaking Changes
- **$compile:**
- due to [d0efd5ee](https://github.com/angular/angular.js/commit/d0efd5eefcc0aaf167c766513e152b74dd31bafe),
Child elements that are defined either in the application template or in some other
directives template do not get the isolate scope. In theory, nobody should rely on this behavior, as
it is very rare - in most cases the isolate directive has a template.
- due to [909cabd3](https://github.com/angular/angular.js/commit/909cabd36d779598763cc358979ecd85bb40d4d7),
Directives without isolate scope do not get the isolate scope from an isolate directive on the
same element. If your code depends on this behavior (non-isolate directive needs to access state
from within the isolate scope), change the isolate directive to use scope locals to pass these explicitly.
**Before**
```
<input ng-model="$parent.value" ng-isolate>
.directive('ngIsolate', function() {
return {
scope: {},
template: '{{value}}'
};
});
```
**After**
```
<input ng-model="value" ng-isolate>
.directive('ngIsolate', function() {
return {
scope: {value: '=ngModel'},
template: '{{value}}
};
});
```
Closes [#1924](https://github.com/angular/angular.js/issues/1924) and
[#2500](https://github.com/angular/angular.js/issues/2500)
- due to [79223eae](https://github.com/angular/angular.js/commit/79223eae5022838893342c42dacad5eca83fabe8),
Previously, the interpolation priority was `-100` in 1.2.0-rc.2, and `100` before 1.2.0-rc.2.
Before this change the binding was setup in the post-linking phase.
Now the attribute interpolation (binding) executes as a directive with priority 100 and the
binding is set up in the pre-linking phase.
Closes [#4525](https://github.com/angular/angular.js/issues/4525),
[#4528](https://github.com/angular/angular.js/issues/4528), and
[#4649](https://github.com/angular/angular.js/issues/4649)
- **$parse:** due to [3d6a89e8](https://github.com/angular/angular.js/commit/3d6a89e8888b14ae5cb5640464e12b7811853c7e),
This commit introduces the notion of "private" properties (properties
whose names begin and/or end with an underscore) on the scope chain.
These properties will not be available to Angular expressions (i.e. {{
}} interpolation in templates and strings passed to `$parse`) They are
freely available to JavaScript code (as before).
**Motivation**
Angular expressions execute in a limited context. They do not have
direct access to the global scope, `window`, `document` or the Function
constructor. However, they have direct access to names/properties on
the scope chain. It has been a long standing best practice to keep
sensitive APIs outside of the scope chain (in a closure or your
controller.) That's easier said that done for two reasons:
1. JavaScript does not have a notion of private properties so if you need
someone on the scope chain for JavaScript use, you also expose it to
Angular expressions
2. the new "controller as" syntax that's now in increased usage exposes the
entire controller on the scope chain greatly increaing the exposed surface.
Though Angular expressions are written and controlled by the developer, they:
1. Typically deal with user input
2. Don't get the kind of test coverage that JavaScript code would
This commit provides a way, via a naming convention, to
allow publishing/restricting properties from controllers/scopes to
Angular expressions enabling one to only expose those properties that
are actually needed by the expressions.
- **csp:** due to [08f376f2](https://github.com/angular/angular.js/commit/08f376f2ea3d3bb384f10e3c01f7d48ed21ce351),
triggering ngCsp directive via `ng:csp` attribute is not supported any more.
Please use `data-ng-csp` instead.
- **jqLite:** due to [27e9340b](https://github.com/angular/angular.js/commit/27e9340b3c25b512e45213b39811098d07e12e3b),
`jqLite.scope()` (connonly used through `angular.element(node).scope()`) does not return the
isolate scope on the element that triggered directive with isolate scope. Use
`jqLite.isolateScope()` instead.
<a name="1.2.0-rc.3"></a>
# 1.2.0-rc.3 ferocious-twitch (2013-10-14)
## Features
- **$interval:** add a service wrapping setInterval
([2b5ce84f](https://github.com/angular/angular.js/commit/2b5ce84fca7b41fca24707e163ec6af84bc12e83))
- **$sce:** simpler patterns for `$sceDelegateProviders` white/blacklists
([93ce5923](https://github.com/angular/angular.js/commit/93ce5923e92f6d2db831d8715ec62734821c70ce),
[#4006](https://github.com/angular/angular.js/issues/4006))
- **$filter:** allow map of filters to be registered
([4033cf28](https://github.com/angular/angular.js/commit/4033cf28142664c52aa7b4bc95340ac913397ac8),
[#4036](https://github.com/angular/angular.js/issues/4036),
[#4091](https://github.com/angular/angular.js/issues/4091))
- **$compile:** support `tel:` links in `a[href]`
([e7730297](https://github.com/angular/angular.js/commit/e773029717f11d727af609a139b173a135c79eab))
- **Directives:**
- **ngRepeat:** support repeating over `ngInclude` and other directives that replace repeated nodes
([9efa46ae](https://github.com/angular/angular.js/commit/9efa46ae640cde17487c341daa9a75c0bd79da02),
[#3104](https://github.com/angular/angular.js/issues/3104))
- **event directives:** add `ngCopy`, `ngCut`, and `ngPaste`
([147c6929](https://github.com/angular/angular.js/commit/147c6929a264a7b077a5f2cfc5aa9a0b9513acd7),
[#4172](https://github.com/angular/angular.js/issues/4172))
- **Misc:**
- jQuery 1.10.x support
([e0c134b8](https://github.com/angular/angular.js/commit/e0c134b8bfa282379daec6a7137512d58f956443),
[#3764](https://github.com/angular/angular.js/issues/3764))
- **minErr:** linkify error messages on minErr docs pages
([6aaae062](https://github.com/angular/angular.js/commit/6aaae062171bfc8e5046c3eae99bc9d63037120a))
- **tutorial:** add step 12 on animations to the phonecat tutorial
([ad525645](https://github.com/angular/angular.js/commit/ad5256452bb8f1d481d78e7ae15a59d288f0d8e9))
## Bug Fixes
- **$compile:**
- abort compilation when duplicate element transclusion
([63c5334c](https://github.com/angular/angular.js/commit/63c5334c84b7269428c710226764d1f08a36e0d4),
[#3893](https://github.com/angular/angular.js/issues/3893),
[#4217](https://github.com/angular/angular.js/issues/4217),
[#3307](https://github.com/angular/angular.js/issues/3307))
- make order directives w/ same priority deterministic
([4357da85](https://github.com/angular/angular.js/commit/4357da857587d3c28790e7dc654664bec5808768))
- fix (reverse) directive postLink fn execution order
([31f190d4](https://github.com/angular/angular.js/commit/31f190d4d53921d32253ba80d9ebe57d6c1de82b),
[#3558](https://github.com/angular/angular.js/issues/3558))
- don't terminate compilation for regular transclusion directives
([fe214501](https://github.com/angular/angular.js/commit/fe2145016cb057c92f9f01b32c58b4d7259eb6ee))
- ng-attr to support dash separated attribute names
([8e6e3eba](https://github.com/angular/angular.js/commit/8e6e3ebad991eaf57a7885549ea3b91932d495c9))
- allow interpolations for non-event handlers attrs
([8e1276c0](https://github.com/angular/angular.js/commit/8e1276c011b33b90af47494dc5e76baf86468a5a))
- link parents before traversing
([742271ff](https://github.com/angular/angular.js/commit/742271ffa3a518d9e8ef2cb97c24b45b44e3378d),
[#3792](https://github.com/angular/angular.js/issues/3792),
[#3923](https://github.com/angular/angular.js/issues/3923),
[#3935](https://github.com/angular/angular.js/issues/3935),
[#3927](https://github.com/angular/angular.js/issues/3927))
- collect ranges on multiple directives on one element
([6a8edc1d](https://github.com/angular/angular.js/commit/6a8edc1d43aca7c5a92f86309b1bb1d5f9968442),
[#4002](https://github.com/angular/angular.js/issues/4002))
- **$parse:**
- deprecate promise unwrapping and make it an opt-in
([5dc35b52](https://github.com/angular/angular.js/commit/5dc35b527b3c99f6544b8cb52e93c6510d3ac577),
[#4158](https://github.com/angular/angular.js/issues/4158),
[#4270](https://github.com/angular/angular.js/issues/4270))
- disallow access to window and dom in expressions
([be0b4856](https://github.com/angular/angular.js/commit/be0b4856699334ff51bacf2d1fd3394663d6bd28))
- **$httpBackend:**
- set headers with falsy values
([e9a22241](https://github.com/angular/angular.js/commit/e9a222418a029d830698444cf95bf13f8ad75805),
[#2984](https://github.com/angular/angular.js/issues/2984))
- don't send empty string bodies
([0d0330ad](https://github.com/angular/angular.js/commit/0d0330adc24a68cd6891a030a56d3ce3bbced03c),
[#2149](https://github.com/angular/angular.js/issues/2149))
- **$location:**
- prevent infinite digest error in IE7
([d7071148](https://github.com/angular/angular.js/commit/d70711481e6311c9cd283d650f07ca0cca72ecc2),
[#2802](https://github.com/angular/angular.js/issues/2802))
- re-assign location after BFCache back
([2ebf9316](https://github.com/angular/angular.js/commit/2ebf93163027abc55ba27f673be3b8dc1281c068),
[#4044](https://github.com/angular/angular.js/issues/4044))
- **$log:** prevent logging `undefined` for $log in IE
([4ff1a650](https://github.com/angular/angular.js/commit/4ff1a65031e985bf930f6761c1ecf46e4db98d6e),
[#1705](https://github.com/angular/angular.js/issues/1705))
- **Scope:**
- `$evalAsync` executes on the right scope
([10cc1a42](https://github.com/angular/angular.js/commit/10cc1a42c925749f88433546d41d35ba07a88e6f))
- make `stopPropagation` only stop its own event
([47f7bd70](https://github.com/angular/angular.js/commit/47f7bd706efc5f2944d182e46c1b1d324298ff36),
[#4204](https://github.com/angular/angular.js/issues/4204))
- **Filters:**
- **date:** allow negative millisecond value strings
([025c9219](https://github.com/angular/angular.js/commit/025c92190376414c15f15fd20a75b41489a4e70a))
- **Directives:**
- correct priority of structural directives (ngRepeat, ngSwitchWhen, ngIf, ngInclude, ngView)
([b7af76b4](https://github.com/angular/angular.js/commit/b7af76b4c5aa77648cc1bfd49935b48583419023))
- **input:** `false` is no longer an empty value by default
([b56b21a8](https://github.com/angular/angular.js/commit/b56b21a898b3c77589a48a290271f9dc181dafe8),
[#3490](https://github.com/angular/angular.js/issues/3490))
- **ngBindHtml:** watch string value instead of wrapper
([e2068ad4](https://github.com/angular/angular.js/commit/e2068ad426075ac34c06c12e2fac5f594cc81969),
[#3932](https://github.com/angular/angular.js/issues/3932))
- **ngOptions:** ignore object properties which start with $
([aa3c54c7](https://github.com/angular/angular.js/commit/aa3c54c73f7470999535294899a1c33cd193f455))
- **ngRepeat:** correctly track elements even when the collection is initially undefined
([31c56f54](https://github.com/angular/angular.js/commit/31c56f540045b5270f5b8e235873da855caf3486),
[#4145](https://github.com/angular/angular.js/issues/4145),
[#3964](https://github.com/angular/angular.js/issues/3964))
- **ngTransclude:** detect ngTranslude usage without a transclusion directive
([5a1a6b86](https://github.com/angular/angular.js/commit/5a1a6b86a8dbcd8aa4fe9c59fad8d005eead686c),
[#3759](https://github.com/angular/angular.js/issues/3759))
- **jqLite:**
- ignore class methods on comment elements
([64fd2c42](https://github.com/angular/angular.js/commit/64fd2c421ed582c16812d164a8a6f031b8e66287))
- use get/setAttribute so that jqLite works on SVG nodes
([c785267e](https://github.com/angular/angular.js/commit/c785267eb8780d8b7658ef93ebb5ebddd566294d),
[#3858](https://github.com/angular/angular.js/issues/3858))
- **Misc:**
- **isArrayLike:** correctly handle string primitives
([5b8c7884](https://github.com/angular/angular.js/commit/5b8c78843e8d62a7a67cead8bf04c76aa8ee411d),
[#3356](https://github.com/angular/angular.js/issues/3356))
- protect calls to hasOwnProperty in public API
([7a586e5c](https://github.com/angular/angular.js/commit/7a586e5c19f3d1ecc3fefef084ce992072ee7f60),
[#3331](https://github.com/angular/angular.js/issues/3331))
- **ngRoute:**
- **ngView:** IE8 regression due to expando on non-element nodes
([255e8c13](https://github.com/angular/angular.js/commit/255e8c13cf0fd78f1c4d7c279be7bf47c2402956),
[#3971](https://github.com/angular/angular.js/issues/3971))
- **$route:** parametrized routes do not match against locations that would not valorize each parameters.
([0ff86c32](https://github.com/angular/angular.js/commit/0ff86c323359fba1a60bacab178e3c68528f8e1f))
- **ngResource:**
- pass transformed value to both callbacks and promises
([e36e28eb](https://github.com/angular/angular.js/commit/e36e28ebd4a6c144e47d11fba8e211d8d5a9d03e),
[#3817](https://github.com/angular/angular.js/issues/3817))
- remove request body from $delete
([8336b3a2](https://github.com/angular/angular.js/commit/8336b3a286f8469d4cd7c412c41ca8c1a31fecf0),
[#4280](https://github.com/angular/angular.js/issues/4280))
- **ngSanitize:**
- sanitize DOCTYPE declarations correctly
([e66c23fe](https://github.com/angular/angular.js/commit/e66c23fe55f8571a014b0686c8dbca128e7a8240),
[#3931](https://github.com/angular/angular.js/issues/3931))
- sanitizer should not accept <!--> as a valid comment
([21e9e8cf](https://github.com/angular/angular.js/commit/21e9e8cf68ef007136da6cc212d2f1f252fb668a))
- **ngTouch:**
- ngClick does not pass touchend event when jQuery is loaded
([9fd92cc3](https://github.com/angular/angular.js/commit/9fd92cc3c93a6378e8887fd46fd4ad182a375544))
- add $event to ng-swipe
([507d8021](https://github.com/angular/angular.js/commit/507d8021b1c91cc0cefc0418e61b04597ad1030b),
[#4071](https://github.com/angular/angular.js/issues/4071),
[#4321](https://github.com/angular/angular.js/issues/4321))
- **ngAnimate:**
- ensure that a timeStamp is created if not provided by the browser event
([cd216c4c](https://github.com/angular/angular.js/commit/cd216c4c30adfebb3ef633f18fab2d98e8c52ebc),
[#3053](https://github.com/angular/angular.js/issues/3053))
- perform internal caching on getComputedStyle to boost the performance of CSS3 transitions/animations
([b1e604e3](https://github.com/angular/angular.js/commit/b1e604e38ceec1714174fb54cc91590a7fe99a92),
[#4011](https://github.com/angular/angular.js/issues/4011),
[#4124](https://github.com/angular/angular.js/issues/4124))
- ensure structural animations skip all child animations even if no animation is present during compile
([cc584607](https://github.com/angular/angular.js/commit/cc5846073e57ef190182026d7e5a8e2770d9b770),
[#3215](https://github.com/angular/angular.js/issues/3215))
- cancel any ongoing child animations during move and leave animations
([3f31a7c7](https://github.com/angular/angular.js/commit/3f31a7c7691993893f0724076816f6558643bd91))
- ensure elapsedTime always considers delay values
([079dd939](https://github.com/angular/angular.js/commit/079dd93991ac79b5f9af6efb7fe2b3600195f10c))
- ensure transition-property is not changed when only keyframe animations are in use
([2df3c9f5](https://github.com/angular/angular.js/commit/2df3c9f58def9584455f7c4bfdabbd12aab58bf9),
[#3933](https://github.com/angular/angular.js/issues/3933))
- avoid completing the animation asynchronously unless CSS transtiions/animations are present
([2a63dfa6](https://github.com/angular/angular.js/commit/2a63dfa6cc7889888f4296fff2944e74ff30b3af),
[#4023](https://github.com/angular/angular.js/issues/4023),
[#3940](https://github.com/angular/angular.js/issues/3940))
- ensure that delays are always considered before an animation closes
([0a63adce](https://github.com/angular/angular.js/commit/0a63adce687d28ada90ea930d5e69883cc11cba5),
[#4028](https://github.com/angular/angular.js/issues/4028))
- check elapsedTime on current event
([d50ed6bf](https://github.com/angular/angular.js/commit/d50ed6bfb8c4982401923ff535fe932ef4f387a2))
- support addClass/removeClass animations on SVG nodes
([c785267e](https://github.com/angular/angular.js/commit/c785267eb8780d8b7658ef93ebb5ebddd566294d),
[#3858](https://github.com/angular/angular.js/issues/3858))
- **ngScenario:**
- remove redundant assignment
([a80e96ce](https://github.com/angular/angular.js/commit/a80e96cea184b392505f0a292785a5c66d45e165),
[#4315](https://github.com/angular/angular.js/issues/4315))
- fix error message description
([f8f8f754](https://github.com/angular/angular.js/commit/f8f8f754b02459bb789247476cc0da63d2d7370f))
- provide event parameters as object
([28f56a38](https://github.com/angular/angular.js/commit/28f56a383e9d1ff378e3568a3039e941c7ffb1d8))
- include "not " in error messages if test is inverted
([3589f178](https://github.com/angular/angular.js/commit/3589f17824376e9db4e8d002caeb4483943eeb18),
[#3840](https://github.com/angular/angular.js/issues/3840))
## Breaking Changes
- **$compile:** due to [31f190d4](https://github.com/angular/angular.js/commit/31f190d4d53921d32253ba80d9ebe57d6c1de82b),
the order of postLink fn is now mirror opposite of the order in which corresponding preLinking and compile functions execute.
Previously the compile/link fns executed in this order controlled via priority:
- CompilePriorityHigh, CompilePriorityMedium, CompilePriorityLow
- compile child nodes
- PreLinkPriorityHigh, PreLinkPriorityMedium, PreLinkPriorityLow
- link child nodes
- PostLinkPriorityHigh, PostLinkPriorityMedium, PostLinkPriorityLow
This was changed to:
- CompilePriorityHigh, CompilePriorityMedium, CompilePriorityLow
- compile child nodes
- PreLinkPriorityHigh, PreLinkPriorityMedium, PreLinkPriorityLow
- link child nodes
- PostLinkPriorityLow, PostLinkPriorityMedium , PostLinkPriorityHigh
Very few directives in practice rely on order of postLinking function (unlike on the order of compile functions), so
in the rare case of this change affecting an existing directive, it might be necessary to convert it to a preLinking
function or give it negative priority (look at the diff of this commit to see how an internal attribute interpolation
directive was adjusted).
- **$parse:**
- due to [5dc35b52](https://github.com/angular/angular.js/commit/5dc35b527b3c99f6544b8cb52e93c6510d3ac577),
$parse and templates in general will no longer automatically unwrap promises. This feature has been deprecated and if absolutely needed, it can be reenabled during transitional period via `$parseProvider.unwrapPromises(true)` api.
- due to [b6a37d11](https://github.com/angular/angular.js/commit/b6a37d112b3e1478f4d14a5f82faabf700443748),
feature added in rc.2 that unwraps return values from functions if the values are promises (if promise unwrapping is enabled - see previous point), was reverted due to breaking a popular usage pattern.
- **directives:** due to [b7af76b4](https://github.com/angular/angular.js/commit/b7af76b4c5aa77648cc1bfd49935b48583419023),
the priority of ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView has changed. This could affect directives that explicitly specify their priority.
In order to make ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView work together in all common scenarios their directives are being adjusted to achieve the following precendence:
```
Directive | Old Priority | New Priority
=============================================
ngRepeat | 1000 | 1000
---------------------------------------------
ngSwitchWhen | 500 | 800
---------------------------------------------
ngIf | 1000 | 600
---------------------------------------------
ngInclude/ngView | 1000 | 400
```
- **form/ngForm** due to [7a586e5c](https://github.com/angular/angular.js/commit/7a586e5c19f3d1ecc3fefef084ce992072ee7f60),
Inputs with name equal to "hasOwnProperty" are not allowed inside form or ngForm directives.
Before, inputs whose name was "hasOwnProperty" were quietly ignored and not added to the scope. Now a badname exception is thrown.
Using "hasOwnProperty" for an input name would be very unusual and bad practice.
Either do not include such an input in a `form` or `ngForm` directive or change the name of the input.
- **ngScenario:** due to [28f56a38](https://github.com/angular/angular.js/commit/28f56a383e9d1ff378e3568a3039e941c7ffb1d8),
browserTrigger now uses an eventData object instead of direct parameters for mouse events.
To migrate, place the `keys`,`x` and `y` parameters inside of an object and place that as the third parameter for the browserTrigger function.
<a name="1.2.0-rc.2"></a>
# 1.2.0-rc.2 barehand-atomsplitting (2013-09-04)
+246 -19
View File
@@ -1,32 +1,259 @@
## Submitting issues
#Contributing to AngularJS
If you have questions about how to use AngularJS, please direct these to the
[Google Group][groups] discussion list or [StackOverflow][stackoverflow]. We are
also available on [IRC][irc].
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
### Guidelines
## Got a Question or Problem?
* Search the archive first, it's likely that your question was already answered.
* A live example demonstrating your problem or question, will get an answer faster.
* Create one using this [template][template]
* If you get help, help others. Good karma rulez!
If you have questions about how to use AngularJS, please direct these to the [Google Group][groups]
discussion list or [StackOverflow][stackoverflow]. We are also available on [IRC][irc].
## Found an Issue?
If you find a bug in the source code or a mistake in the documentation, you can help us by
submitting and issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
with a fix.
***Localization Issue:*** *Angular.js uses the [Google Closure I18N library], to generate its own I18N files. This means that
any changes to these files would be lost the next time that we import the library. The recommended
approach is to submit a patch to the I18N project directly, instead of submitting it here.*
**Please see the Submission Guidelines below**.
## Want a Feature?
You can request a new feature by submitting an issue to our [GitHub Repository][github]. If you
would like to implement a new feature then consider what kind of change it is:
* **Major Changes** that you wish to contribute to the project should be discussed first on our
[dev mailing list][angular-dev] or [IRC][irc] so that we can better coordinate our efforts, prevent
duplication of work, and help you to craft the change so that it is successfully accepted into the
project.
* **Small Changes** can be crafted and submitted to [GitHub Repository][github] as a Pull Request.
## Want a Doc Fix?
If you want to help improve the docs, it's a good idea to let others know what you're working on to
minimize duplication of effort. Before starting, check out the issue queue for [Milestone:Docs Only](https://github.com/angular/angular.js/issues?milestone=24&state=open).
Comment on an issue to let others know what you're working on, or create a new issue if your work
doesn't fit within the scope of any of the existing doc fix projects.
For large fixes, please build and test the documentation before submitting the PR to be sure you haven't
accidentally introduced any layout or formatting issues.You should also make sure that your commit message
is labeled "docs:" and follows the **Git Commit Guidelines** outlined below.
If you're just making a small change, don't worry about filing an issue first. Use the friendly blue "Improve this doc" button at the top right of the doc page to fork the repository in-place and make a quick change on the fly.
## Submission Guidelines
### Submitting an Issue
Before you submit your issue search the archive, maybe your question was already answered.
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues.
features, by not reporting duplicate issues. Providing the following information will increase the
chances of your issue being dealt with quickly:
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[template]: http://plnkr.co/edit/gist:3510140
* **Overview of the issue** - if an error is being thrown a non-minified stack trace helps
* **Motivation for or Use Case** - explain why this is a bug for you
* **Angular Version(s)** - is it a regression?
* **Browsers and Operating System** - is this a problem with all browsers or only IE8?
* **Reproduce the error** - provide a live example (using [Plunker][plunker] or
[JSFiddle][jsfiddle]) or a unambiguous set of steps.
* **Related issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
causing the problem (line of code or commit)
## Contributing to Source Code
Here is a great example of a well defined issue: https://github.com/angular/angular.js/issues/5069
We'd love for you to contribute to our source code and to make AngularJS even
better than it is today!
**If you get help, help others. Good karma rulez!**
Please read the [contribution guidelines][contribute] to learn about how to submit code as well as
other useful info like how to build and test AngularJS code.
### Submitting a Pull Request
Before you submit your pull request consider the following guidelines:
* Search [GitHub](https://github.com/angular/angular.js/pulls) for an open or closed Pull Request
that relates to your submission. You don't want to duplicate effort.
* Please sign our [Contributor License Agreement (CLA)](#signing-the-cla) before sending pull
requests. We cannot accept code without this.
* Make your changes in a new git branch
```shell
git checkout -b my-fix-branch master
```
* Create your patch, including appropriate test cases.
* Follow our Coding Rules
* Commit your changes and create a descriptive commit message (the
commit message is used to generate release notes, please check out our
[commit message conventions](#commit-message-format) and our commit message presubmit hook
`validate-commit-msg.js`):
```shell
git commit -a
```
* Build your changes locally to ensure all the tests pass
```shell
grunt test
```
* Push your branch to Github:
```shell
git push origin my-fix-branch
```
* In Github, send a pull request to `angular:master`.
* If we suggest changes then you can modify your branch, rebase and force a new push to your GitHub
repository to update the Pull Request:
```shell
git rebase master -i
git push -f
```
That's it! Thank you for your contribution!
When the patch is reviewed and merged, you can safely delete your branch and pull the changes
from the main (upstream) repository:
* Delete the remote branch on Github:
```shell
git push origin --delete my-fix-branch
```
* Check out the master branch:
```shell
git checkout master -f
```
* Delete the local branch:
```shell
git branch -D my-fix-branch
```
* Update your master with the latest upstream version:
```shell
git pull --ff upstream master
```
### GitHub Pull Request Helper
We track Pull Requests by attaching labels and assigning to milestones. For some reason GitHub
does not provide a good UI for managing labels on Pull Requests (unlike Issues). We have developed
a simple Chrome Extension that enables you to view (and manage if you have permission) the labels
on Pull Requests. You can get the extension from the Chrome WebStore -
[GitHub PR Helper][github-pr-helper]
## Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must be tested** by one or more [specs][unit-testing].
* All public API methods **must be documented** with ngdoc, an extended version of jsdoc (we added
support for markdown and templating via @ngdoc tag). To see how we document our APIs, please check
out the existing ngdocs and see [this wiki page][ngDocs].
* With the exceptions listed below, we follow the rules contained in
[Google's JavaScript Style Guide][js-style-guide]:
* **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
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
external API. See our existing code to see what we mean.
* We **don't go crazy with type annotations** for private internal APIs unless it's an internal API
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
## Git Commit Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the AngularJS change log**.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on github as well as in various git tools.
### Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
### Scope
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
###Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
The body should include the motivation for the change and contrast this with previous behavior.
###Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
A detailed explanation can be found in this [document][commit-message-format].
## Signing the CLA
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
* For individuals we have a [simple click-through form][individual-cla].
* For corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
## Further Information
You can find out more detailed information about contributing in the
[AngularJS documentation][contributing].
[github]: https://github.com/angular/angular.js
[Google Closure I18N library]: https://code.google.com/p/closure-library/source/browse/closure/goog/i18n/
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[contribute]: http://docs.angularjs.org/misc/contribute
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
[angular-dev]: https://groups.google.com/forum/?fromgroups#!forum/angular-dev
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[plunker]: http://plnkr.co/edit
[jsfiddle]: http://jsfiddle.net/
[ngDocs]: https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation
[unit-testing]: http://docs.angularjs.org/guide/dev_guide.unit-testing
[js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
[contributing]: http://docs.angularjs.org/misc/contribute
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[github-pr-helper]: https://chrome.google.com/webstore/detail/github-pr-helper/mokbklfnaddkkbolfldepnkfmanfhpen
+47 -23
View File
@@ -13,6 +13,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-merge-conflict');
grunt.loadNpmTasks('grunt-parallel');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadTasks('lib/grunt');
var NG_VERSION = util.getVersion();
@@ -104,6 +105,41 @@ module.exports = function(grunt) {
tmp: ['tmp']
},
jshint: {
options: {
jshintrc: true,
},
ng: {
files: { src: files['angularSrc'] },
},
ngAnimate: {
files: { src: 'src/ngAnimate/**/*.js' },
},
ngCookies: {
files: { src: 'src/ngCookies/**/*.js' },
},
ngLocale: {
files: { src: 'src/ngLocale/**/*.js' },
},
ngMock: {
files: { src: 'src/ngMock/**/*.js' },
},
ngResource: {
files: { src: 'src/ngResource/**/*.js' },
},
ngRoute: {
files: { src: 'src/ngRoute/**/*.js' },
},
ngSanitize: {
files: { src: 'src/ngSanitize/**/*.js' },
},
ngScenario: {
files: { src: 'src/ngScenario/**/*.js' },
},
ngTouch: {
files: { src: 'src/ngTouch/**/*.js' },
}
},
build: {
scenario: {
@@ -121,54 +157,42 @@ module.exports = function(grunt) {
src: util.wrap([files['angularSrc']], 'angular'),
styles: {
css: ['css/angular.css'],
generateCspCssFile: true,
minify: true
}
},
loader: {
dest: 'build/angular-loader.js',
src: util.wrap(['src/loader.js'], 'loader')
src: util.wrap(files['angularLoader'], 'loader')
},
touch: {
dest: 'build/angular-touch.js',
src: util.wrap([
'src/ngTouch/touch.js',
'src/ngTouch/swipe.js',
'src/ngTouch/directive/ngClick.js',
'src/ngTouch/directive/ngSwipe.js'
], 'module')
src: util.wrap(files['angularModules']['ngTouch'], 'module')
},
mocks: {
dest: 'build/angular-mocks.js',
src: ['src/ngMock/angular-mocks.js'],
src: util.wrap(files['angularModules']['ngMock'], 'module'),
strict: false
},
sanitize: {
dest: 'build/angular-sanitize.js',
src: util.wrap([
'src/ngSanitize/sanitize.js',
'src/ngSanitize/filter/linky.js'
], 'module')
src: util.wrap(files['angularModules']['ngSanitize'], 'module')
},
resource: {
dest: 'build/angular-resource.js',
src: util.wrap(['src/ngResource/resource.js'], 'module')
src: util.wrap(files['angularModules']['ngResource'], 'module')
},
animate: {
dest: 'build/angular-animate.js',
src: util.wrap(['src/ngAnimate/animate.js'], 'module')
src: util.wrap(files['angularModules']['ngAnimate'], 'module')
},
route: {
dest: 'build/angular-route.js',
src: util.wrap([
'src/ngRoute/routeUtils.js',
'src/ngRoute/route.js',
'src/ngRoute/routeParams.js',
'src/ngRoute/directive/ngView.js'
], 'module')
src: util.wrap(files['angularModules']['ngRoute'], 'module')
},
cookies: {
dest: 'build/angular-cookies.js',
src: util.wrap(['src/ngCookies/cookies.js'], 'module')
src: util.wrap(files['angularModules']['ngCookies'], 'module')
},
"promises-aplus-adapter": {
dest:'tmp/promises-aplus-adapter++.js',
@@ -249,7 +273,7 @@ module.exports = function(grunt) {
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e']);
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
@@ -263,6 +287,6 @@ module.exports = function(grunt) {
grunt.registerTask('webserver', ['connect:devserver']);
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('package-without-bower', ['clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'test:docgen']);
grunt.registerTask('default', ['package']);
};
+55
View File
@@ -0,0 +1,55 @@
# Triage new issues/PRs on github
This document shows the steps the Angular team is using to triage issues.
The labels are used later on for planning releases.
## Tips ##
* install [github pr helper extension](https://github.com/petebacondarwin/github-pr-helper) and become 356% more productive
* Label "resolution:*"
* these tags can be used for labeling a closed issue/PR with a reason why it was closed. (we can add reasons as we need them, right there are only a few rejection reasons. it doesn't make sense to label issues that were fixed or prs that were merged)
## Process ##
1. Open list of [non triaged issues](https://github.com/angular/angular.js/issues?direction=desc&milestone=none&page=1&sort=created&state=open)
1. Assign yourself: Pick an issue that is not assigned to anyone and assign it to you
1. Assign milestone:
* "Docs only" milestone - for documentation PR -> **Done**.
* Current/next milestone - regressions
* 1.2.x - everything else
1. Label "GH: *" (to be automated via Mary Poppins)
* PR - issue is a PR
* issue - otherwise
1. Bugs:
* Label "Type: Bug"
* Label "Type: Regression" - if the bug is a regression
* Duplicate? - Check if there are comments pointing out that this is a dupe, if they do exist verify that this is indeed a dupe and close it and go to the last step
* Reproducible? - Steps to reproduce the bug are clear, if not ask for clarification (ideally plunker or fiddle)
* Reproducible on master? - http://code.angularjs.org/snapshot/
1. Non bugs:
* Label "Type: Feature" or "Type: Chore"
* Label "needs: breaking change" - if needed
* Understandable? - verify if the description of the request is clear. if not ask for clarification
* Goals of angular core? - Often new features should be implemented as a third-party module rather than an addition to the core.
1. Label "component: *"
* In rare cases, it's ok to have multiple components.
1. Label "impact: *"
* small - obscure issue affecting one or handful of developers
* medium - impacts some usage patterns
* large - impacts most or all of angular apps
1. Label "complexity: *"
* small - trivial change
* medium - non-trivial but straightforward change
* large - changes to many components in angular or any changes to $compile, ngRepeat or other "fun" components
1. Label "PRs welcome" for "GH: issue"
* if complexity is small or medium and the problem as well as solution are well captured in the issue
1. Label "cla: yes" for "GH: PR":
* otherwise prompt the contributor to sign the CLA
1. Label "origin: google" for issues from Google
1. Label "high priority" for security issues, major performance regressions or memory leaks
1. Unassign yourself from the issue
+44 -16
View File
@@ -27,6 +27,7 @@ angularFiles = {
'src/ng/parse.js',
'src/ng/q.js',
'src/ng/rootScope.js',
'src/ng/sanitizeUri.js',
'src/ng/sce.js',
'src/ng/sniffer.js',
'src/ng/timeout.js',
@@ -65,24 +66,41 @@ angularFiles = {
'src/ng/directive/style.js'
],
'angularSrcModules': [
'src/ngAnimate/animate.js',
'src/ngCookies/cookies.js',
'src/ngResource/resource.js',
'src/ngRoute/routeUtils.js',
'src/ngRoute/route.js',
'src/ngRoute/routeParams.js',
'src/ngRoute/directive/ngView.js',
'src/ngSanitize/sanitize.js',
'src/ngSanitize/filter/linky.js',
'src/ngMock/angular-mocks.js',
'src/ngTouch/touch.js',
'src/ngTouch/swipe.js',
'src/ngTouch/directive/ngClick.js',
'src/ngTouch/directive/ngSwipe.js',
'docs/components/angular-bootstrap/bootstrap.js',
'angularLoader': [
'src/minErr.js',
'src/loader.js'
],
'angularModules': {
'ngAnimate': [
'src/ngAnimate/animate.js'
],
'ngCookies': [
'src/ngCookies/cookies.js'
],
'ngResource': [
'src/ngResource/resource.js'
],
'ngRoute': [
'src/ngRoute/route.js',
'src/ngRoute/routeParams.js',
'src/ngRoute/directive/ngView.js'
],
'ngSanitize': [
'src/ngSanitize/sanitize.js',
'src/ngSanitize/filter/linky.js'
],
'ngMock': [
'src/ngMock/angular-mocks.js'
],
'ngTouch': [
'src/ngTouch/touch.js',
'src/ngTouch/swipe.js',
'src/ngTouch/directive/ngClick.js',
'src/ngTouch/directive/ngSwipe.js'
],
},
'angularScenario': [
'src/ngScenario/Scenario.js',
'src/ngScenario/browserTrigger.js',
@@ -172,6 +190,16 @@ angularFiles = {
]
};
angularFiles['angularSrcModules'] = [].concat(
angularFiles['angularModules']['ngAnimate'],
angularFiles['angularModules']['ngCookies'],
angularFiles['angularModules']['ngResource'],
angularFiles['angularModules']['ngRoute'],
angularFiles['angularModules']['ngSanitize'],
angularFiles['angularModules']['ngMock'],
angularFiles['angularModules']['ngTouch']
);
if (exports) {
exports.files = angularFiles;
exports.mergeFilesFor = function() {
-6
View File
@@ -16,7 +16,6 @@ var LINK_ISSUE = '[#%s](https://github.com/angular/angular.js/issues/%s)';
var LINK_COMMIT = '[%s](https://github.com/angular/angular.js/commit/%s)';
var EMPTY_COMPONENT = '$$';
var MAX_SUBJECT_LENGTH = 80;
var warn = function() {
@@ -54,11 +53,6 @@ var parseRawCommit = function(raw) {
return null;
}
if (match[3].length > MAX_SUBJECT_LENGTH) {
warn('Too long subject: %s %s', msg.hash, msg.subject);
match[3] = match[3].substr(0, MAX_SUBJECT_LENGTH);
}
msg.type = match[1];
msg.component = match[2];
msg.subject = match[3];
-80
View File
@@ -1,80 +0,0 @@
<a name="v1.0.0rc3"></a>
# v1.0.0rc3 (2012-03-27)
## Bug Fixes
- **$compile:**
- create new (isolate) scopes for directives on root elements ([5390fb37](https://github.com/angular/angular.js/commit/5390fb37d2c01937922613fc57df4986af521787), closes [#817](https://github.com/angular/angular.js/issues/817))
- don't touch static element attributes ([9cb2195e](https://github.com/angular/angular.js/commit/9cb2195e61a78e99020ec19d687a221ca88b5900))
- Merge interpolated css class when replacing an element ([f49eaf8b](https://github.com/angular/angular.js/commit/f49eaf8bf2df5f4e0e82d6c89e849a4f82c8d414))
- **$http:**
- don't send Content-Type header when no data ([1a5bebd9](https://github.com/angular/angular.js/commit/1a5bebd927ecd22f9c34617642fdf58fe3f62efb), closes [#749](https://github.com/angular/angular.js/issues/749))
- **$log:**
- avoid console.log.apply calls in IE ([15213ec2](https://github.com/angular/angular.js/commit/15213ec212769837cb2b7e781ffc5bfd598d27ca), closes [#805](https://github.com/angular/angular.js/issues/805))
- **$resource:**
- support escaping of ':' in resource url ([6d6f8753](https://github.com/angular/angular.js/commit/6d6f875345e01f2c6c63ef95164f6f39e923da15))
- **compiler:**
- allow transclusion of root elements ([9918b748](https://github.com/angular/angular.js/commit/9918b748be01266eb10db39d51b4d3098d54ab66))
- **e2e runner:**
- fix typo that caused errors on IE8 ([ee5a5352](https://github.com/angular/angular.js/commit/ee5a5352fd4b94cedee6ef20d4bf2d43ce77e00b), closes [#806](https://github.com/angular/angular.js/issues/806))
- **forEach:**
- should ignore prototypically inherited properties ([8d7e6948](https://github.com/angular/angular.js/commit/8d7e6948496ff26ef1da8854ba02fcb8eebfed61), closes [#813](https://github.com/angular/angular.js/issues/813))
- **forms:**
- Remove double registering of form ([1faafa31](https://github.com/angular/angular.js/commit/1faafa31582c4e9413f48dc7d12f5b681f9fe9fd))
- Set ng-valid/ng-invalid correctly ([08bfea18](https://github.com/angular/angular.js/commit/08bfea183a850b29da270eac47f80b598cbe600f))
- **init:**
- use jQuery#ready for init if available ([cb2ad9ab](https://github.com/angular/angular.js/commit/cb2ad9abf24e6f855cc749efe3155bd7987ece9d), closes [#818](https://github.com/angular/angular.js/issues/818))
- **json:**
- added support for iso8061 timezone ([5ac14f63](https://github.com/angular/angular.js/commit/5ac14f633a69f49973b5512780c6ec7752405967))
- **matchers.toHaveClass:**
- Correct reference to angular.mock.dump ([f701ce08](https://github.com/angular/angular.js/commit/f701ce08f9d63be05fc3b92f57ad473e1e749b2d))
- **ng-switch:**
- properly destroy child scopes ([2315d9b3](https://github.com/angular/angular.js/commit/2315d9b3610994b36c44e4a97fb1427d59471ce8))
- **ngDocSpec:**
- fix broken tests ([53b6f522](https://github.com/angular/angular.js/commit/53b6f522a56eea314cbd084816e08f24b2c7879f))
- **ngForm:**
- alias name||ngForm ([823adb23](https://github.com/angular/angular.js/commit/823adb231995e917bc060bfa49453e2a96bac2b6))
- **ngRepeat:**
- correct variable reference in error message ([935c1018](https://github.com/angular/angular.js/commit/935c1018da05dbf3124b2dd33619c4a3c82d7a2a))
- **ngView:**
- controller not published ([21e74c2d](https://github.com/angular/angular.js/commit/21e74c2d2e8e985b23711785287feb59965cbd90))
- **q:**
- resolve all of nothing to nothing ([ac75079e](https://github.com/angular/angular.js/commit/ac75079e2113949d5d64adbcf23d56f3cf295d41))
- **select:**
- multiselect failes to update view on selection insert ([6ecac8e7](https://github.com/angular/angular.js/commit/6ecac8e71a84792a434d21db2c245b3648c55f18))
## Features
- **$compile:**
- do not interpolate boolean attributes, rather evaluate them ([a08cbc02](https://github.com/angular/angular.js/commit/a08cbc02e78e789a66e9af771c410e8ad1646e25))
- **$controller:**
- support controller registration via $controllerProvider ([d54dfecb](https://github.com/angular/angular.js/commit/d54dfecb00fba41455536c5ddd55310592fdaf84))
- **$route:**
- when matching consider trailing slash as optional ([a4fe51da](https://github.com/angular/angular.js/commit/a4fe51da3ba0dc297ecd389e230d6664f250c9a6), closes [#784](https://github.com/angular/angular.js/issues/784))
- **assertArgFn:**
- should support array annotated fns ([4b8d9260](https://github.com/angular/angular.js/commit/4b8d926062eb4d4483555bdbdec4656f585ab40b))
- **http:**
- added params parameter ([73c85930](https://github.com/angular/angular.js/commit/73c8593077155a9f2e8ef42efd4c497eba0bef4f))
- **injector:**
- infer _foo_ as foo ([f13dd339](https://github.com/angular/angular.js/commit/f13dd3393dfb7a33565c9360342c193bc0bddcb6))
- **input.radio:**
- Allow value attribute to be interpolated ([ade6c452](https://github.com/angular/angular.js/commit/ade6c452753145c84884d17027a7865bf4b34b0c))
- **jqLite:**
- make injector() and scope() work with the document object ([5fdab52d](https://github.com/angular/angular.js/commit/5fdab52dd7c269f99839f4fa6b5854d9548269fa))
- add .controller() method ([6c5a05ad](https://github.com/angular/angular.js/commit/6c5a05ad49a1e083570c3dfe331403398f899dbe))
- **ngValue:**
- allow radio inputs to have non string values ([09e175f0](https://github.com/angular/angular.js/commit/09e175f02cca0f4a295fd0c9b980cd8f432e722b), closes [#816](https://github.com/angular/angular.js/issues/816))
- **scope:**
- broadcast $destroy event on scope destruction ([9b1aff90](https://github.com/angular/angular.js/commit/9b1aff905b638aa274a5fc8f88662df446d374bd))
- **scope.$eval:**
- Allow passing locals to the expression ([192ff61f](https://github.com/angular/angular.js/commit/192ff61f5d61899e667c6dbce4d3e6e399429d8b))
## Breaking Changes
- boolean attrs are evaluated rather than interpolated ([a08cbc02](https://github.com/angular/angular.js/commit/a08cbc02e78e789a66e9af771c410e8ad1646e25))
- ng-bind-attr directive removed ([55027132](https://github.com/angular/angular.js/commit/55027132f3d57e5dcf94683e6e6bd7b0aae0087d))
- any app that depends on this service and its fallback to Modernizr, please ([aaedefb9](https://github.com/angular/angular.js/commit/aaedefb92e6bec6626e173e5155072c91471596a))
+17
View File
@@ -0,0 +1,17 @@
This file contains externs for use with the Closure compiler (aka JSCompiler).
Passing these files to the --externs parameter of a compiler pass allows using
type annotations for AngularJS objects. For example, Angular's $scope objects
can be annotated as:
```js
/** @type {angular.Scope} */
var scope = $scope;
```
This allows JSCompiler to type check accesses to scope, give warnings about
missing methods or incorrect arguments, and also prevents renaming of property
accesses with advanced compilation.
The externs are incomplete and maintained on an as-needed basis, but strive to
be correct. Externs for individual modules should be added in separate files.
See https://developers.google.com/closure/compiler/
+1933
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -9,3 +9,14 @@
ng\:form {
display: block;
}
/* The styles below ensure that the CSS transition will ALWAYS
* animate and close. A nasty bug occurs with CSS transitions where
* when the active class isn't set, or if the active class doesn't
* contain any styles to transition to, then, if ngAnimate is used,
* it will appear as if the webpage is broken due to the forever hanging
* animations. The border-spacing (!ie) and zoom (ie) CSS properties are
* used below since they trigger a transition without making the browser
* animate anything and they're both highly underused CSS properties */
.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }
.ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; }
+23 -15
View File
@@ -169,28 +169,30 @@ directive.ngSetHtml = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplate) {
return {
compile: function (element, attr) {
var script = getEmbeddedTemplate(attr.ngEvalJavascript);
try {
if (window.execScript) { // IE
window.execScript(script || '""'); // IE complains when evaling empty string
} else {
window.eval(script);
var fileNames = attr.ngEvalJavascript.split(' ');
angular.forEach(fileNames, function(fileName) {
var script = getEmbeddedTemplate(fileName);
try {
if (window.execScript) { // IE
window.execScript(script || '""'); // IE complains when evaling empty string
} else {
window.eval(script + '//@ sourceURL=' + fileName);
}
} catch (e) {
if (window.console) {
window.console.log(script, '\n', e);
} else {
window.alert(e);
}
}
} catch (e) {
if (window.console) {
window.console.log(script, '\n', e);
} else {
window.alert(e);
}
}
});
}
};
}];
directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', '$sniffer', '$animate',
function($templateCache, $browser, docsRootScope, $location, $sniffer, $animate) {
function($templateCache, $browser, docsRootScope, $location, $sniffer, $animate) {
return {
terminal: true,
link: function(scope, element, attrs) {
@@ -203,6 +205,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
$provide.value('$anchorScroll', angular.noop);
$provide.value('$browser', $browser);
$provide.value('$sniffer', $sniffer);
$provide.value('$animate', $animate);
$provide.provider('$location', function() {
this.$get = ['$rootScope', function($rootScope) {
docsRootScope.$on('$locationChangeSuccess', function(event, oldUrl, newUrl) {
@@ -225,6 +228,11 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
}]);
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
embedRootScope = $delegate;
// Since we are teleporting the $animate service, which relies on the $$postDigestQueue
// we need the embedded scope to use the same $$postDigestQueue as the outer scope
embedRootScope.$$postDigestQueue = docsRootScope.$$postDigestQueue;
deregisterEmbedRootScope = docsRootScope.$watch(function embedRootScopeDigestWatch() {
embedRootScope.$digest();
});
+3 -1
View File
@@ -193,7 +193,9 @@ directive.table = function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
element[0].className = 'table table-bordered table-striped code-table';
if (!attrs['class']) {
element.addClass('table table-bordered table-striped code-table');
}
}
};
};
+294 -3
View File
@@ -2,6 +2,297 @@
@name API Reference
@description
Use the API Reference documentation when you need more information about a specific feature. Check out
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recommend the
{@link tutorial/ Tutorial}.
# AngularJS API Docs
Welcome to the AngularJS API docs page. These pages contain the AngularJS reference materials for version <strong ng-bind="version"></strong>.
The documentation is organized into **modules** which contain various components of an AngularJS application.
These components are directives, services, filters, providers, types, global APIs and testing mocks.
<div class="alert alert-info">
**Angular Namespaces `$` and `$$`**
To prevent accidental name collisions with your code,
Angular prefixes names of public objects with `$` and names of private objects with `$$`.
Please do not use the `$` or `$$` prefix in your code.
</div>
## Angular Namespace
## {@link ng ng (core module)}
This module is provided by default and contains the core components of AngularJS.
<table class="definition-table spaced">
<tr>
<td>{@link ng#directive Directives}</td>
<td>
<p>
This is the core collection of directives you would use in your template code to build an AngularJS application.
</p>
<p>
Some examples include:
{@link ng.directive:ngClick ngClick},
{@link ng.directive:ngInclude ngInclude},
{@link ng.directive:ngRepeat ngRepeat},
etc… <br />
</p>
</td>
</tr>
<tr>
<td>
{@link ng#service Services / Factories}
</td>
<td>
<p>
This is the core collection of services which are used within the DI of your application.
</p>
<p>
Some examples include:
{@link ng.$compile $compile},
{@link ng.$http $http},
{@link ngRoute.$routeParams $routeParams},
{@link ng.$location $location},
etc…
<p>
</td>
</tr>
<tr>
<td>
{@link ng#filter Filters}
</td>
<td>
<p>
The core filters available in the ng module are used to transform template data before it is renders within directives and expressions.
</p>
<p>
Some examples include:
{@link ng.filter:filter filter},
{@link ng.filter:date date},
{@link ng.filter:currency currency},
{@link ng.filter:lowercase lowercase},
{@link ng.filter:uppercase uppercase},
etc...
</p>
</td>
</tr>
<tr>
<td>
{@link ng#function Global APIs}
</td>
<td>
<p>
The core global API functions are attached to the angular object. These core functions are useful for low level JavaScript operations within your application.
</p>
<p>
Some examples include:
{@link angular.copy angular.copy()},
{@link angular.equals angular.equals()},
{@link angular.element angular.element()},
etc...
</p>
</td>
</tr>
</table>
## {@link ngRoute ngRoute}
Use ngRoute to enable URL routing to your application. The ngRoute module supports URL management via both hashbang and HTML5 pushState.
<div class="alert alert-info">Include the **angular-route.js** file and set **ngRoute** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngRoute#service Services / Factories}
</td>
<td>
The following services are used for route management:
<ul>
<li>{@link ngRoute.$routeParams $routeParams} is used to access the querystring values present in the URL.</li>
<li>{@link ngRoute.$route $route} is used to access the details of the route that is currently being accessed.</li>
<li>{@link ngRoute.$routeProvider $routeProvider} is used to register routes for the application.</li>
</ul>
</td>
</tr>
<tr>
<td>
{@link ngRoute#directive Directives}
</td>
<td>
The {@link ngRoute.directive:ngView ngView} directive will display the template of the current route within the page.
</td>
</tr>
</table>
## {@link ngAnimate ngAnimate}
Use ngAnimate to enable animation features into your application. Various core ng directives will provide
animation hooks into your application when ngAnimate is included. Animations are defined by using CSS transitions/animations
or JavaScript callbacks.
<div class="alert alert-info">Include the **angular-animate.js** file and set **ngAnimate** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngAnimate#service Services / Factories}
</td>
<td>
Use {@link ngAnimate.$animate $animate} to trigger animation operations within your directive code.
</td>
</tr>
<tr>
<td>
{@link ngAnimate CSS-based animations}
</td>
<td>
Follow ngAnimates CSS naming structure to reference CSS transitions / keyframe animations in AngularJS. Once defined the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
<tr>
<td>
{@link ngAnimate JS-based animations}
</td>
<td>
Use {@link angular.Module#methods_animation module.animation()} to register a JavaScript animation. Once registered the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
</table>
## {@link ngResource ngResource}
Use the ngResource module when querying and posting data to a REST API.
<div class="alert alert-info">Include the **angular-resource.js** file and set **ngResource** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngResource#service Services / Factories}
</td>
<td>
The {@link ngResource.$resource $resource} service is used to define RESTful objects which communicate with a REST API.
</td>
</tr>
</table>
## {@link ngCookies ngCookies}
Use the ngCookies module to handle cookie management within your application.
<div class="alert alert-info">Include the **angular-cookies.js** file and set **ngCookies** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngCookies#service Services / Factories}
</td>
<td>
The following services are used for cookie management:
<ul>
<li>The {@link ngCookies.$cookies $cookie} service is a convenient wrapper to store simple data within browser cookies.</li>
<li>{@link ngCookies.$cookieStore $cookieStore} is used to store more complex data using serialization.</li>
</ul>
</td>
</tr>
</table>
## {@link ngTouch ngTouch}
Use ngTouch when developing for mobile browsers/devices.
<div class="alert alert-info">Include the **angular-touch.js** file and set **ngTouch** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngTouch#service Services / Factories}
</td>
<td>
The {@link ngTouch.$swipe $swipe} service is used to register and manage mobile DOM events.
</td>
</tr>
<tr>
<td>
{@link ngTouch#directive Directives}
</td>
<td>
Various directives are available in ngTouch to emulate mobile DOM events.
</td>
</tr>
</table>
## {@link ngSanitize ngSanitize}
Use ngSanitize to securely parse and manipulate HTML data in your application.
<div class="alert alert-info">Include the **angular-sanitize.js** file and set **ngSanitize** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngSanitize#service Services / Factories}
</td>
<td>
The {@link ngSanitize.$sanitize $sanitize} service is used to clean up dangerous HTML code in a quick and convenient way.
</td>
</tr>
<tr>
<td>
{@link ngTouch#filter Filters}
</td>
<td>
The {@link ngSanitize.filter:linky linky filter} is used to turn URLs into HTML links within the provided string.
</td>
</tr>
</table>
## {@link ngMock ngMock}
Use ngMock to inject and mock modules, factories, services and providers within your unit tests
<div class="alert alert-info">Include the **angular-mocks.js** file into your test runner for this to work.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngMock#service Services / Factories}
</td>
<td>
<p>
ngMock will extend the behavior of various core services to become testing aware and manageable in a synchronous manner.
<p>
<p>
Some examples include:
{@link ngMock.$timeout $timeout},
{@link ngMock.$interval $interval},
{@link ngMock.$log $log},
{@link ngMock.$httpBackend $httpBackend},
etc...
<p>
</td>
</tr>
<tr>
<td>
{@link ngMock#function Global APIs}
</td>
<td>
<p>
Various helper functions are available to inject and mock modules within unit test code.
</p>
<p>
Some examples
{@link angular.mock.inject inject()},
{@link angular.mock.module module()},
{@link angular.mock.dump dump()},
etc...
<p>
</td>
</tr>
</table>
+4 -1
View File
@@ -2,4 +2,7 @@
@name ng
@description
`ng` is the name of the {@link guide/module angular module} that contains all of the core angular services.
# ng (core module)
The ng module is loaded by default when an AngularJS application is started. The module itself contains the essential components to for an AngularJS application to function. The table below lists a high level breakdown of each of the services/factories, filters, directives and testing components available within this core module.
<div doc-module-components="ng"></div>
+1 -1
View File
@@ -34,6 +34,6 @@ Take a look through the source and note:
* There is no need for listener registration and event firing on change events.
* The implicit presence of the `name` variable which is in the root {@link api/ng.$rootScope.Scope scope}.
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
* The concept of {@link guide/dev_guide.templates.databinding data binding}, which reflects any
* The concept of {@link guide/databinding data binding}, which reflects any
changes to the
input field in the greeting text.
+1 -1
View File
@@ -125,4 +125,4 @@ board variable.
* The view can call any controller function.
* In this example, the `setUrl()` and `readUrl()` functions copy the game state to/from the URL's
hash so the browser's back button will undo game steps. See deep-linking. This example calls {@link
api/ng.$rootScope.Scope#$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
api/ng.$rootScope.Scope#methods_$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
+1 -1
View File
@@ -3,7 +3,7 @@
@fullName Missing Required Controller
@description
This error occurs when {@link api/ng.$compile template compiler} tries process the directive that specifies the `require` option in a {@link guide/directive#directivedefinitionobject directive definition},
This error occurs when {@link api/ng.$compile HTML compiler} tries to process a directive that specifies the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object `require` option} in a {@link api/ng.$compile#description_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.
+2 -1
View File
@@ -21,4 +21,5 @@ myModule.directive('directiveName', function factory() {
});
```
Please refer to the {@link guide/directive#directivedefinitionobject directive definition docs} to learn more about the api.
Please refer to the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object
`scope` option} of the directive definition documentation to learn more about the API.
+2 -1
View File
@@ -3,7 +3,8 @@
@fullName Multiple Directive Resource Contention
@description
This error occurs when multiple directives are applied to the same DOM element, and processing them would result in an collisions or unsupported configuration.
This error occurs when multiple directives are applied to the same DOM element, and
processing them would result in a collision or an unsupported configuration.
To resolve this issue remove one of the directives which is causing the collision.
+3 -1
View File
@@ -3,7 +3,9 @@
@fullName Non-Assignable Expression
@description
This error occurs when a directive defines an isolate scope property that support two-way data-binding (using the `=` mode in the {@link guide/directive#directivedefinitionobject directive definition}) but the directive is used with an expression that is not-assignable.
This error occurs when a directive defines an isolate scope property
(using the `=` mode in the {@link api/ng.$compile#description_comprehensive-directive-api_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.
+13 -4
View File
@@ -3,11 +3,16 @@
@fullName Invalid Template Root
@description
When a directive is declared with `template` (or `templateUrl`) and `replace` mode on, the template must have exactly one root element.
Otherwise the replacement operation would result in a single element being replaced with multiple elements or nodes, which is unsupported and not commonly needed in practice.
When a directive is declared with `template` (or `templateUrl`) and `replace` mode on, the template
must have exactly one root element. That is, the text of the template property or the content
referenced by the templateUrl must be contained within a single html element.
For example, `<p>blah <em>blah</em> blah</p>` instead of simply `blah <em>blah</em> blah`.
Otherwise, the replacement operation would result in a single element (the directive) being replaced
with multiple elements or nodes, which is unsupported and not commonly needed in practice.
For example a directive with definition:
```
myModule.directive('myDirective', function factory() {
return {
@@ -19,12 +24,16 @@ myModule.directive('myDirective', function factory() {
});
```
And a template provided at URL `someUrl`. The template must be an html fragment that has only a single root element, like the `div` element in this template:
And a template provided at URL `someUrl`. The template must be an html fragment that has only a
single root element, like the `div` element in this template:
```
<div><b>Hello</b> World!</div>
```
An an invalid template to be used with this directive is one that defines multiple root nodes or elements. For example:
An an invalid template to be used with this directive is one that defines multiple root nodes or
elements. For example:
```
<b>Hello</b> World!
```
+1 -1
View File
@@ -6,6 +6,6 @@
This error occurs when a module fails to load due to some exception. The error
message above should provide additional context.
In AngularJS `1.2.0` and later, `ngRoute` has been moved ot its own module.
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`, be sure that you've
installed {@link api/ngRoute `ngRoute`}.
+1 -1
View File
@@ -22,5 +22,5 @@ angular.module("myApp", [])
.provider('good', GoodProvider);
```
For more information, refer to the {@link api/AUTO.$provide#provider
For more information, refer to the {@link api/AUTO.$provide#methods_provider
$provide.provider} api doc.
+1 -1
View File
@@ -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 api/angular.element#angularsjqlite jqLite}.
In order to keep Angular small, Angular implements only a subset of the selectors in {@link api/angular.element#description_angulars-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.
@@ -0,0 +1,27 @@
@ngdoc error
@name $resource:badmember
@fullName Syntax error in param value using @member lookup
@description
Occurs when there is a syntax error when attempting to extract a param
value from the data object.
Here's an example of valid syntax for `params` or `paramsDefault`:
````javascript
{
bar: '@foo.bar'
}
````
The part following the `@`, `foo.bar` in this case, should be a simple
dotted member lookup using only ASCII identifiers. This error occurs
when there is an error in that expression. The following are all syntax
errors
| Value | Error |
|---------|----------------|
| `@` | Empty expression following `@`. |
| `@1.a` | `1` is an invalid javascript identifier. |
| `@.a` | Leading `.` is invalid. |
| `@a[1]` | Only dotted lookups are supported (no index operator) |
+5 -2
View File
@@ -3,7 +3,8 @@
@fullName Infinite $digest Loop
@description
This error occurs when the application's model becomes unstable and each `$digest` cycle triggers a state change and subsequent `$digest` cycle. Angular detects this situation and prevents an infinite loop from causing the browser to become unresponsive.
This error occurs when the application's model becomes unstable and each `$digest` cycle triggers a state change and subsequent `$digest` cycle.
Angular detects this situation and prevents an infinite loop from causing the browser to become unresponsive.
For example, the situation can occur by setting up a watch on a path and subsequently updating the same path when the value changes.
@@ -11,4 +12,6 @@ For example, the situation can occur by setting up a watch on a path and subsequ
$scope.$watch('foo', function() {
$scope.foo = $scope.foo + 1;
});
```
```
The maximum number of allowed iterations of the `$digest` cycle is controlled via TTL setting which can be configured via {@link api/ng.$rootScopeProvider $rootScopeProvider}.
+1 -1
View File
@@ -3,6 +3,6 @@
@fullName Invalid / Unknown SCE context
@description
The context enum passed to {@link api/ng.$sce#trustAs $sce.trustAs} was not recognized.
The context enum passed to {@link api/ng.$sce#methods_trustAs $sce.trustAs} was not recognized.
Please consult the list of {@link api/ng.$sce#contexts supported Strict Contextual Escaping (SCE) contexts}.
+1 -1
View File
@@ -3,7 +3,7 @@
@fullName IE8 in quirks mode is unsupported
@description
This error occurs when you are using AngularJS with {@link api/ng.$sce#strictcontextualescaping 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 api/ng.$sce Strict Contextual Escaping (SCE)} mode enabled (the default) on IE8 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.
Refer {@link http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx MSDN Blogs > IEBlog > Ending Expressions} to learn more about them.
+2 -2
View File
@@ -3,7 +3,7 @@
@fullName Invalid matcher (only string patterns and RegExp instances are supported)
@description
Please see {@link api/ng.$sceDelegateProvider#resourceUrlWhitelist
Please see {@link api/ng.$sceDelegateProvider#methods_resourceUrlWhitelist
$sceDelegateProvider.resourceUrlWhitelist} and {@link
api/ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
api/ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
list of acceptable items.
+5 -5
View File
@@ -3,21 +3,21 @@
@fullName Processing of a Resource from Untrusted Source Blocked
@description
AngularJS' {@link api/ng.$sce#strictcontextualescaping Strict Contextual Escaping (SCE)} mode (enabled by default) has blocked loading a resource from an insecure URL.
AngularJS' {@link api/ng.$sce Strict Contextual Escaping (SCE)} mode (enabled by default) has blocked loading a resource from an insecure URL.
Typically, this would occur if you're attempting to load an Angular template from an untrusted source.
It's also possible that a custom directive threw this error for a similar reason.
Angular only loads templates from trusted URLs (by calling {@link api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl} on the template URL).
Angular only loads templates from trusted URLs (by calling {@link api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl} on the template URL).
By default, only URLs that belong to the same origin are trusted. These are urls with the same domain and protocol as the application document.
The {@link api/ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
To load templates from other domains and/or protocols, either adjust the {@link
api/ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
api/ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
api/ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
api/ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist}/ {@link
api/ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
api/ng.$sce#methods_trustAsResourceUrl $sce.trustAsResourceUrl}.
**Note**: The browser's {@link
https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest Same Origin
+2 -2
View File
@@ -3,6 +3,6 @@
@fullName String Value is Required for SCE Trust Call
@description
{@link api/ng.$sce#trustAs $sce.trustAs} requires a string value.
{@link api/ng.$sce#methods_trustAs $sce.trustAs} requires a string value.
Read more about {@link api/ng.$sce#strictcontextualescaping Strict Contextual Escaping (SCE)} in AngularJS.
Read more about {@link api/ng.$sce Strict Contextual Escaping (SCE)} in AngularJS.
+2 -2
View File
@@ -3,7 +3,7 @@
@fullName The sequence *** is not a valid pattern wildcard
@description
The strings in {@link api/ng.$sceDelegateProvider#resourceUrlWhitelist
The strings in {@link api/ng.$sceDelegateProvider#methods_resourceUrlWhitelist
$sceDelegateProvider.resourceUrlWhitelist} and {@link
api/ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
api/ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
contain the undefined sequence `***`. Only `*` and `**` wildcard patterns are defined.
+2 -2
View File
@@ -5,11 +5,11 @@
The value provided for use in a specific context was not found to be safe/trusted for use.
Angular's {@link api/ng.$sce#strictcontextualescaping Strict Contextual Escaping (SCE)} mode
Angular's {@link api/ng.$sce Strict Contextual Escaping (SCE)} mode
(enabled by default), requires bindings in certain
contexts to result in a value that is trusted as safe for use in such a context. (e.g. loading an
Angular template from a URL requires that the URL is one considered safe for loading resources.)
This helps prevent XSS and other security issues. Read more at {@link
api/ng.$sce#strictcontextualescaping Strict Contextual Escaping (SCE)}
api/ng.$sce Strict Contextual Escaping (SCE)}
+7 -7
View File
@@ -253,13 +253,13 @@ The table below explains in detail which animation events are triggered
| Directive | Supported Animations |
|-------------------------------------------------------------------------------------|------------------------------------------|
| {@link api/ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
| {@link api/ngRoute.directive:ngView#animations ngView} | enter and leave |
| {@link api/ng.directive:ngInclude#animations ngInclude} | enter and leave |
| {@link api/ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
| {@link api/ng.directive:ngIf#animations ngIf} | enter and leave |
| {@link api/ng.directive:ngShow#animations ngClass or &#123;&#123;class&#125;&#125;} | add and remove |
| {@link api/ng.directive:ngShow#animations ngShow & ngHide} | add and remove (the ng-hide class value) |
| {@link api/ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave, and move |
| {@link api/ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
| {@link api/ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
| {@link api/ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
| {@link api/ng.directive:ngIf#usage_animations ngIf} | enter and leave |
| {@link api/ng.directive:ngShow#usage_animations ngClass or &#123;&#123;class&#125;&#125;} | add and remove |
| {@link api/ng.directive:ngShow#usage_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 api/ngAnimate.$animate API docs}.
+4 -2
View File
@@ -51,6 +51,8 @@ initialization.
## Automatic Initialization
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
Angular initializes automatically upon `DOMContentLoaded` event or when the `angular.js` script is
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
for the {@link api/ng.directive:ngApp `ng-app`} directive which designates your application root.
@@ -114,7 +116,7 @@ This is the sequence that your code should follow:
## Deferred Bootstrap
This features enables tools like Batarang and test runners to
This feature enables tools like 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.
@@ -125,4 +127,4 @@ until `angular.resumeBootstrap()` is called.
`angular.resumeBootstrap()` takes an optional array of modules that
should be added to the original list of modules that the app was
about to be bootstrapped with.
about to be bootstrapped with.
+257 -18
View File
@@ -2,12 +2,21 @@
@name Developer Guide: HTML Compiler
@description
<div class="alert alert-warning">
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
If you're just getting started, we recommend the {@link tutorial/ tutorial} first.
If you just want to create custom directives, we recommend the {@link guide/directive directives guide}.
If you want a deeper look into Angular's compilation process, you're in the right place.
</div>
# Overview
Angular's {@link api/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
and even create new HTML elements or attributes with custom behavior. Angular calls these behavior
extensions {@link api/ng.$compileProvider#directive directives}.
extensions {@link api/ng.$compileProvider#methods_directive directives}.
HTML has a lot of constructs for formatting the HTML for static documents in a declarative fashion.
For example if something needs to be centered, there is no need to provide instructions to the
@@ -27,9 +36,9 @@ All of this compilation takes place in the web browser; no server side or pre-co
involved.
# Compiler
## Compiler
Compiler is an angular service which traverses the DOM looking for attributes. The compilation
Compiler is an Angular service which traverses the DOM looking for attributes. The compilation
process happens in two phases.
1. **Compile:** traverse the DOM and collect all of the directives. The result is a linking
@@ -44,7 +53,7 @@ for each item in a collection. Having a compile and link phase improves performa
cloned template only needs to be compiled once, and then linked once for each clone instance.
# Directive
## Directive
A directive is a behavior which should be triggered when specific HTML constructs are encountered
during the compilation process. The directives can be placed in element names, attributes, class
@@ -59,7 +68,7 @@ api/ng.directive:ngBind `ng-bind`} directive.
</pre>
A directive is just a function which executes when the compiler encounters it in the DOM. See {@link
api/ng.$compileProvider#directive directive API} for in-depth documentation on how
api/ng.$compileProvider#methods_directive directive API} for in-depth documentation on how
to write directives.
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
@@ -108,35 +117,265 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
</example>
The presence of the `draggable` attribute on any element gives the element new behavior. The beauty of
this approach is that we have taught the browser a new trick. We have extended the vocabulary of
what the browser understands in a way which is natural to anyone who is familiar with HTML
principles.
The presence of the `draggable` attribute on any element gives the element new behavior.
We extended the vocabulary of the browser in a way which is natural to anyone who is familiar with the principles of HTML.
# Understanding View
## Understanding View
There are many templating systems out there. Most of them consume a static string template and
Most other templating systems consume a static string template and
combine it with data, resulting in a new string. The resulting text is then `innerHTML`ed into
an element.
<img src="img/One_Way_Data_Binding.png">
This means that any changes to the data need to be re-merged with the template and then
`innerHTML`ed into the DOM. Some of the issues with this approach are: reading user input and merging it with data,
clobbering user input by overwriting it, managing the whole update process, and lack of behavior
expressiveness.
`innerHTML`ed into the DOM. Some of the issues with this approach are:
Angular is different. The Angular compiler consumes the DOM with directives, not string templates.
1. reading user input and merging it with data
2. clobbering user input by overwriting it
3. managing the whole update process
4. lack of behavior expressiveness
Angular is different. The Angular compiler consumes the DOM, not string templates.
The result is a linking function, which when combined with a scope model results in a live view. The
view and scope model bindings are transparent. No action from the developer is needed to update
the view. And because no `innerHTML` is used there are no issues of clobbering user input.
view and scope model bindings are transparent. The developer does not need to make any special calls to update
the view. And because `innerHTML` is not used, you won't accidentally clobber user input.
Furthermore, Angular directives can contain not just text bindings, but behavioral constructs as
well.
<img src="img/Two_Way_Data_Binding.png">
The Angular approach produces a stable DOM. This means that the DOM element instance bound to a model
The Angular approach produces a stable DOM. The DOM element instance bound to a model
item instance does not change for the lifetime of the binding. This means that the code can get
hold of the elements and register event handlers and know that the reference will not be destroyed
by template data merge.
## How directives are compiled
It's important to note that Angular operates on DOM nodes rather than strings. Usually, you don't
notice this restriction because when a page loads, the web browser parses HTML into the DOM automatically.
However it's important to keep this in mind when calling `$compile` yourself, because passing it a string
will fail. Instead, use `angular.element` to convert a string to DOM before passing elements into
Angular's `$compile` service.
HTML compilation happens in three phases:
1. {@link api/ng.$compile `$compile`} traverses the DOM and matches directives.
If the compiler finds that an element matches a directive, then the directive is added to the list of
directives that match the DOM element. A single element may match multiple directives.
2. Once all directives matching a DOM element have been identified, the compiler sorts the directives
by their `priority`.
Each directive's `compile` functions are executed. Each `compile` function has a chance to
modify the DOM. Each `compile` function returns a `link` function. These functions are composed into
a "combined" link function, which invokes each directive's returned `link` function.
3. `$compile` links the template with the scope by calling the combined linking function from the previous step.
This in turn will call the linking function of the individual directives, registering listeners on the elements
and setting up {@link api/ng.$rootScope.Scope#methods_$watch `$watch`s} with the {@link api/ng.$rootScope.Scope `scope`}
as each directive is configured to do.
The result of this is a live binding between the scope and the DOM. So at this point, a change in
a model on the compiled scope will be reflected in the DOM.
Below is the corresponding code using the `$compile` service.
This should help give you an idea of what Angular does internally.
<pre>
var $compile = ...; // injected into your code
var scope = ...;
var parent = ...; // DOM element where the compiled template can be appended
var html = '<div ng-bind="exp"></div>';
// Step 1: parse HTML into DOM element
var template = angular.element(html);
// Step 2: compile the template
var linkFn = $compile(template);
// Step 3: link the compiled template with the scope.
var element = linkFn(scope);
// Step 4: Append to DOM (optional)
parent.appendChild(element);
</pre>
### The difference between Compile and Link
At this point you may wonder why the compile process has separate compile and link phases. The
short answer is that compile and link separation is needed any time a change in a model causes
a change in the **structure** of the DOM.
It's rare for directives to have a **compile function**, since most directives are concerned with
working with a specific DOM element instance rather than changing its overall structure.
Directives often have a **link function**. A link function allows the directive to register
listeners to the specific cloned DOM element instance as well as to copy content into the DOM
from the scope.
<div class="alert alert-success">
**Best Practice:** Any operation which can be shared among the instance of directives should be
moved to the compile function for performance reasons.
</div>
#### An Example of "Compile" Versus "Link"
To understand, let's look at a real-world example with `ngRepeat`:
<pre>
Hello {{user}}, you have these actions:
<ul>
<li ng-repeat="action in user.actions">
{{action.description}}
</li>
</ul>
</pre>
When the above example is compiled, the compiler visits every node and looks for directives.
`{{user}}` matches the {@link api/ng.$interpolate interpolation directive}
and `ng-repeat` matches the {@link api/ng.directive:ngRepeat `ngRepeat` directive}.
But {@link api/ng.directive:ngRepeat ngRepeat} has a dilemma.
It needs to be able to clone new `<li>` elements for every `action` in `user.actions`.
This initially seems trivial, but it becomes more complicated when you consider that `user.actions`
might have items added to it later. This means that it needs to save a clean copy of the `<li>`
element for cloning purposes.
As new `action`s are inserted, the template `<li>` element needs to be cloned and inserted into `ul`.
But cloning the `<li>` element is not enough. It also needs to compile the `<li>` so that its
directives, like `{{action.description}}`, evaluate against the right {@link api/ng.$rootScope.Scope scope}.
A naive approach to solving this problem would be to simply insert a copy of the `<li>` element and
then compile it.
The problem with this approach is that compiling on every `<li>` element that we clone would duplicate
a lot of the work. Specifically, we'd be traversing `<li>` each time before cloning it to find the
directives. This would cause the compilation process to be slower, in turn making applications
less responsive when inserting new nodes.
The solution is to break the compilation process into two phases:
the **compile phase** where all of the directives are identified and sorted by priority,
and a **linking phase** where any work which "links" a specific instance of the
{@link api/ng.$rootScope.Scope scope} and the specific instance of an `<li>` is performed.
<div class="alert alert-warning">
**Note:** *Link* means setting up listeners on the DOM and setting up `$watch` on the Scope to
keep the two in sync.
</div>
{@link api/ng.directive:ngRepeat `ngRepeat`} works by preventing the compilation process from
descending into the `<li>` element so it can make a clone of the original and handle inserting
and removing DOM nodes itself.
Instead the {@link api/ng.directive:ngRepeat `ngRepeat`} directive compiles `<li>` separately.
The result of the `<li>` element compilation is a linking function which contains all of the
directives contained in the `<li>` element, ready to be attached to a specific clone of the `<li>`
element.
At runtime the {@link api/ng.directive:ngRepeat `ngRepeat`} watches the expression and as items
are added to the array it clones the `<li>` element, creates a new
{@link api/ng.$rootScope.Scope scope} for the cloned `<li>` element and calls the link function
on the cloned `<li>`.
### Understanding How Scopes Work with Transcluded Directives
One of the most common use cases for directives is to create reusable components.
Below is a pseudo code showing how a simplified dialog component may work.
<pre>
<div>
<button ng-click="show=true">show</button>
<dialog title="Hello {{username}}."
visible="show"
on-cancel="show = false"
on-ok="show = false; doSomething()">
Body goes here: {{username}} is {{title}}.
</dialog>
</div>
</pre>
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
data bound to `username`, and it will also have a body which we would like to transclude
into the dialog.
Here is an example of what the template definition for the `dialog` widget may look like.
<pre>
<div ng-show="visible">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
<button ng-click="onOk()">Save changes</button>
<button ng-click="onCancel()">Close</button>
</div>
</div>
</pre>
This will not render properly, unless we do some scope magic.
The first issue we have to solve is that the dialog box template expects `title` to be defined.
But we would like the template's scope property `title` to be the result of interpolating the
`<dialog>` element's `title` attribute (i.e. `"Hello {{username}}"`. Furthermore, the buttons expect
the `onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
widget. To solve the mapping issue we use the `locals` to create local variables which the template
expects as follows:
<pre>
scope: {
title: '@', // the title uses the data-binding from the parent scope
onOk: '&', // create a delegate onOk function
onCancel: '&', // create a delegate onCancel function
visible: '=' // set up visible to accept data-binding
}
</pre>
Creating local properties on widget scope creates two problems:
1. isolation - if the user forgets to set `title` attribute of the dialog widget the dialog
template will bind to parent scope property. This is unpredictable and undesirable.
2. transclusion - the transcluded DOM can see the widget locals, which may overwrite the
properties which the transclusion needs for data-binding. In our example the `title`
property of the widget clobbers the `title` property of the transclusion.
To solve the issue of lack of isolation, the directive declares a new `isolated` scope. An
isolated scope does not prototypically inherit from the parent scope, and therefore we don't have
to worry about accidentally clobbering any properties.
However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
is a child of the original scope, before the widget created an isolated scope for its local
variables. This makes the transcluded and widget isolated scope siblings.
This may seem to be unexpected complexity, but it gives the widget user and developer the least
surprise.
Therefore the final directive definition looks something like this:
<pre>
transclude: true,
scope: {
title: '@', // the title uses the data-binding from the parent scope
onOk: '&', // create a delegate onOk function
onCancel: '&', // create a delegate onCancel function
visible: '=' // set up visible to accept data-binding
},
restrict: 'E',
replace: true
</pre>
+351 -418
View File
@@ -2,450 +2,383 @@
@name Conceptual Overview
@description
# Overview
There are some concepts within Angular that you should understand before creating your first application.
This section touches all important parts of Angular really quickly using a simple example.
However, it won't explain all details.
For a more in-depth explanation, have a look at the {@link tutorial/ tutorial}.
This document gives a quick overview of the main angular components and how they work together.
These are:
| Concept | Description |
|------------------|------------------------------------------|
|{@link concepts#template Template} | HTML with additional markup |
|{@link concepts#directive Directives} | extend HTML with custom attributes and elements |
|{@link concepts#model Model} | the data that is shown to the user and with which the user interacts |
|{@link concepts#scope Scope} | context where the model is stored so that controllers, directives and expressions can access it |
|{@link concepts#expression Expressions} | access variables and functions from the scope |
|{@link concepts#compiler Compiler} | parses the template and instantiates directives and expressions |
|{@link concepts#filter Filter} | formats the value of an expression for display to the user |
|{@link concepts#view View} | what the user sees (the DOM) |
|{@link concepts#databinding Data Binding} | sync data between the model and the view |
|{@link concepts#controller Controller} | the business logic behind views |
|{@link concepts#di Dependency Injection} | Creates and wires objects / functions |
|{@link concepts#injector Injector} | dependency injection container |
|{@link concepts#module Module} | configures the Injector |
|{@link concepts#service Service} | reusable business logic independent of views |
* {@link concepts#startup startup} - bring up hello world
* {@link concepts#runtime runtime} - overview of angular runtime
* {@link concepts#scope scope} - the glue between the view and the controller
* {@link concepts#controller controller} - application behavior
* {@link concepts#model model} - your application data
* {@link concepts#view view} - what the user sees
* {@link concepts#directives directives} - extend HTML vocabulary
* {@link concepts#filters filters} - format the data in user locale
* {@link concepts#injector injector} - assembles your application
* {@link concepts#module module} - configures the injector
* {@link concepts#angular_namespace `$`} - angular namespace
<a name="startup"></a>
# Startup
# A first example: Data binding
This is how we get the ball rolling (refer to the diagram and example below):
In the following we will build a form to calculate the costs of an invoice in different currencies.
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
Let's start with input fields for quantity and cost whose values are multiplied to produce the total of the invoice:
1. The browser loads the HTML and parses it into a DOM
2. The browser loads `angular.js` script
3. Angular waits for `DOMContentLoaded` event
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
{@link guide/directive directive}, which designates the application boundary
5. The {@link guide/module Module} specified in {@link
api/ng.directive:ngApp ng-app} (if any) is used to configure
the {@link api/AUTO.$injector $injector}
6. The {@link api/AUTO.$injector $injector} is used to create the {@link
api/ng.$compile $compile} service as well as {@link
api/ng.$rootScope $rootScope}
7. The {@link api/ng.$compile $compile} service is used to compile the DOM and link
it with {@link api/ng.$rootScope $rootScope}
8. The {@link api/ng.directive:ngInit ng-init} {@link
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
scope}
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
`Hello World!`
<example>
<file name="index.html">
<p ng-init=" name='World' ">Hello {{name}}!</p>
<div ng-init="qty=1;cost=2">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="qty" required >
</div>
<div>
Costs: <input type="number" ng-model="cost" required >
</div>
<div>
<b>Total:</b> {{qty * cost | currency}}
</div>
</div>
</file>
</example>
Try out the Live Preview above, and then let's walk through the example and describe what's going on.
<a name="runtime"></a>
# Runtime
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding1.png">
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
This looks like normal HTML, with some new markup. In Angular, a file like this is called a
<a name="template">"{@link templates template}"</a>. When Angular starts your application, it parses and
processes this new markup from the template using the so called <a name="compiler">"{@link compiler compiler}"</a>.
The loaded, transformed and rendered DOM is then called the <a name="view">"view"</a>.
The diagram and the example below describe how Angular interacts with the browser's event loop.
The first kind of new markup are the so called <a name="directive">"{@link directive directives}"</a>.
They apply special behavior to attributes or elements in the HTML. In the example above we use the
{@link api/ng.directive:ngApp `ng-app`} attribute, which is linked to a directive that automatically
initializes our application. Angular also defines a directive for the {@link api/ng.directive:input `input`}
element that adds extra behavior to the element. E.g. it is able to automatically validate that the entered
text is non empty by evaluating the `required` attribute.
The {@link api/ng.directive:ngModel `ng-model`} directive stores/updates
the value of the input field into/from a variable and shows the validation state of the input field by
adding css classes. In the example we use these css classes to mark an empty input field with a red border.
1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event,
or network event (response from a server).
2. The event's callback gets executed. This enters the JavaScript context. The callback can
modify the DOM structure.
3. Once the callback executes, the browser leaves the JavaScript context and
re-renders the view based on DOM changes.
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
splits the JavaScript into classical and Angular execution context. Only operations which are
applied in Angular execution context will benefit from Angular data-binding, exception handling,
property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in
mind that in most places (controllers, services) $apply has already been called for you by the
directive which is handling the event. An explicit call to $apply is needed only when
implementing custom event callbacks, or when working with third-party library callbacks.
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
the work you wish to do in Angular execution context.
2. Angular executes the `stimulusFn()`, which typically modifies application state.
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
stabilizes, which means that the {@link api/ng.$rootScope.Scope#$evalAsync
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#$watch
$watch} list does not detect any changes.
4. The {@link api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue is used to
schedule work which needs to occur outside of current stack frame, but before the browser's
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
suffers from slowness and may cause view flickering since the browser renders the view after
each event.
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
which may have changed since last iteration. If a change is detected then the `$watch`
function is called which typically updates the DOM with the new value.
6. Once the Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
the execution leaves the Angular and JavaScript context. This is followed by the browser
re-rendering the DOM to reflect any changes.
Here is the explanation of how the `Hello world` example achieves the data-binding effect when the
user enters text into the text field.
1. During the compilation phase:
1. the {@link api/ng.directive:ngModel ng-model} and {@link
api/ng.directive:input input} {@link guide/directive
directive} set up a `keydown` listener on the `<input>` control.
2. the {@link api/ng.$interpolate &#123;&#123;name&#125;&#125; } interpolation
sets up a {@link api/ng.$rootScope.Scope#$watch $watch} to be notified of
`name` changes.
2. During the runtime phase:
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
2. The {@link api/ng.directive:input input} directive
captures the change to the input's value and calls {@link
api/ng.$rootScope.Scope#$apply $apply}`("name = 'X';")` to update the
application model inside the Angular execution context.
3. Angular applies the `name = 'X';` to the model.
4. The {@link api/ng.$rootScope.Scope#$digest $digest} loop begins
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
on the `name` property and notifies the {@link api/ng.$interpolate
&#123;&#123;name&#125;&#125; } interpolation, which in turn updates the DOM.
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
the JavaScript execution context.
7. The browser re-renders the view with update text.
<example>
<file name="index.html">
<input ng-model="name">
<p>Hello {{name}}!</p>
</file>
</example>
<a name="scope"></a>
#Scope
The {@link guide/scope scope} is responsible for detecting changes to the model section and
provides the execution context for expressions. The scopes are nested in a hierarchical structure
which closely follow the DOM structure. (See individual directive documentation to see which
directives cause a creation of new scopes.)
The following example demonstrates how the `name` {@link guide/expression expression} will evaluate
into a different value depending on which scope it is evaluated in. The example is followed by
a diagram depicting the scope boundaries.
<div class="show-scope">
<example>
<file name="index.html">
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">{{name}}</li>
</ol>
</div>
</file>
<file name="script.js">
function GreetCtrl($scope) {
$scope.name = 'World';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
</file>
<file name="style.css">
.show-scope .doc-example-live.ng-scope,
.show-scope .doc-example-live .ng-scope {
border: 1px solid red;
margin: 3px;
}
</file>
</example>
<div class="alert alert-info">
**Custom directives to access the DOM**: In Angular, the only place where an application touches the DOM is
within directives. This is good as artifacts that access the DOM are hard to test.
If you need to access the DOM directly you should write a custom directive for this. The
{@link directive directives guide} explains how to do this.
</div>
<img class="center" src="img/guide/concepts-scope.png">
The second kind of new markup are the double curly braces `{{ expression | filter }}`:
When the compiler encounters this markup, it will replace it with the evaluated value of the markup.
An <a name="expression">"{@link expression expression}"</a> in a template is a JavaScript-like code snippet that allows
to read and write variables. Note that those variables are not global variables.
Just like variables in a JavaScript function live in a scope,
Angular provides a <a name="scope">"{@link scope scope}"</a> for the variables accessible to expressions.
The values that are stored in variables on the scope are referred to as the <a name="model">"model"</a>
in the rest of the documentation.
Applied to the example above, the markup directs Angular to "take the data we got from the input widgets
and multiply them together".
The example above also contains a <a name="filter">"{@link filter filter}"</a>.
A filter formats the value of an expression for display to the user.
In the example above, the filter {@link api/ng.filter:currency `currency`} formats a number
into an output that looks like money.
The important thing in the example is that angular provides _live_ bindings:
Whenever the input values change, the value of the expressions are automatically
recalculated and the DOM is updated with their values.
The concept behind this is <a name="databinding">"{@link databinding two-way data binding}"</a>.
<a name="controller"></a>
# Controller
# Adding UI logic: Controllers
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
Let's add some more logic to the example that allows us to enter and calculate the costs in
different currencies and also pay the invoice.
A controller is the code behind the view. Its job is to construct the model and publish it to the
view along with callback methods. The view is a projection of the scope onto the template (the
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
controller.
<example module="invoice1">
<file name="invoice1.js">
angular.module('invoice1', [])
.controller('InvoiceController', function() {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = ['USD', 'EUR', 'CNY'];
this.usdToForeignRates = {
USD: 1,
EUR: 0.74,
CNY: 6.09
};
The separation of the controller and the view is important because:
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
for specifying application behavior. The controller should not contain any rendering
information (DOM references or HTML fragments).
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
specifying UI. The View should not contain any behavior.
* Since the controller is unaware of the view, there could be many views for the same
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
and testability.
<example>
<file name="index.html">
<div ng-controller="MyCtrl">
Hello {{name}}!
<button ng-click="action()">
OK
</button>
</div>
</file>
<file name="script.js">
function MyCtrl($scope) {
$scope.action = function() {
$scope.name = 'OK';
}
$scope.name = 'World';
}
</file>
</example>
<a name="model"></a>
# Model
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
The model is the data which is merged with the template to produce the view. To be able to
render the model into the view, the model has to be able to be referenced from the scope. Unlike many
other frameworks Angular makes no restrictions or requirements on the model. There are no classes
to inherit from or special accessor methods for accessing or changing the model. The model can be
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
<a name="view"></a>
# View
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
The view is what the user sees. The view begins its life as a template, is merged with the
model and finally rendered into the browser DOM. Angular takes a very different approach to
rendering the view compared to most other templating systems.
* **Others** - Most templating systems begin as an HTML string with special templating markup.
Often the template markup breaks the HTML syntax which means that the template can not be
edited by an HTML editor. The template string is then parsed by the template engine, and
merged with the data. The result of the merge is an HTML string. The HTML string is then
written to the browser using the `.innerHTML`, which causes the browser to render the HTML.
When the model changes the whole process needs to be repeated. The granularity of the template
is the granularity of the DOM updates. The key here is that the templating system manipulates
strings.
* **Angular** - Angular is different, since its templating system works on DOM objects not on
strings. The template is still written in an HTML string, but it is HTML (not HTML with
template sprinkled in.) The browser parses the HTML into the DOM, and the DOM becomes the input to
the template engine known as the {@link api/ng.$compile compiler}. The compiler
looks for {@link guide/directive directives} which in turn set up {@link
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
continuously updating view which does not need template model re-merging. Your model becomes
the single source-of-truth for your view.
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
<input ng-model="list" ng-list> <br>
<input ng-model="list" ng-list> <br>
<pre>list={{list}}</pre> <br>
<ol>
<li ng-repeat="item in list">
{{item}}
</li>
</ol>
</div>
</file>
</example>
<a name="directives"></a>
# Directives
A directive is a behavior or DOM transformation which is triggered by the presence of a custom attribute,
element name, class name or comment. A directive allows you to extend the HTML vocabulary in a
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
in HTML.
<example module="directive">
<file name="script.js">
angular.module('directive', []).directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
// view -> model
elm.on('blur', function() {
scope.$apply(function() {
ctrl.$setViewValue(elm.html());
});
});
// model -> view
ctrl.$render = function(value) {
elm.html(value);
};
// load init value from DOM
ctrl.$setViewValue(elm.html());
}
};
});
</file>
<file name="index.html">
<div contentEditable="true" ng-model="content">Edit Me</div>
<pre>model = {{content}}</pre>
</file>
<file name="style.css">
div[contentEditable] {
cursor: pointer;
background-color: #D0D0D0;
margin-bottom: 1em;
padding: 1em;
}
</file>
</example>
<a name="filters"></a>
# Filters
{@link api/ng.$filter Filters} perform data transformation. Typically
they are used in conjunction with the locale to format the data in locale specific output.
They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
Number formatting: {{ 1234567890 | number }} <br>
array filtering <input ng-model="predicate">
{{ list | filter:predicate | json }}
</div>
</file>
</example>
<a name="module"></a>
<a name="injector"></a>
# Modules and the Injector
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
The {@link api/AUTO.$injector injector} is a service locator. There is a single
{@link api/AUTO.$injector injector} per Angular {@link
api/ng.directive:ngApp application}. The {@link
api/AUTO.$injector injector} provides a way to look up an object instance by its
name. The injector keeps an internal cache of all objects so that repeated calls to get the same
object name result in the same instance. If the object does not exist, then the {@link
api/AUTO.$injector injector} asks the instance factory to create a new instance.
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
as a {@link api/AUTO.$provide provider}.
<pre>
// Create a module
var myModule = angular.module('myModule', [])
// Configure the injector
myModule.factory('serviceA', function() {
return {
// instead of {}, put your object creation here
};
});
// create an injector and configure it from 'myModule'
var $injector = angular.injector(['myModule']);
// retrieve an object from the injector by name
var serviceA = $injector.get('serviceA');
// always true because of instance cache
$injector.get('serviceA') === $injector.get('serviceA');
</pre>
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
used to {@link api/AUTO.$injector#invoke call} methods and {@link
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
allows the methods and types to ask for their dependencies instead of having to look for them.
<pre>
// You write functions such as this one.
function doSomething(serviceA, serviceB) {
// do something here.
}
// Angular provides the injector for your application
var $injector = ...;
///////////////////////////////////////////////
// the old-school way of getting dependencies.
var serviceA = $injector.get('serviceA');
var serviceB = $injector.get('serviceB');
// now call the function
doSomething(serviceA, serviceB);
///////////////////////////////////////////////
// the cool way of getting dependencies.
// the $injector will supply the arguments to the function automatically
$injector.invoke(doSomething); // This is how the framework calls your functions
</pre>
Notice that the only thing you needed to write was the function, and list the dependencies in the
function arguments. When angular calls the function, it will use the {@link
api/AUTO.$injector#invoke call} which will automatically fill the function
arguments.
Examine the `ClockCtrl` below, and notice how it lists the dependencies in the constructor. When the
{@link api/ng.directive:ngController ng-controller} instantiates
the controller it automatically provides the dependencies. There is no need to create
dependencies, look for dependencies, or even get a reference to the injector.
<example module="timeExampleModule">
<file name="index.html">
<div ng-controller="ClockCtrl">
Current time is: {{ time.now }}
</div>
</file>
<file name="script.js">
angular.module('timeExampleModule', []).
// Declare new object called time,
// which will be available for injection
factory('time', function($timeout) {
var time = {};
(function tick() {
time.now = new Date().toString();
$timeout(tick, 1000);
})();
return time;
this.total = function total(outCurr) {
return this.convertCurrency(this.qty * this.cost, this.inCurr, outCurr);
};
this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
return amount * this.usdToForeignRates[outCurr] * 1 / this.usdToForeignRates[inCurr];
};
this.pay = function pay() {
window.alert("Thanks!");
};
});
// Notice that you can simply ask for time
// and it will be provided. No need to look for it.
function ClockCtrl($scope, time) {
$scope.time = time;
}
</file>
<file name="index.html">
<div ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
</file>
</example>
What changed?
<a name="angular_namespace"></a>
# Angular Namespace
First, there is a new JavaScript file that contains a so called <a name="controller">"{@link controller controller}"</a>.
More exactly, the file contains a constructor function that creates the actual controller instance.
The purpose of controllers is to expose variables and functionality to expressions and directives.
Besides the new file that contains the controller code we also added a
{@link api/ng.directive:ngController `ng-controller`} directive to the HTML.
This directive tells angular that the new `InvoiceController` is responsible for the element with the directive
and all of the element's children.
The syntax `InvoiceController as invoice` tells Angular to instantiate the controller
and save it in the variable `invoice` in the current scope.
We also changed all expressions in the page to read and write variables within that
controller instance by prefixing them with `invoice.` . The possible currencies are defined in the controller
and added to the template using {@link api/ng.directive:ngRepeat `ng-repeat`}.
As the controller contains a `total` function
we are also able to bind the result of that function to the DOM using `{{ invoice.total(...) }}`.
Again, this binding is live, i.e. the DOM will be automatically updated
whenever the result of the function changes.
The button to pay the invoice uses the directive {@link api/ng.directive:ngClick `ngClick`}. This will evaluate the
corresponding expression whenever the button is clicked.
In the new JavaScript file we are also creating a {@link concepts#module module}
at which we register the controller. We will talk about modules in the next section.
The following graphic shows how everything works together after we introduced the controller:
<img style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding2.png">
# View independent business logic: Services
Right now, the `InvoiceController` contains all logic of our example. When the application grows it
is a good practise to move view independent logic from the controller into a so called
<a name="service">"{@link dev_guide.services service}"</a>, so it can be reused by other parts
of the application as well. Later on, we could also change that service to load the exchange rates
from the web, e.g. by calling the Yahoo Finance API, without changing the controller.
Let's refactor our example and move the currency conversion into a service in another file:
<example module="invoice2">
<file name="finance2.js">
angular.module('finance2', [])
.factory('currencyConverter', function() {
var currencies = ['USD', 'EUR', 'CNY'],
usdToForeignRates = {
USD: 1,
EUR: 0.74,
CNY: 6.09
};
return {
currencies: currencies,
convert: convert
};
function convert(amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
}
});
</file>
<file name="invoice2.js">
angular.module('invoice2', ['finance2'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
</file>
<file name="index.html">
<div ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
</file>
</example>
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-service.png">
What changed?
We moved the `convertCurrency` function and the definition of the existing currencies
into the new file `finance.js`. But how does the controller
get a hold of the now separated function?
This is where <a name="di">"{@link di Dependency Injection}"</a> comes into play.
Dependency Injection (DI) is a software design pattern that
deals with how objects and functions get created and how they get a hold of their dependencies.
Everything within Angular (directives, filters, controllers,
services, ...) is created and wired using dependency injection. Within Angular,
the DI container is called the <a name="injector">"{@link di injector}"</a>.
To use DI, there needs to be a place where all the things that should work together are registered.
In Angular, this is the purpose of the so called <a name="module">"{@link module modules}"</a>.
When Angular starts, it will use the configuration of the module with the name defined by the `ng-app` directive,
including the configuration of all modules that this module depends on.
In the example above:
The template contains the directive `ng-app="invoice2"`. This tells Angular
to use the `invoice` module as the main module for the application.
The code snippet `angular.module('invoice', ['finance'])` specifies that the `invoice` module depends on the
`finance` module. By this, Angular uses the `InvoiceController` as well as the `currencyConverter` service.
Now that Angular knows of all the parts of the application, it needs to create them.
In the previous section we saw that controllers are created using a factory function.
For services there are multiple ways to define their factory
(see the {@link dev_guide.services service guide}).
In the example above, we are using a function that returns the `currencyConverter` function as the factory
for the service.
Back to the initial question: How does the `InvoiceController` get a reference to the `currencyConverter` function?
In Angular, this is done by simply defining arguments on the constructor function. With this, the injector
is able to create the objects in the right order and pass the previously created objects into the
factories of the objects that depend on them.
In our example, the `InvoiceController` has an argument named `currencyConverter`. By this, Angular knows about the
dependency between the controller and the service and calls the controller with the service instance as argument.
The last thing that changed in the example between the previous section and this section is that we
now pass an array to the `module.controller` function, instead of a plain function. The array first
contains the names of the service dependencies that the controller needs. The last entry
in the array is the controller constructor function.
Angular uses this array syntax to define the dependencies so that the DI also works after minifying
the code, which will most probably rename the argument name of the controller constructor function
to something shorter like `a`.
# Accessing the backend
Let's finish our example by fetching the exchange rates from the Yahoo Finance API.
The following example shows how this is done with Angular:
<example module="invoice3">
<file name="invoice3.js">
angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
</file>
<file name="finance3.js">
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'http://query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK',
currencies = ['USD', 'EUR', 'CNY'],
usdToForeignRates = {};
refresh();
return {
currencies: currencies,
convert: convert,
refresh: refresh
};
function convert(amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
}
function refresh() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
});
usdToForeignRates = newUsdToForeignRates;
});
}
}]);
</file>
<file name="index.html">
<div ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
</file>
</example>
What changed?
Our `currencyConverter` service of the `finance` module now uses the
{@link api/ng.$http $http} service, a builtin service provided by Angular
for accessing the backend. It is a wrapper around [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
and [JSONP](http://en.wikipedia.org/wiki/JSONP) transports. Details can be found in the api docs of that service.
To prevent accidental name collision, Angular prefixes names of objects which could potentially
collide with `$`. Please do not use the `$` prefix in your code as it may accidentally collide
with Angular code.
@@ -1,5 +1,5 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
@name Controllers
@description
# Understanding Controllers
@@ -63,7 +63,7 @@ of the Controller on the `$scope` service provided by Angular. See the guide on
# Adding Behavior to a Scope Object
In order to react to events or execute computation in the view we must provide behavior to the
scope. We add behavior the scope by attaching methods to the `$scope` object. These methods are
scope. We add behavior to the scope by attaching methods to the `$scope` object. These methods are
then available to be called from the template/view.
The following example uses a Controller to add a method to the scope, which doubles a number:
@@ -85,7 +85,7 @@ expression in the template:
</div>
</pre>
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
As discussed in the {@link concepts Concepts} section of this guide, any
objects (or primitives) assigned to the scope become model properties. Any methods assigned to
the scope are available in the template/view, and can be invoked via angular expressions
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
@@ -105,11 +105,11 @@ Do not use Controllers for:
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
manipulation (the presentation logic of an application) is well known for being hard to test.
Putting any presentation logic into Controllers significantly affects testability of the business
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
logic. Angular offers {@link databinding databinding} for automatic DOM manipulation. If
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
{@link guide/directive directives}.
- Input formatting — Use {@link forms angular form controls} instead.
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
- Output filtering — Use {@link filter angular filters} instead.
- Sharing stateless or stateful code across Controllers — Use {@link dev_guide.services angular
services} instead.
- Managing the life-cycle of other components (for example, to create service instances).
@@ -126,7 +126,7 @@ directive} or {@link api/ngRoute.$route $route service}.
To illustrate further how Controller components work in Angular, let's create a little app with the
following components:
- A {@link dev_guide.templates template} with two buttons and a simple message
- A {@link templates template} with two buttons and a simple message
- A model consisting of a string named `spice`
- A Controller with two functions that set the value of `spice`
@@ -145,7 +145,7 @@ string "very". Depending on which button is clicked, the `spice` model is set to
var myApp = angular.module('spicyApp1', []);
myApp.controller('SpicyCtrl', ['$scope', function($scope){
$scope.spicy = 'very';
$scope.spice = 'very';
$scope.chiliSpicy = function() {
$scope.spice = 'chili';
@@ -200,7 +200,7 @@ previous example.
Notice that the `SpicyCtrl` Controller now defines just one method called `spicy`, which takes one
argument called `spice`. The template then refers to this Controller method and passes in a string
constant `'chili'` in the binding for the first button and a model property `spice` (bound to an
constant `'chili'` in the binding for the first button and a model property `customSpice` (bound to an
input box) in the second button.
## Scope Inheritance Example
@@ -221,7 +221,7 @@ more information about scope inheritance.
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="BabyCtrl">
<div ng-controller="GrandChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
</div>
</div>
@@ -242,7 +242,7 @@ more information about scope inheritance.
myApp.controller('ChildCtrl', ['$scope', function($scope){
$scope.name = 'Mattie';
}]);
myApp.controller('BabyCtrl', ['$scope', function($scope){
myApp.controller('GrandChildCtrl', ['$scope', function($scope){
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbreak Baby';
}]);
@@ -257,7 +257,7 @@ scopes being created for our view:
- The `MainCtrl` scope, which contains `timeOfDay` and `name` properties
- The `ChildCtrl` scope, which inherits the `timeOfDay` property but overrides (hides) the `name`
property from the previous
- The `BabyCtrl` scope, which overrides (hides) both the `timeOfDay` property defined in `MainCtrl`
- The `GrandChildCtrl` scope, which overrides (hides) both the `timeOfDay` property defined in `MainCtrl`
and the `name` property defined in `ChildCtrl`
Inheritance works with methods in the same way as it does with properties. So in our previous
@@ -312,7 +312,7 @@ in your test that exists in the DOM:
<pre>
describe('state', function() {
var mainScope, childScope, babyScope;
var mainScope, childScope, grandChildScope;
beforeEach(module('myApp'));
@@ -321,8 +321,8 @@ describe('state', function() {
$controller('MainCtrl', {$scope: mainScope});
childScope = mainScope.$new();
$controller('ChildCtrl', {$scope: childScope});
babyScope = childScope.$new();
$controller('BabyCtrl', {$scope: babyScope});
grandChildScope = childScope.$new();
$controller('GrandChildCtrl', {$scope: grandChildScope});
}));
it('should have over and selected', function() {
@@ -330,17 +330,11 @@ describe('state', function() {
expect(mainScope.name).toBe('Nikki');
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(babyScope.timeOfDay).toBe('evening');
expect(babyScope.name).toBe('Gingerbreak Baby');
expect(grandChildScope.timeOfDay).toBe('evening');
expect(grandChildScope.name).toBe('Gingerbreak Baby');
});
});
</pre>
## Related Topics
* {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
@@ -1,5 +1,5 @@
@ngdoc overview
@name Developer Guide: Templates: Data Binding in Angular
@name Data Binding
@description
Data-binding in Angular web apps is the automatic synchronization of data between the model and view
@@ -35,4 +35,4 @@ isolation without the view and the related DOM/browser dependency.
## Related Topics
* {@link scope Angular Scopes}
* {@link dev_guide.templates Angular Templates}
* {@link templates Angular Templates}
@@ -3,6 +3,10 @@
@name Developer Guide: E2E Testing
@description
**If you're starting a new Angular project, you may want to look into
using {@link https://github.com/angular/protractor Protractor}, as it is going to
replace the current method of E2E Testing in the near future.**
As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to
verify the correctness of new features, catch bugs and notice regressions.
@@ -37,6 +41,11 @@ it('should filter results', function() {
});
});
</pre>
Note that
[`input('user')`](https://github.com/angular/angular.js/blob/master/docs/content/guide/dev_guide.e2e-testing.ngdoc#L119)
finds the `<input>` element with `ng-model="user"` not `name="user"`.
This scenario describes the requirements of a Buzz Client, specifically, that it should be able to
filter the stream of the user. It starts by entering a value in the input field with ng-model="user", clicking
the only button on the page, and then it verifies that there are 10 items listed. It then enters
@@ -173,11 +182,6 @@ Executes the `method` passing in `key` and `value` on the element matching the g
`selector`, where `method` can be any of the following jQuery methods: `attr`, `prop`, `css`. The
`label` is used for test output.
JavaScript is a dynamically typed language which comes with great power of expression, but it also
come with almost no-help from the compiler. For this reason we feel very strongly that any code
written in JavaScript needs to come with a strong set of tests. We have built many features into
angular which makes testing your angular applications easy. So there is no excuse for not testing.
# Matchers
Matchers are used in combination with the `expect(...)` function as described above and can
-24
View File
@@ -1,24 +0,0 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular
@description
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
first appeared, Angular incorporates the basic principles behind the original {@link
http://en.wikipedia.org/wiki/Modelviewcontroller MVC} software design pattern into its way of
building client-side web applications.
The MVC pattern summarized:
* Separate applications into distinct presentation, data, and logic components
* Encourage loose coupling between these components
Along with {@link dev_guide.services services} and {@link di dependency injection}, MVC
makes angular applications better structured, easier to maintain and more testable.
The following topics explain how angular incorporates the MVC pattern into the angular way of
developing web applications:
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
@@ -1,71 +0,0 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the Model Component
@description
Depending on the context of the discussion in the Angular documentation, the term _model_ can refer to
either a single object representing one entity (for example, a model called "phones" with its value
being an array of phones) or the entire data model for the application (all entities).
In Angular, a model is any data that is reachable as a property of an angular {@link
scope Scope} object. The name of the property is the model identifier and the value is
any JavaScript object (including arrays and primitives).
The only requirement for a JavaScript object to be a model in Angular is that the object must be
referenced by an Angular scope as a property of that scope object. This property reference can be
created explicitly or implicitly.
You can create models by explicitly creating scope properties referencing JavaScript objects in the
following ways:
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
occurs in controllers:
function MyCtrl($scope) {
// create property 'foo' on the MyCtrl's scope
// and assign it an initial value 'bar'
$scope.foo = 'bar';
}
* Use an {@link expression angular expression} with an assignment operator in templates:
<button ng-click="{{foo='bar'}}">Click me</button>
* Use {@link api/ng.directive:ngInit ngInit directive} in templates (for toy/example apps
only, not recommended for real applications):
<body ng-init=" foo = 'bar' ">
Angular creates models implicitly (by creating a scope property and assigning it a suitable value)
when processing the following template constructs:
* Form input, select, textarea and other form elements:
<input ng-model="query" value="fluffy cloud">
The code above creates a model called "query" on the current scope with the value set to "fluffy
cloud".
* An iterator declaration in {@link api/ng.directive:ngRepeat ngRepeater}:
<p ng-repeat="phone in phones"></p>
The code above creates one child scope for each item in the "phones" array and creates a "phone"
object (model) on each of these scopes with its value set to the value of "phone" in the array.
In Angular, a JavaScript object stops being a model when:
* No Angular scope contains a property that references the object.
* All Angular scopes that contain a property referencing the object become stale and eligible for
garbage collection.
The following illustration shows a simple data model created implicitly from a simple template:
<img src="img/guide/about_model_final.png">
## Related Topics
* {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
@@ -1,22 +0,0 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the View Component
@description
In Angular, the view is the DOM loaded and rendered in the browser, after Angular has transformed
the DOM based on information in the template, controller and model.
<img src="img/guide/about_view_final.png">
In the Angular implementation of MVC, the view has knowledge of both the model and the controller.
The view knows about the model where two-way data-binding occurs. The view has knowledge of the
controller through Angular directives, such as {@link api/ng.directive:ngController
ngController} and {@link api/ngRoute.directive:ngView ngView}, and through bindings of this form:
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
controller function.
## Related Topics
* {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
@@ -15,14 +15,14 @@ convention they match the service IDs, which has added benefits discussed below.
<pre>
function myController($loc, $log) {
this.firstMethod = function() {
// use $location service
$loc.setHash();
};
this.secondMethod = function() {
// use $log service
$log.info('...');
};
this.firstMethod = function() {
// use $location service
$loc.setHash();
};
this.secondMethod = function() {
// use $log service
$log.info('...');
};
}
// which services to inject ?
myController.$inject = ['$location', '$log'];
@@ -13,7 +13,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s
* `ng-binding`
- **Usage:** angular applies this class to any element that is attached to a data binding, via `ng-bind` or
{{}} curly braces, for example. (see {@link guide/dev_guide.templates.databinding databinding} guide)
{{}} curly braces, for example. (see {@link guide/databinding databinding} guide)
* `ng-invalid`, `ng-valid`
- **Usage:** angular applies this class to an input widget element if that element's input does
@@ -27,5 +27,5 @@ Angular sets these CSS classes. It is up to your application to provide useful s
## Related Topics
* {@link dev_guide.templates Angular Templates}
* {@link templates Angular Templates}
* {@link forms Angular Forms}
@@ -1,60 +0,0 @@
@ngdoc overview
@name Developer Guide: Templates: Filters: Creating Angular Filters
@description
Writing your own filter is very easy: just register a new filter (injectable) factory function with
your module. This factory function should return a new filter function which takes the input value
as the first argument. Any filter arguments are passed in as additional arguments to the filter
function.
The following sample filter reverses a text string. In addition, it conditionally makes the
text upper-case.
<doc:example module="MyReverseModule">
<doc:source>
<script>
angular.module('MyReverseModule', []).
filter('reverse', function() {
return function(input, uppercase) {
var out = "";
for (var i = 0; i < input.length; i++) {
out = input.charAt(i) + out;
}
// conditional based on optional argument
if (uppercase) {
out = out.toUpperCase();
}
return out;
}
});
function Ctrl($scope) {
$scope.greeting = 'hello';
}
</script>
<div ng-controller="Ctrl">
<input ng-model="greeting" type="greeting"><br>
No filter: {{greeting}}<br>
Reverse: {{greeting|reverse}}<br>
Reverse + uppercase: {{greeting|reverse:true}}<br>
</div>
</doc:source>
<doc:scenario>
it('should reverse greeting', function() {
expect(binding('greeting|reverse')).toEqual('olleh');
input('greeting').enter('ABC');
expect(binding('greeting|reverse')).toEqual('CBA');
});
</doc:scenario>
</doc:example>
## Related Topics
* {@link dev_guide.templates.filters Understanding Angular Filters}
* {@link compiler Angular HTML Compiler}
## Related API
* {@link api/ng.$filter Angular Filter API}
@@ -1,23 +0,0 @@
@ngdoc overview
@name Developer Guide: Templates: Understanding Angular Filters
@description
Angular filters format data for display to the user.
For example, you might have a data object that needs to be formatted according to the locale before
displaying it to the user. You can pass expressions through a chain of filters like this:
name | uppercase
The expression evaluator simply passes the value of name to
{@link api/ng.filter:uppercase uppercase filter}.
## Related Topics
* {@link dev_guide.templates.filters.using_filters Using Angular Filters}
* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters}
## Related API
* {@link api/ng.$filter Angular Filter API}
@@ -1,44 +0,0 @@
@ngdoc overview
@name Developer Guide: Templates: Filters: Using Angular Filters
@description
Filters can be part of any {@link api/ng.$rootScope.Scope} evaluation but are typically used to format
expressions in bindings in your templates:
{{ expression | filter }}
Filters typically transform the data to a new data type, formatting the data in the process.
Filters can also be chained, and can take optional arguments.
You can chain filters using this syntax:
{{ expression | filter1 | filter2 }}
You can also pass colon-delimited arguments to filters, for example, to display the number 123 with
2 decimal points:
123 | number:2
Use the same syntax for multiple arguments:
myArray | orderBy:'timestamp':true
Here are some examples that show values before and after applying different filters to an
expression in a binding:
* No filter: `{{1234.5678}}` => `1234.5678`
* Number filter: `{{1234.5678|number}}` => `1,234.57`. Notice the "," and rounding to two
significant digits.
* Filter with arguments: `{{1234.5678|number:5}}` => `1,234.56780`. Filters can take optional
arguments, separated by colons in a binding. For example, the "number" filter takes a number
argument that specifies how many digits to display to the right of the decimal point.
## Related Topics
* {@link dev_guide.templates.filters Understanding Angular Filters}
* {@link dev_guide.templates.filters.creating_filters Creating Angular Filters}
## Related API
* {@link api/ng.$filter Angular Filter API}
+49 -50
View File
@@ -13,45 +13,44 @@ Unit testing as the name implies is about testing individual units of code. Unit
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order the list
in the right order?"
In order to answer such question it is very important that we can isolate the unit of code under test.
In order to answer such a question it is very important that we can isolate the unit of code under test.
That is because when we are testing the sort function we don't want to be forced into creating
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort.
While
this may seem obvious it usually is very difficult to be able to call an individual function on a
typical project. The reason is that the developers often mix concerns, and they end up with a
piece of code which does everything. It reads the data from XHR, it sorts it and then it
While this may seem obvious it can be very difficult to call an individual function on a
typical project. The reason is that the developers often mix concerns resulting in a
piece of code which does everything. It makes an XHR request, it sorts the response data and then it
manipulates the DOM.
With Angular we try to make it easy for you to do the right thing, and so we
provide dependency injection for your XHR (which you can mock out) and we created abstraction which
provide dependency injection for your XHR (which you can mock out) and we created abstractions which
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
it is easy to write a sort function which sorts some data, so that your test can create a data set,
apply the function, and assert that the resulting model is in the correct order. The test does not
have to wait for XHR, or create the right kind of DOM, or assert that your function has mutated the
DOM in the right way.
have to wait for the XHR response to arrive, create the right kind of test DOM, nor assert that your
function has mutated the DOM in the right way.
## With great power comes great responsibility
Angular is written with testability in mind, but it still requires that you
do the right thing. We tried to make the right thing easy, but Angular is not magic, which means if
you don't follow these guidelines you may very well end up with an untestable application.
Angular is written with testability in mind, but it still requires that you do the right thing.
We tried to make the right thing easy, but Angular is not magic. If you don't follow these guidelines
you may very well end up with an untestable application.
## Dependency Injection
There are several ways in which you can get a hold of a dependency:
1. You could create it using the `new` operator.
2. You could look for it in a well known place, also known as global singleton.
3. You could ask a registry (also known as service registry) for it. (But how do you get a hold of
the registry? Most likely by looking it up in a well known place. See #2)
4. You could expect that it be handed to you.
There are several ways in which you can get a hold of a dependency. You can:
1. Create it using the `new` operator.
2. Look for it in a well-known place, also known as a global singleton.
3. Ask a registry (also known as service registry) for it. (But how do you get a hold of
the registry? Most likely by looking it up in a well known place. See #2.)
4. Expect it to be handed to you.
Out of the four options in the list above, only the last one is testable. Let's look at why:
### Using the `new` operator
While there is nothing wrong with the `new` operator fundamentally the issue is that calling a new
on a constructor permanently binds the call site to the type. For example lets say that we are
trying to instantiate an `XHR` so that we can get some data from the server.
While there is nothing wrong with the `new` operator fundamentally, a problem arises when calling `new`
on a constructor. This permanently binds the call site to the type. For example, lets say that we try to
instantiate an `XHR` that will retrieve data from the server.
<pre>
function MyClass() {
@@ -64,12 +63,12 @@ function MyClass() {
}
</pre>
The issue becomes that in tests, we would very much like to instantiate a `MockXHR` which would
A problem surfaces in tests when we would like to instantiate a `MockXHR` that would
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
permanently bound to the actual XHR, and there is no good way to replace it. Yes there is monkey
patching. That is a bad idea for many reasons which are outside the scope of this document.
permanently bound to the actual XHR and there is no way to replace it. Yes, we could monkey
patch, but that is a bad idea for many reasons which are outside the scope of this document.
The class above is hard to test since we have to resort to monkey patching:
Here's an example of how the class above becomes hard to test when resorting to monkey patching:
<pre>
var oldXHR = XHR;
XHR = function MockXHR() {};
@@ -81,7 +80,7 @@ XHR = oldXHR; // if you forget this bad things will happen
### Global look-up:
Another way to approach the problem is to look for the service in a well known location.
Another way to approach the problem is to look for the service in a well-known location.
<pre>
function MyClass() {
@@ -95,14 +94,14 @@ function MyClass() {
}
</pre>
While no new instance of the dependency is being created, it is fundamentally the same as `new`, in
that there is no good way to intercept the call to `global.xhr` for testing purposes, other then
While no new dependency instance is created, it is fundamentally the same as `new` in
that no way exists to intercept the call to `global.xhr` for testing purposes, other then
through monkey patching. The basic issue for testing is that a global variable needs to be mutated in
order to replace it with call to a mock method. For further explanation why this is bad see: {@link
order to replace it with call to a mock method. For further explanation of why this is bad see: {@link
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global
State & Singletons}
The class above is hard to test since we have to change global state:
The class above is hard to test since we have to change the global state:
<pre>
var oldXHR = global.xhr;
global.xhr = function mockXHR() {};
@@ -115,7 +114,7 @@ global.xhr = oldXHR; // if you forget this bad things will happen
### Service Registry:
It may seem as that this can be solved by having a registry for all of the services, and then
It may seem that this can be solved by having a registry of all the services and then
having the tests replace the services as needed.
<pre>
@@ -131,12 +130,12 @@ function MyClass() {
}
</pre>
However, where does the serviceRegistry come from? if it is:
* `new`-ed up, the the test has no chance to reset the services for testing
* global look-up, then the service returned is global as well (but resetting is easier, since
there is only one global variable to be reset).
However, where does the serviceRegistry come from? If it is:
* `new`-ed up, the test has no chance to reset the services for testing.
* a global look-up then the service returned is global as well (but resetting is easier, since
only one global variable exists to be reset).
The class above is hard to test since we have to change global state:
The class above is hard to test since we have to change the global state:
<pre>
var oldServiceLocator = global.serviceLocator;
global.serviceLocator.set('xhr', function mockXHR() {});
@@ -148,7 +147,7 @@ global.serviceLocator = oldServiceLocator; // if you forget this bad things will
### Passing in Dependencies:
Lastly the dependency can be passed in.
Last, the dependency can be passed in.
<pre>
function MyClass(xhr) {
@@ -161,12 +160,12 @@ function MyClass(xhr) {
}
</pre>
This is the preferred way since the code makes no assumptions as to where the `xhr` comes from,
rather that whoever created the class was responsible for passing it in. Since the creator of the
This is the preferred method since the code makes no assumptions about the origin of `xhr` and cares
instead about whoever created the class responsible for passing it in. Since the creator of the
class should be different code than the user of the class, it separates the responsibility of
creation from the logic, and that is what dependency-injection is in a nutshell.
creation from the logic. This is dependency-injection is in a nutshell.
The class above is very testable, since in the test we can write:
The class above is testable, since in the test we can write:
<pre>
function xhrMock(args) {...}
var myClass = new MyClass(xhrMock);
@@ -176,12 +175,12 @@ myClass.doWork();
Notice that no global variables were harmed in the writing of this test.
Angular comes with {@link di dependency injection} built in which makes the right thing
Angular comes with {@link di dependency injection} built-in, making the right thing
easy to do, but you still need to do it if you wish to take advantage of the testability story.
## Controllers
What makes each application unique is its logic, which is what we would like to test. If the logic
for your application is mixed in with DOM manipulation, it will be hard to test as in the example
What makes each application unique is its logic, and the logic is what we would like to test. If the logic
for your application contains DOM manipulation, it will be hard to test. See the example
below:
<pre>
@@ -209,7 +208,7 @@ function PasswordCtrl() {
}
</pre>
The code above is problematic from a testability point of view, since it requires your test to have the right kind
The code above is problematic from a testability point of view since it requires your test to have the right kind
of DOM present when the code executes. The test would look like this:
<pre>
@@ -226,8 +225,8 @@ expect(span.text()).toEqual('weak');
$('body').html('');
</pre>
In angular the controllers are strictly separated from the DOM manipulation logic which results in
a much easier testability story as can be seen in this example:
In angular the controllers are strictly separated from the DOM manipulation logic and this results in
a much easier testability story as the following example shows:
<pre>
function PasswordCtrl($scope) {
@@ -245,7 +244,7 @@ function PasswordCtrl($scope) {
}
</pre>
and the test is straight forward
and the test is straight forward:
<pre>
var $scope = {};
@@ -255,11 +254,11 @@ $scope.grade();
expect($scope.strength).toEqual('weak');
</pre>
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
Notice that the test is not only much shorter, it is also easier to follow what is happening. We say
that such a test tells a story, rather then asserting random bits which don't seem to be related.
## Filters
{@link api/ng.$filter Filters} are functions which transform the data into user readable
{@link api/ng.$filterProvider Filters} are functions which transform the data into a user readable
format. They are important because they remove the formatting responsibility from the application
logic, further simplifying the application logic.
@@ -282,7 +281,7 @@ you create with directives may be used throughout your application and in many d
### Simple HTML Element Directive
Lets start with an angular app with no dependencies.
Let's start with an angular app with no dependencies.
<pre>
var app = angular.module('myApp', []);
+3 -1
View File
@@ -47,6 +47,8 @@ is simply handed the `greeter` at runtime.
This is desirable, but it puts the responsibility of getting hold of the dependency on the
code that constructs `SomeClass`.
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
To manage the responsibility of dependency creation, each Angular application has an {@link
api/angular.injector injector}. The injector is a service locator that is responsible for
construction and lookup of dependencies.
@@ -144,7 +146,7 @@ of service names to inject.
var MyController = function(renamed$scope, renamedGreeter) {
...
}
MyController.$inject = ['$scope', 'greeter'];
MyController['$inject'] = ['$scope', 'greeter'];
</pre>
In this scenario the ordering of the values in the '$inject' array must match the ordering of the arguments to inject.
File diff suppressed because it is too large Load Diff
+3 -41
View File
@@ -4,12 +4,11 @@
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
expression }}`. Expressions are processed by the {@link api/ng.$parse $parse}
service.
service. Expressions are often post processed using {@link filter filters} to create a more user-friendly format.
For example, these are all valid expressions in angular:
* `1+2`
* `3*10 | currency`
* `user.name`
@@ -29,12 +28,9 @@ You can think of Angular expressions as JavaScript expressions with following di
* **No Control Flow Statements:** you cannot do any of the following in angular expression:
conditionals, loops, or throw.
* **Filters:** you can pass result of expression evaluations through filter chains. For example
to convert date object into a local specific human-readable format.
If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
controller method and call the method. If you want to `eval()` an angular expression from
JavaScript, use the {@link api/ng.$rootScope.Scope#$eval `$eval()`} method.
JavaScript, use the {@link api/ng.$rootScope.Scope#methods_$eval `$eval()`} method.
## Example
<doc:example>
@@ -70,7 +66,7 @@ You can try evaluating different expressions here:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
<ul>
<li ng-repeat="expr in exprs">
<li ng-repeat="expr in exprs track by $index">
[ <a href="" ng-click="removeExp($index)">X</a> ]
<tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
@@ -150,37 +146,3 @@ You cannot write a control flow statement in an expression. The reason behind th
Angular philosophy that application logic should be in controllers, not in the view. If you need a
conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.
## Filters
When presenting data to the user, you might need to convert the data from its raw format to a
user-friendly format. For example, you might have a data object that needs to be formatted
according to the locale before displaying it to the user. You can pass expressions through a chain
of filters like this:
name | uppercase
The expression evaluator simply passes the value of name to {@link
api/ng.filter:uppercase `uppercase`} filter.
Chain filters using this syntax:
value | filter1 | filter2
You can also pass colon-delimited arguments to filters, for example, to display the number 123
with 2 decimal points:
123 | number:2
# The $
You might be wondering, what is the significance of the $ prefix? It is simply a prefix that
angular uses, to differentiate its API names from others. If angular didn't use $, then evaluating
`a.length()` would return undefined because neither a nor angular define such a property.
Consider that in a future version of Angular we might choose to add a length method, in which case
the behavior of the expression would change. Worse yet, you, the developer, could create a length
property and then we would have a collision. This problem exists because Angular augments existing
objects with additional behavior. By prefixing its additions with $ we are reserving our namespace
so that angular developers and developers who use Angular can develop in harmony without collisions.
+123
View File
@@ -0,0 +1,123 @@
@ngdoc overview
@name Filters
@description
A filter formats the value of an expression for display to the user. They can be used in view templates,
controllers or services and it is easy to define your own filter.
The underlying API is the {@link api/ng.$filterProvider filterProvider}.
## Using filters in view templates
Filters can be applied to expressions in view templates using the following syntax:
{{ expression | filter }}
E.g. the markup `{{ 12 | currency }}` formats the number 12 as a currency using the {@link api/ng.filter:currency `currency`}
filter. The resulting value is `$12.00`.
Filters can be applied to the result of another filter. This is called "chaining" and uses
the following syntax:
{{ expression | filter1 | filter2 | ... }}
Filters may have arguments. The syntax for this is
{{ expression | filter:argument1:argument2:... }}
E.g. the markup `{{ 1234 | number:2 }}` formats the number 1234 with 2 decimal points using the
{@link api/ng.filter:number `number`} filter. The resulting value is `1,234.00`.
## Using filters in controllers and services
You can also use filters in controllers and services. For this, add a dependency with the name `<filterName>Filter`
to your controller or service. E.g. using the dependency `numberFilter` will inject the number filter.
The injected argument is a function that takes the value to format as first argument and filter parameters
starting with the second argument.
The example below uses the filter called {@link api/ng.filter:filter `filter`}.
This filter reduces arrays into sub arrays based on
conditions. The filter can be applied in the view template with markup like
`{{ctrl.array | filter:'a'}}`, which would do a fulltext search for "a".
However, using a filter in a view template will reevaluate the filter on
every digest, which can be costly if the array is big.
The example below therefore calls the filter directly in the controller.
By this, the controller is able to call the filter only when needed (e.g. when the data is loaded from the backend
or the filter expression is changed).
<doc:example module="FilterInControllerModule">
<doc:source>
<script>
angular.module('FilterInControllerModule', []).
controller('FilterController', ['filterFilter', function(filterFilter) {
this.array = [
{name: 'Tobias'},
{name: 'Jeff'},
{name: 'Brian'},
{name: 'Igor'},
{name: 'James'},
{name: 'Brad'}
];
this.filteredArray = filterFilter(this.array, 'a');
}]);
</script>
<div ng-controller="FilterController as ctrl">
<div>
All entries:
<span ng-repeat="entry in ctrl.array">{{entry.name}} </span>
</div>
<div>
Entries that contain an "a":
<span ng-repeat="entry in ctrl.filteredArray">{{entry.name}} </span>
</div>
</div>
</doc:source>
</doc:example>
## Creating custom filters
Writing your own filter is very easy: just register a new filter factory function with
your module. Internally, this uses the {@link api/ng.$filterProvider `filterProvider`}.
This factory function should return a new filter function which takes the input value
as the first argument. Any filter arguments are passed in as additional arguments to the filter
function.
The following sample filter reverses a text string. In addition, it conditionally makes the
text upper-case.
<doc:example module="MyReverseModule">
<doc:source>
<script>
angular.module('MyReverseModule', []).
filter('reverse', function() {
return function(input, uppercase) {
var out = "";
for (var i = 0; i < input.length; i++) {
out = input.charAt(i) + out;
}
// conditional based on optional argument
if (uppercase) {
out = out.toUpperCase();
}
return out;
}
});
function Ctrl($scope) {
$scope.greeting = 'hello';
}
</script>
<div ng-controller="Ctrl">
<input ng-model="greeting" type="greeting"><br>
No filter: {{greeting}}<br>
Reverse: {{greeting|reverse}}<br>
Reverse + uppercase: {{greeting|reverse:true}}<br>
</div>
</doc:source>
</doc:example>
+4 -4
View File
@@ -186,11 +186,11 @@ To get a hold of the controller the directive specifies a dependency as shown in
The validation can occur in two places:
* **Model to View update** -
Whenever the bound model changes, all functions in {@link api/ng.directive:ngModel.NgModelController#$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 api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
Whenever the bound model changes, all functions in {@link api/ng.directive: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 api/ng.directive:ngModel.NgModelController#methods_$setValidity NgModelController#$setValidity}.
* **View to Model update** -
In a similar way, whenever a user interacts with a control it calls {@link api/ng.directive:ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
This in turn pipelines all functions in the {@link api/ng.directive:ngModel.NgModelController#$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 api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
In a similar way, whenever a user interacts with a control it calls {@link api/ng.directive:ngModel.NgModelController#methods_$setViewValue NgModelController#$setViewValue}.
This in turn pipelines all functions in the {@link api/ng.directive: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 api/ng.directive:ngModel.NgModelController#methods_$setValidity NgModelController#$setValidity}.
In the following example we create two directives.
@@ -278,7 +278,7 @@ However, if you need more flexibility, you can write your own form control as a
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#$formatters NgModelController#$formatters},
- 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.
See {@link guide/directive $compileProvider.directive} for more info.
+1 -1
View File
@@ -43,7 +43,7 @@ http://userguide.icu-project.org/locale ICU } website for more information about
**Supported locales in Angular**
Angular separates number and datetime format rule sets into different files, each file for a
particular locale. You can find a list of currently supported locales {@link
https://github.com/angular/angular.js/tree/master/i18n/locale here}
https://github.com/angular/angular.js/tree/master/src/ngLocale here}
# Providing locale rules to Angular
There are two approaches to providing locale rules to Angular:
+13 -2
View File
@@ -8,6 +8,17 @@ This document describes the Internet Explorer (IE) idiosyncrasies when dealing w
attributes and tags. Read this document if you are planning on deploying your Angular application
on IE v8.0 or earlier.
The project currently supports and will attempt to fix bugs for IE8 and above. The continuous
integration server runs all the tests against IE8. See http://ci.angularjs.org.
IE7 and below are not tested and the project makes no guarantee that Angular will work on it.
A subset of the AngularJS functionality may work. It is up to you to test and decide whether
it works for your particular app.
It is very unlikely that issues specific to IE7 or earlier will be given any time by the core team.
[GitHub](https://github.com/angular/angular.js/issues/4974)
# Short Version
To make your Angular application work on IE please make sure that:
@@ -80,7 +91,7 @@ The **important** parts are:
IE has issues with element tag names which are not standard HTML tag names. These fall into two
categories, and each category has its own fix.
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
* If the tag name starts with `my:` prefix then it is considered an XML namespace and must
have corresponding namespace declaration on `<html xmlns:my="ignored">`
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
@@ -164,7 +175,7 @@ To make CSS selectors work with custom elements, the custom element name must be
</script>
<![endif]-->
<style>
ng\\:view {
ng\:view {
display: block;
border: 1px solid red;
}
+177 -6
View File
@@ -2,11 +2,182 @@
@name Developer Guide
@description
Welcome to the angular Developer Guide. If you are here to learn the details of how to use angular
to develop web apps, you've come to the right place.
# Guide to AngularJS Documentation
If you are completely or relatively unfamiliar with angular, you may want to check out one or both
of the following documents before returning here to the Developer Guide:
Everything you need to know about AngularJS
* {@link guide/introduction What is AngularJS?}
* {@link guide/concepts Conceptual Overview}
## Tutorials
* {@link tutorial/index Official AngularJS Tutorial}
* [10 Reasons Why You Should Use AngularJS](http://www.sitepoint.com/10-reasons-use-angularjs/)
* [Design Principles of AngularJS (video)](https://www.youtube.com/watch?v=HCR7i5F5L8c)
* [Fundamentals in 60 Minutes (video)](http://www.youtube.com/watch?v=i9MHigUZKEM)
* [For folks with jQuery background](http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background)
## Core Concepts
### Templates
In Angular applications, you move the job of filling page templates with data from the server to the client. The result is a system better structured for dynamic page updates. Below are the core features you'll use.
* {@link guide/databinding Data binding}
* {@link guide/expression Expressions}
* {@link guide/directive Directives}
* {@link api/ngRoute.$route Views and routes (see the example)}
* {@link guide/filter Filters}
* {@link guide/forms Forms} and [Concepts of AngularJS Forms](http://mrbool.com/the-concepts-of-angularjs-forms/29117)
### Application Structure
* **Blog post: **[When to use directives, controllers or services](http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/)
* **App wiring:** {@link guide/di Dependency injection}
* **Exposing model to templates:** {@link guide/scope Scopes}
* **Communicating with servers:** {@link api/ng.$http $http}, {@link api/ngResource.$resource $resource}
### Other AngularJS Features
* **Animation:** {@link guide/animations Core concepts}, {@link api/ngAnimate ngAnimate API}, and [Animation in AngularJS 1.2](http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html)
* **Security:** {@link api/ng.$sce Strict Contextual Escaping}, {@link api/ng.directive:ngCsp Content Security Policy}, {@link api/ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
* **Internationalization and Localization:** {@link guide/i18n Angular Guide to i18n and l10n}, {@link api/ng.filter:date date filter}, {@link api/ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
* **Mobile:** {@link api/ngTouch Touch events}
### Testing
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/dev_guide.unit-testing Unit testing}, {@link guide/dev_guide.services.testing_services Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
* **Scenario testing:** [Protractor](https://github.com/angular/protractor)
## Specific Topics
* **Login: **[Google example](https://developers.google.com/+/photohunt/python), [Facebook example](http://blog.brunoscopelliti.com/facebook-authentication-in-your-angularjs-web-app), [authentication strategy](http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app), [unix-style authorization](http://frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/)
* **Mobile:** [Angular on Mobile Guide](http://www.ng-newsletter.com/posts/angular-on-mobile.html), [PhoneGap](http://devgirl.org/2013/06/10/quick-start-guide-phonegap-and-angularjs/)
* **Other Languages:** [CoffeeScript](http://www.coffeescriptlove.com/2013/08/angularjs-and-coffeescript-tutorials.html), [Dart](https://github.com/angular/angular.dart.tutorial/wiki)
* **Realtime: **[Socket.io](http://www.creativebloq.com/javascript/angularjs-collaboration-board-socketio-2132885), [OmniBinder](https://github.com/jeffbcross/omnibinder)
* **Visualization:** [SVG](http://gaslight.co/blog/angular-backed-svgs), [D3.js](http://www.ng-newsletter.com/posts/d3-on-angular.html)
## Tools
* **Debugging:** [Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en)
* **Testing:** [Karma](http://karma-runner.github.io), [Protractor](https://github.com/angular/protractor)
* **Editor support:** [Webstorm](http://plugins.jetbrains.com/plugin/6971) (and [video](http://www.youtube.com/watch?v=LJOyrSh1kDU)), [Sublime Text](https://github.com/angular-ui/AngularJS-sublime-package), [Visual Studio](http://madskristensen.net/post/angularjs-intellisense-in-visual-studio-2012)
* **Workflow:** [Yeoman.io](https://github.com/yeoman/generator-angular) and [Angular Yeoman Tutorial](http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower/)
## Complementary Libraries
This is a short list of libraries with specific support and documentation for working with Angular. You can find a full list of all known Angular external libraries at [ngmodules.org](http://ngmodules.org/).
* **Internationalization:** [angular-translate](http://pascalprecht.github.io/angular-translate/), [angular-gettext](http://angular-gettext.rocketeer.be/)
* **RESTful services:** [Restangular](https://github.com/mgonto/restangular)
* **SQL and NoSQL backends:** [BreezeJS](http://www.breezejs.com/), [AngularFire](http://angularfire.com/)
* **UI Widgets: **[KendoUI](http://kendo-labs.github.io/angular-kendo/#/), [UI Bootstrap](http://angular-ui.github.io/bootstrap/), [Wijmo](http://wijmo.com/tag/angularjs-2/)
## Deployment
### General
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ngmin automation tool](http://www.thinkster.io/pick/XlWneEZCqY/angularjs-ngmin)
* **Tracking:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Logging Client-Side Errors](http://www.bennadel.com/blog/2542-Logging-Client-Side-Errors-With-AngularJS-And-Stacktrace-js.htm)
* **SEO:** [By hand](http://www.yearofmoo.com/2012/11/angularjs-and-seo.html), [prerender.io](http://prerender.io/), [Brombone](http://www.brombone.com/), [SEO.js](http://getseojs.com/), [SEO4Ajax](http://www.seo4ajax.com/)
### Server-Specific
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html)
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/resources/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
* **Hood.ie:** [60 Minutes to Awesome](http://www.roberthorvick.com/2013/06/30/todomvc-angularjs-hood-ie-60-minutes-to-awesome/)
* **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)
## Learning Resources
###Books
* [AngularJS](http://www.amazon.com/AngularJS-Brad-Green/dp/1449344852) by Brad Green and Shyam Seshadri
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
###Videos:
* [egghead.io](http://egghead.io/),
* [Angular on YouTube](http://youtube.com/angularjs)
###Courses
* **Free on-line:**
[thinkster.io](http://thinkster.io),
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1)
* **Paid on-line:**
[Pluralsite (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html)
* **Paid on-site:**
[angularbootcamp.com](http://angularbootcamp.com/)
## Getting Help
The recipe for getting help on your unique issue is to create an example that could work (even if it doesn't) in a shareable example on [Plunker](http://plnkr.co/), [JSFiddle](http://jsfiddle.net/), or similar site and then post to one of the following:
* [Stackoverflow.com](http://stackoverflow.com/search?q=angularjs)
* [AngularJS mailing list](https://groups.google.com/forum/#!forum/angular)
* [AngularJS IRC channel](http://webchat.freenode.net/?channels=angularjs&uio=d4)
## Social Channels
* **Daily updates:** [Google+](https://plus.google.com/u/0/+AngularJS) or [Twitter](https://twitter.com/angularjs)
* **Weekly newsletter:** [ng-newsletter](http://www.ng-newsletter.com/)
* **Meetups: **[meetup.com](http://www.meetup.com/find/?keywords=angularJS&radius=Infinity&userFreeform=San+Francisco%2C+CA&mcId=z94108&mcName=San+Francisco%2C+CA&sort=member_count&eventFilter=mysugg)
* **Official news and releases: **[AngularJS Blog](http://blog.angularjs.org/)
## Contributing to AngularJS
Though we have a core group of core contributors at Google, Angular is an open source project with hundreds of contributors. We'd love you to be one of them. When you're ready, please read the {@link misc/contribute Guide for contributing to AngularJS}.
## Final Bits
Didn't find what you're looking for here? Check out [AngularJS-Learning](https://github.com/jmcunningham/AngularJS-Learning) for an even more comprehensive list of links to videos, tutorials, and blog posts.
If you have awesome AngularJS resources that belong on this page, please tell us about them on [Google+](https://plus.google.com/u/0/+AngularJS) or [Twitter](https://twitter.com/angularjs).
* {@link misc/started Getting Started}
* {@link tutorial/index Angular Tutorial}
+96 -30
View File
@@ -1,42 +1,108 @@
@ngdoc overview
@name Developer Guide: Introduction
@name Introduction
@description
Angular is pure client-side technology, written entirely in JavaScript. It works with the
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of
web apps easier and faster than ever before.
One important way that Angular simplifies web development is by increasing the level of abstraction
between the developer and most low-level web app development tasks. Angular automatically takes
care of many of these tasks, including:
# What Is Angular?
* DOM Manipulation
* Setting Up Listeners and Notifiers
* Input Validation
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
language and lets you extend HTML's syntax to express your application's components clearly and
succinctly. Out of the box, it eliminates much of the code you currently write through data
binding and dependency injection. And it all happens in JavaScript within the browser, making it
an ideal partner with any server technology.
Because Angular handles much of the work involved in these tasks, developers can concentrate more
on application logic and less on repetitive, error-prone, lower-level coding.
Angular is what HTML would have been had it been designed for applications. HTML is a great
declarative language for static documents. It does not contain much in the way of creating
applications, and as a result building web applications is an exercise in *what do I have to do
to trick the browser into doing what I want.*
At the same time that Angular simplifies the development of web apps, it brings relatively
sophisticated techniques to the client-side, including:
The impedance mismatch between dynamic applications and static documents is often solved with:
* Separation of data, application logic, and presentation components
* Data Binding between data and presentation components
* Services (common web app operations, implemented as substitutable objects)
* Dependency Injection (used primarily for wiring together services)
* An extensible HTML compiler (written entirely in JavaScript)
* Ease of Testing
* **a library** - a collection of functions which are useful when writing web apps. Your code is
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
* **frameworks** - a particular implementation of a web application, where your code fills in
the details. The framework is in charge and it calls into your code when it needs something
app specific. E.g., `knockout`, `ember`, etc.
These techniques have been for the most part absent from the client-side for far too long.
## Single-page / Round-trip Applications
Angular takes another approach. It attempts to minimize the impedance mismatch between document
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
browser new syntax through a construct we call directives. Examples include:
You can use Angular to develop both single-page and round-trip apps, but Angular is designed
primarily for developing single-page apps. Angular supports browser history, forward and back
buttons, and bookmarking in single-page apps.
* Data binding, as in `{{}}`.
* DOM control structures for repeating/hiding DOM fragments.
* Support for forms and form validation.
* Attaching code-behind to DOM elements.
* Grouping of HTML into reusable components.
## A complete client-side solution
Angular is not a single piece in the overall puzzle of building the client-side of a web
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
well-defined structure. This makes Angular opinionated about how a CRUD application should be
built. But while it is opinionated, it also tries to make sure that its opinion is just a
starting point you can easily change. Angular comes with the following out-of-the-box:
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
directives, form validation, routing, deep-linking, reusable components, dependency injection.
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
* Seed application with directory layout and test scripts as a starting point.
## Angular Sweet Spot
Angular simplifies application development by presenting a higher level of abstraction to the
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
applications represent the majority of web applications. To understand what Angular is
good at, though, it helps to understand when an app is not a good fit for Angular.
Games and GUI editors are examples of applications with intensive and tricky DOM manipulation.
These kinds of apps are different from CRUD apps, and as a result are probably not a good fit for Angular.
In these cases it may be better to use a library with a lower level of abstraction, such as `jQuery`.
# The Zen of Angular
Angular is built around the belief that declarative code is better than imperative when it comes
to building UIs and wiring software components together, while imperative code is excellent for
expressing business logic.
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
the testability of the code.
* It is a really, _really_ good idea to regard app testing as equal in importance to app
writing. Testing difficulty is dramatically affected by the way the code is structured.
* It is an excellent idea to decouple the client side of an app from the server side. This
allows development work to progress in parallel, and allows for reuse of both sides.
* It is very helpful indeed if the framework guides developers through the entire journey of
building an app: from designing the UI, through writing the business logic, to testing.
* It is always good to make common tasks trivial and difficult tasks possible.
Angular frees you from the following pains:
* **Registering callbacks:** Registering callbacks clutters your code, making it hard to see the
forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It
vastly reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see
what your application does.
* **Manipulating HTML DOM programmatically:** Manipulating HTML DOM is a cornerstone of AJAX
applications, but it's cumbersome and error-prone. By declaratively describing how the UI
should change as your application state changes, you are freed from low-level DOM manipulation
tasks. Most applications written with Angular never have to programmatically manipulate the
DOM, although you can if you want to.
* **Marshaling data to and from the UI:** CRUD operations make up the majority of AJAX
applications' tasks. The flow of marshaling data from the server to an internal object to an HTML
form, allowing users to modify the form, validating the form, displaying validation errors,
returning to an internal model, and then back to the server, creates a lot of boilerplate
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
overall flow of the application rather than all of the implementation details.
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
your app easily using services, which are auto-injected into your application in a {@link
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
to get started developing features quickly. As a bonus, you get full control over the
initialization process in automated tests.
You normally wouldn't want to load Angular with every page change, as would be the case with using
Angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
Angular's features (for example, templates to leverage angular's data-binding feature) to an
existing round-trip app. You might follow this course of action if you were migrating an older app
to a single-page Angular app.
+655
View File
@@ -0,0 +1,655 @@
@ngdoc overview
@name Migrating from 1.0 to 1.2
@description
AngularJS version 1.2 introduces several breaking changes that may require changes to your
application's source code.
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
AngularJS 1.2 has undergone a thourough security review to make applications safer by default,
which has driven many of these changes. Several new features, especially animations, would not
be possible without a few changes. Finally, some outstanding bugs were best fixed by changing
an existing API.
<div class="alert alert-warning">
<p>**Note:** AngularJS versions 1.1.x are considered "experimental" with breaking changes between minor releases.
Version 1.2 is the result of several versions on the 1.1 branch, and has a stable API.</p>
<p>If you have an application on 1.1 and want to migrate it to 1.2, everything in the guide
below should still apply, but you may want to consult the
[changelog](https://github.com/angular/angular.js/blob/master/CHANGELOG.md) as well.</p>
</div>
<ul class="nav nav-list">
<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> or <code>*[ng-src]</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#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-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#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>
<li>{@link guide/migration#directives-order-of-postlink-functions-reversed Directives: Order of postLink functions reversed}</li>
<li>{@link guide/migration#directive-priority Directive priority}</li>
<li>{@link guide/migration#ngscenario ngScenario}</li>
<li>{@link guide/migration#nginclude-and-ngview-replace-its-entire-element-on-update ngInclude and ngView replace its entire element on update}</li>
<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-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#uncommon-region-specific-local-files-were-removed-from-i18n Uncommon region-specific local files were removed from i18n}</li>
</ul>
## ngRoute has been moved into its own module
Just like `ngResource`, `ngRoute` is now its own module.
Applications that use `$route`, `ngView`, and/or `$routeParams` will now need to load an
`angular-route.js` file and have their application's module dependency on the `ngRoute` module.
Before:
```html
<script src="angular.js"></script>
```
```javascript
var myApp = angular.module('myApp', ['someOtherModule']);
```
After:
```html
<script src="angular.js"></script>
<script src="angular-route.js"></script>
```
```javascript
var myApp = angular.module('myApp', ['ngRoute', 'someOtherModule']);
```
See [5599b55b](https://github.com/angular/angular.js/commit/5599b55b04788c2e327d7551a4a699d75516dd21).
## Templates no longer automatically unwrap promises
`$parse` and templates in general will no longer automatically unwrap promises.
Before:
```javascript
$scope.foo = $http({method: 'GET', url: '/someUrl'});
```
```html
<p>{{foo}}</p>
```
After:
```javascript
$http({method: 'GET', url: '/someUrl'})
.success(function(data) {
$scope.foo = data;
});
```
```html
<p>{{foo}}</p>
```
This feature has been deprecated. If absolutely needed, it can be reenabled for now via the
`$parseProvider.unwrapPromises(true)` API.
See [5dc35b52](https://github.com/angular/angular.js/commit/5dc35b527b3c99f6544b8cb52e93c6510d3ac577),
[b6a37d11](https://github.com/angular/angular.js/commit/b6a37d112b3e1478f4d14a5f82faabf700443748).
## Syntax for named wildcard parameters changed in `$route`
To migrate the code, follow the example below. Here, `*highlight` becomes `:highlight*`
Before:
```javascript
$routeProvider.when('/Book1/:book/Chapter/:chapter/*highlight/edit',
{controller: noop, templateUrl: 'Chapter.html'});
```
After:
```javascript
$routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit',
{controller: noop, templateUrl: 'Chapter.html'});
```
See [04cebcc1](https://github.com/angular/angular.js/commit/04cebcc133c8b433a3ac5f72ed19f3631778142b).
## You can only bind one expression to `*[src]` or `*[ng-src]`
With the exception of `<a>` and `<img>` elements, you cannot bind more than one expression to the
`src` attribute of elements.
This is one of several improvements to security introduces by Angular 1.2.
Concatenating expressions makes it hard to understand whether some combination of concatenated
values are unsafe to use and potentially subject to XSS vulnerabilities. To simplify the task of
auditing for XSS issues, we now require that a single expression be used for `*[src/ng-src]`
bindings such as bindings for `iframe[src]`, `object[src]`, etc.
<table class="table table-bordered code-table">
<thead>
<tr>
<th>Examples</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&lt;img src="{{a}}/{{b}}"&gt;</code></td>
<td class="success">ok</td>
</tr>
<tr>
<td><code>&lt;iframe src="{{a}}/{{b}}"&gt;&lt;/iframe&gt;</code></td>
<td class="error">bad</td>
</tr>
<tr>
<td><code>&lt;iframe src="{{a}}"&gt;&lt;/iframe&gt;</code></td>
<td class="success">ok</td>
</tr>
</tbody>
</table>
To migrate your code, you can combine multiple expressions using a method attached to your scope.
Before:
```javascript
scope.baseUrl = 'page';
scope.a = 1;
scope.b = 2;
```
```html
<!-- Are a and b properly escaped here? Is baseUrl controlled by user? -->
<iframe src="{{baseUrl}}?a={{a}&b={{b}}">
```
After:
```javascript
var baseUrl = "page";
scope.getIframeSrc = function() {
// One should think about their particular case and sanitize accordingly
var qs = ["a", "b"].map(function(value, name) {
return encodeURIComponent(name) + "=" +
encodeURIComponent(value);
}).join("&");
// `baseUrl` isn't exposed to a user's control, so we don't have to worry about escaping it.
return baseUrl + "?" + qs;
};
```
```html
<iframe src="{{getIframeSrc()}}">
```
See [38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262bb43f26d47245f6c2739).
## Interpolations inside DOM event handlers are now disallowed
DOM event handlers execute arbitrary Javascript code. Using an interpolation for such handlers
means that the interpolated value is a JS string that is evaluated. Storing or generating such
strings is error prone and leads to XSS vulnerabilities. On the other hand, `ngClick` and other
Angular specific event handlers evaluate Angular expressions in non-window (Scope) context which
makes them much safer.
To migrate the code follow the example below:
Before:
```
JS: scope.foo = 'alert(1)';
HTML: <div onclick="{{foo}}">
```
After:
```
JS: scope.foo = function() { alert(1); }
HTML: <div ng-click="foo()">
```
See [39841f2e](https://github.com/angular/angular.js/commit/39841f2ec9b17b3b2920fd1eb548d444251f4f56).
## Directives cannot end with -start or -end
This change was necessary to enable multi-element directives. The best fix is to rename existing
directives so that they don't end with these suffixes.
See [e46100f7](https://github.com/angular/angular.js/commit/e46100f7097d9a8f174bdb9e15d4c6098395c3f2).
## In $q, promise.always has been renamed promise.finally
The reason for this change is to align `$q` with the [Q promise
library](https://github.com/kriskowal/q), despite the fact that this makes it a bit more difficult
to use with non-ES5 browsers, like IE8.
`finally` also goes well together with the `catch` API that was added to `$q` recently and is part
of the [DOM promises standard](http://dom.spec.whatwg.org/).
To migrate the code follow the example below.
Before:
```javascript
$http.get('/foo').always(doSomething);
```
After:
```javascript
$http.get('/foo').finally(doSomething);
```
Or for IE8-compatible code:
```javascript
$http.get('/foo')['finally'](doSomething);
```
See [f078762d](https://github.com/angular/angular.js/commit/f078762d48d0d5d9796dcdf2cb0241198677582c).
## ngMobile is now ngTouch
Many touch-enabled devices are not mobile devices, so we decided to rename this module to better
reflect its concerns.
To migrate, replace all references to `ngMobile` with `ngTouch` and `angular-mobile.js` with
`angular-touch.js`.
See [94ec84e7](https://github.com/angular/angular.js/commit/94ec84e7b9c89358dc00e4039009af9e287bbd05).
## resource.$then has been removed
Resource instances do not have a `$then` function anymore. Use the `$promise.then` instead.
Before:
```javascript
Resource.query().$then(callback);
```
After:
```javascript
Resource.query().$promise.then(callback);
```
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
## Resource methods return the promise
Methods of a resource instance return the promise rather than the instance itself.
Before:
```javascript
resource.$save().chaining = true;
```
After:
```javascript
resource.$save();
resource.chaining = true;
```
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
## Resource promises are resolved with the resource instance
On success, the resource promise is resolved with the resource instance rather than HTTP response object.
Use interceptor API to access the HTTP response object.
Before:
```javascript
Resource.query().$then(function(response) {...});
```
After:
```javascript
var Resource = $resource('/url', {}, {
get: {
method: 'get',
interceptor: {
response: function(response) {
// expose response
return response;
}
}
}
});
```
See [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d).
## $location.search supports multiple keys
{@link api/ng.$location#methods_search `$location.search`} now supports multiple keys with the
same value provided that the values are stored in an array.
Before this change:
* `parseKeyValue` only took the last key overwriting all the previous keys.
* `toKeyValue` joined the keys together in a comma delimited string.
This was deemed buggy behavior. If your server relied on this behavior then either the server
should be fixed, or a simple serialization of the array should be done on the client before
passing it to `$location`.
See [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a03d5fed81fea5c9a1abe).
## ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
`ngBindHtml` which has been moved from `ngSanitize` module to the core `ng` module.
`ngBindHtml` provides `ngBindHtmlUnsafe` like
behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result
of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanitized via
`$sanitize` before being innerHTML'd. If the `$sanitize` service isn't available (`ngSanitize`
module is not loaded) and the bound expression evaluates to a value that is not trusted an
exception is thrown.
See [dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55).
## Form names that are expressions are evaluated
If you have form names that will evaluate as an expression:
```
<form name="ctrl.form">
```
And if you are accessing the form from your controller:
Before:
```javascript
function($scope) {
$scope['ctrl.form'] // form controller instance
}
```
After:
```javascript
function($scope) {
$scope.ctrl.form // form controller instance
}
```
This makes it possible to access a form from a controller using the new "controller as" syntax.
Supporting the previous behavior offers no benefit.
See [8ea802a1](https://github.com/angular/angular.js/commit/8ea802a1d23ad8ecacab892a3a451a308d9c39d7).
## hasOwnProperty disallowed as an input name
Inputs with name equal to `hasOwnProperty` are not allowed inside form or ngForm directives.
Before, inputs whose name was "hasOwnProperty" were quietly ignored and not added to the scope.
Now a badname exception is thrown. Using "hasOwnProperty" for an input name would be very unusual
and bad practice. To migrate, change your input name.
See [7a586e5c](https://github.com/angular/angular.js/commit/7a586e5c19f3d1ecc3fefef084ce992072ee7f60).
## Directives: Order of postLink functions reversed
The order of postLink fn is now mirror opposite of the order in which corresponding preLinking and compile functions execute.
Previously the compile/link fns executed in order, sorted by priority:
<table class="table table-bordered table-striped code-table">
<thead>
<tr>
<th>#</th>
<th>Step</th>
<th align="center">Old Sort Order</th>
<th align="center">New Sort Order</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Compile Fns</td>
<td align="center" colspan="2">High → Low</td>
</tr>
<tr>
<td>2</td>
<td colspan="3">Compile child nodes</td>
</tr>
<tr>
<td>3</td>
<td>PreLink Fns</td>
<td align="center" colspan="2">High → Low</td>
</tr>
<tr>
<td>4</td>
<td colspan="3">Link child nodes</td>
</tr>
<tr>
<td>5</td>
<td>PostLink Fns</td>
<td align="center">High → Low</td>
<td align="center">**Low → High**</td>
</tr>
</tbody>
</table>
<small>"High → Low" here refers to the `priority` option of a directive.</small>
Very few directives in practice rely on the order of postLinking functions (unlike on the order
of compile functions), so in the rare case of this change affecting an existing directive, it might
be necessary to convert it to a preLinking function or give it negative priority.
You can look at [the diff of this
commit](https://github.com/angular/angular.js/commit/31f190d4d53921d32253ba80d9ebe57d6c1de82b) to see how an internal
attribute interpolation directive was adjusted.
See [31f190d4](https://github.com/angular/angular.js/commit/31f190d4d53921d32253ba80d9ebe57d6c1de82b).
## Directive priority
the priority of ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView has changed. This could affect directives that explicitly specify their priority.
In order to make ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView work together in all common scenarios their directives are being adjusted to achieve the following precendence:
Directive | Old Priority | New Priority
-----------------|--------------|-------------
ngRepeat | 1000 | 1000
ngSwitchWhen | 500 | 800
ngIf | 1000 | 600
ngInclude | 1000 | 400
ngView | 1000 | 400
See [b7af76b4](https://github.com/angular/angular.js/commit/b7af76b4c5aa77648cc1bfd49935b48583419023).
## ngScenario
browserTrigger now uses an eventData object instead of direct parameters for mouse events.
To migrate, place the `keys`,`x` and `y` parameters inside of an object and place that as the
third parameter for the browserTrigger function.
See [28f56a38](https://github.com/angular/angular.js/commit/28f56a383e9d1ff378e3568a3039e941c7ffb1d8).
## ngInclude and ngView replace its entire element on update
Previously `ngInclude` and `ngView` only updated its element's content. Now these directives will
recreate the element every time a new content is included.
This ensures that a single rootElement for all the included contents always exists, which makes
definition of css styles for animations much easier.
See [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d6fe57a6c45561a05b182),
[aa2133ad](https://github.com/angular/angular.js/commit/aa2133ad818d2e5c27cbd3933061797096356c8a).
## URLs are now sanitized against a whitelist
A whitelist configured via `$compileProvider` can be used to configure what URLs are considered safe.
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`.
This change sholdn't impact apps that don't contain malicious image links.
See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97),
[3e39ac7e](https://github.com/angular/angular.js/commit/3e39ac7e1b10d4812a44dad2f959a93361cd823b).
## Isolate scope only exposed to directives with `scope` property
Directives without isolate scope do not get the isolate scope from an isolate directive on the
same element. If your code depends on this behavior (non-isolate directive needs to access state
from within the isolate scope), change the isolate directive to use scope locals to pass these explicitly.
**Before**
```
<input ng-model="$parent.value" ng-isolate>
.directive('ngIsolate', function() {
return {
scope: {},
template: '{{value}}'
};
});
```
**After**
```
<input ng-model="value" ng-isolate>
.directive('ngIsolate', function() {
return {
scope: {value: '=ngModel'},
template: '{{value}}
};
});
```
See [909cabd3](https://github.com/angular/angular.js/commit/909cabd36d779598763cc358979ecd85bb40d4d7),
[#1924](https://github.com/angular/angular.js/issues/1924) and
[#2500](https://github.com/angular/angular.js/issues/2500).
## Change to interpolation priority
Previously, the interpolation priority was `-100` in 1.2.0-rc.2, and `100` before 1.2.0-rc.2.
Before this change the binding was setup in the post-linking phase.
Now the attribute interpolation (binding) executes as a directive with priority 100 and the
binding is set up in the pre-linking phase.
See [79223eae](https://github.com/angular/angular.js/commit/79223eae5022838893342c42dacad5eca83fabe8),
[#4525](https://github.com/angular/angular.js/issues/4525),
[#4528](https://github.com/angular/angular.js/issues/4528), and
[#4649](https://github.com/angular/angular.js/issues/4649)
## Underscore-prefixed/suffixed properties are non-bindable
<div class="alert alert-info">
<p>**Reverted**: This breaking change has been reverted in 1.2.1, and so can be ignored if you're using **version 1.2.1 or higher**</p>
</div>
This change introduces the notion of "private" properties (properties
whose names begin and/or end with an underscore) on the scope chain.
These properties will not be available to Angular expressions (i.e. {{
}} interpolation in templates and strings passed to `$parse`) They are
freely available to JavaScript code (as before).
**Motivation**
Angular expressions execute in a limited context. They do not have
direct access to the global scope, `window`, `document` or the Function
constructor. However, they have direct access to names/properties on
the scope chain. It has been a long standing best practice to keep
sensitive APIs outside of the scope chain (in a closure or your
controller.) That's easier said that done for two reasons:
1. JavaScript does not have a notion of private properties so if you need
someone on the scope chain for JavaScript use, you also expose it to
Angular expressions
2. The new `controller as` syntax that's now in increased usage exposes the
entire controller on the scope chain greatly increaing the exposed surface.
Though Angular expressions are written and controlled by the developer, they:
1. Typically deal with user input
2. Don't get the kind of test coverage that JavaScript code would
This commit provides a way, via a naming convention, to allow restricting properties from
controllers/scopes. This means Angular expressions can access only those properties that
are actually needed by the expressions.
See [3d6a89e8](https://github.com/angular/angular.js/commit/3d6a89e8888b14ae5cb5640464e12b7811853c7e).
## You cannot bind to select[multiple]
Switching between `select[single]` and `select[multiple]` has always been odd due to browser quirks.
This feature never worked with two-way data-binding so it's not expected that anyone is using it.
If you are interested in properly adding this feature, please submit a pull request on Github.
See [d87fa004](https://github.com/angular/angular.js/commit/d87fa0042375b025b98c40bff05e5f42c00af114).
## Uncommon region-specific local files were removed from i18n
AngularJS uses the Google Closure library's locale files. The following locales were removed from
Closure, so Angular is not able to continue to support them:
`chr`, `cy`, `el-polyton`, `en-zz`, `fr-rw`, `fr-sn`, `fr-td`, `fr-tg`, `haw`, `it-ch`, `ln-cg`,
`mo`, `ms-bn`, `nl-aw`, `nl-be`, `pt-ao`, `pt-gw`, `pt-mz`, `pt-st`, `ro-md`, `ru-md`, `ru-ua`,
`sr-cyrl-ba`, `sr-cyrl-me`, `sr-cyrl`, `sr-latn-ba`, `sr-latn-me`, `sr-latn`, `sr-rs`, `sv-fi`,
`sw-ke`, `ta-lk`, `tl-ph`, `ur-in`, `zh-hans-hk`, `zh-hans-mo`, `zh-hans-sg`, `zh-hans`,
`zh-hant-hk`, `zh-hant-mo`, `zh-hant-tw`, `zh-hant`
Although these locales were removed from the official AngularJS repository, you can continue to
load and use your copy of the locale file provided that you maintain it yourself.
See [6382e21f](https://github.com/angular/angular.js/commit/6382e21fb28541a2484ac1a241d41cf9fbbe9d2c).
-207
View File
@@ -1,207 +0,0 @@
@ngdoc overview
@name Developer Guide: Overview
@description
# What Is Angular?
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
language and lets you extend HTML's syntax to express your application's components clearly and
succinctly. Out of the box, it eliminates much of the code you currently write through data
binding and dependency injection. And it all happens in JavaScript within the browser, making it
an ideal partner with any server technology.
Angular is what HTML would have been had it been designed for applications. HTML is a great
declarative language for static documents. It does not contain much in the way of creating
applications, and as a result building web applications is an exercise in *what do I have to do
to trick the browser into doing what I want.*
The impedance mismatch between dynamic applications and static documents is often solved with:
* **a library** - a collection of functions which are useful when writing web apps. Your code is
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
* **frameworks** - a particular implementation of a web application, where your code fills in
the details. The framework is in charge and it calls into your code when it needs something
app specific. E.g., `knockout`, `ember`, etc.
Angular takes another approach. It attempts to minimize the impedance mismatch between document
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
browser new syntax through a construct we call directives. Examples include:
* Data binding, as in `{{}}`.
* DOM control structures for repeating/hiding DOM fragments.
* Support for forms and form validation.
* Attaching code-behind to DOM elements.
* Grouping of HTML into reusable components.
## A complete client-side solution
Angular is not a single piece in the overall puzzle of building the client-side of a web
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
well-defined structure. This makes Angular opinionated about how a CRUD application should be
built. But while it is opinionated, it also tries to make sure that its opinion is just a
starting point you can easily change. Angular comes with the following out-of-the-box:
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
directives, form validation, routing, deep-linking, reusable components, dependency injection.
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
* Seed application with directory layout and test scripts as a starting point.
## Angular Sweet Spot
Angular simplifies application development by presenting a higher level of abstraction to the
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
is a good fit for Angular. Angular was built for the CRUD application in mind. Luckily CRUD
applications represent the majority of web applications. But to understand what Angular is
good at one also has to understand when an app is not a good fit for Angular.
Games and GUI editors are examples of applications with intensive and tricky DOM manipulation.
These kinds of apps are different from CRUD apps, and as a result are probably not a good fit for Angular.
In these cases it may be better to use a library with a lower level of abstraction, such as `jQuery`.
# An Introductory Angular Example
Below is a typical CRUD application which contains a form. The form values are validated, and
are used to compute the total, which is formatted to a particular locale. These are some common
concepts which the application developer may face:
* attaching data-model to the UI.
* writing, reading and validating user input.
* computing new values based on the model.
* formatting output in a user specific locale.
<example>
<file name="script.js">
function InvoiceCntl($scope) {
$scope.qty = 1;
$scope.cost = 19.95;
}
</file>
<file name="index.html">
<div ng-controller="InvoiceCntl">
<b>Invoice:</b>
<br>
<br>
<table>
<tr><td>Quantity</td><td>Cost</td></tr>
<tr>
<td><input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required ></td>
<td><input type="number" ng-model="cost" required ></td>
</tr>
</table>
<hr>
<b>Total:</b> {{qty * cost | currency}}
</div>
</file>
<file name="scenario.js">
it('should show off angular binding', function() {
expect(binding('qty * cost')).toEqual('$19.95');
input('qty').enter('2');
input('cost').enter('5.00');
expect(binding('qty * cost')).toEqual('$10.00');
});
</file>
</example>
Try out the Live Preview above, and then let's walk through the example and describe what's going
on.
In the `<html>` tag, we specify that it is an Angular
application with the `ng-app` directive. The `ng-app` will cause Angular to {@link
bootstrap auto initialize} your application.
<html ng-app>
We load Angular using the `<script>` tag:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
From the `ng-model` attribute of the `<input>` tags, Angular automatically sets up two-way data
binding, and we also demonstrate some easy input validation:
Quantity: <input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required >
Cost: <input type="number" ng-model="cost" required >
These input widgets look normal enough, but consider these points:
* When this page loaded, Angular bound the names of the input widgets (`qty` and `cost`) to
variables of the same name. Think of those variables as the "Model" component of the
Model-View-Controller design pattern.
* Note that the HTML widget {@link api/ng.directive:input input}
has special powers. The input invalidates itself by turning red when you enter invalid data or
leave the input fields blank. These new widget behaviors make it easier to implement field
validation common in CRUD applications.
And finally, the mysterious `{{ double curly braces }}`:
Total: {{qty * cost | currency}}
This notation, `{{ _expression_ }}`, is Angular markup for data-binding. The expression itself can
be a combination of both an expression and a {@link dev_guide.templates.filters filter}: `{{
expression | filter }}`. Angular provides filters for formatting display data.
In the example above, the expression in double-curly braces directs Angular to "bind the data we
got from the input widgets to the display, multiply them together, and format the resulting number
into output that looks like money."
Notice that we achieved this application behavior not by calling Angular methods, nor by
implementing application specific behavior as a framework. We achieved the behavior because the
browser behaved more in line with what is needed for a dynamic web application rather than what is
needed for a static document. Angular has lowered the impedance mismatch to the point where no
library/framework calls are needed.
# The Zen of Angular
Angular is built around the belief that declarative code is better than imperative when it comes
to building UIs and wiring software components together, while imperative code is excellent for
expressing business logic.
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
the testability of the code.
* It is a really, _really_ good idea to regard app testing as equal in importance to app
writing. Testing difficulty is dramatically affected by the way the code is structured.
* It is an excellent idea to decouple the client side of an app from the server side. This
allows development work to progress in parallel, and allows for reuse of both sides.
* It is very helpful indeed if the framework guides developers through the entire journey of
building an app: from designing the UI, through writing the business logic, to testing.
* It is always good to make common tasks trivial and difficult tasks possible.
Angular frees you from the following pains:
* **Registering callbacks:** Registering callbacks clutters your code, making it hard to see the
forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It
vastly reduces the amount of JavaScript coding _you_ have to do, and it makes it easier to see
what your application does.
* **Manipulating HTML DOM programmatically:** Manipulating HTML DOM is a cornerstone of AJAX
applications, but it's cumbersome and error-prone. By declaratively describing how the UI
should change as your application state changes, you are freed from low level DOM manipulation
tasks. Most applications written with Angular never have to programmatically manipulate the
DOM, although you can if you want to.
* **Marshaling data to and from the UI:** CRUD operations make up the majority of AJAX
applications. The flow of marshaling data from the server to an internal object to an HTML
form, allowing users to modify the form, validating the form, displaying validation errors,
returning to an internal model, and then back to the server, creates a lot of boilerplate
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
overall flow of the application rather than all of the implementation details.
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
your app easily using services, which are auto-injected into your application in a {@link
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
to get started developing features quickly. As a bonus, you get full control over the
initialization process in automated tests.
# Watch a Presentation About Angular
Here is a presentation on Angular from May 2012. The {@link http://mhevery.github.io/angular-demo-slides/index.html#/list corresponding slides} are also available.
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
+425
View File
@@ -0,0 +1,425 @@
@ngdoc overview
@name Developer Guide: Providers
@description
# Providers
Each web application you build is composed of objects that collaborate to get stuff done. These
objects need to be instantiated and wired together for the app to work. In Angular apps most of
these objects are instantiated and wired together automatically by the {@link api/AUTO.$injector
injector service}.
The injector creates two types of objects, **services** and **specialized objects**.
Services are objects whose API is defined by the developer writing the service.
Specialized objects conform to a specific Angular framework API. These objects are one of
controllers, directives, filters or animations.
The injector needs to know how to create these objects. You tell it by registering a "recipe" for
creating your object with the injector. There are five recipe types.
The most verbose, but also the most comprehensive one is a Provider recipe. The remaining four
recipe types — Value, Factory, Service and Constant — are just syntactic sugar on top of a provider
recipe.
Let's take a look at the different scenarios for creating and using services via various recipe
types. We'll start with the simplest case possible where various places in your code need a shared
string and we'll accomplish this via Value recipe.
## Note: A Word on Modules
In order for the injector to know how to create and wire together all of these objects, it needs
a registry of "recipes". Each recipe has an identifier of the object and the description of how to
create this object.
Each recipe belongs to an {@link api/angular.Module Angular module}. An Angular module is a bag
that holds one or more recipes. And since manually keeping track of module dependencies is no fun,
a module can contain information about dependencies on other modules as well.
When an Angular application starts with a given application module, Angular creates a new instance
of injector, which in turn creates a registry of recipes as a union of all recipes defined in the
core "ng" module, application module and its dependencies. The injector then consults the recipe
registry when it needs to create an object for your application.
## Value Recipe
Let's say that we want to have a very simple service called "clientId" that provides a string
representing an authentication id used for some remote API. You would define it like this:
```javascript
var myApp = angular.module('myApp', []);
myApp.value('clientId', 'a12345654321x');
```
Notice how we created an Angular module called `myApp`, and specified that this module definition
contains a "recipe" for constructing the `clientId` service, which is a simple string in this case.
And this is how you would display it via Angular's data-binding:
```javascript
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
}]);
```
```html
<html ng-app="myApp">
<body ng-controller="DemoController as demo">
Client ID: {{demo.clientId}}
</body>
</html>
```
In this example, we've used the Value recipe to define the value to provide when `DemoController`
asks for the service with id "clientId".
On to more complex examples!
## Factory Recipe
The Value recipe is very simple to write, but lacks some important features we often need when
creating services. Let's now look at the Value recipe's more powerful sibling, the Factory.The
Factory recipe adds the following abilities:
* ability to use other services (have dependencies)
* service initialization
* delayed/lazy initialization
The Factory recipe constructs a new service using a function with zero or more arguments (these
are dependencies on other services). The return value of this function is the service instance
created by this recipe.
Note: All services in Angular are singletons. That means that the injector uses each recipe at most
once to create the object. The injector then caches the reference for all future needs.
Since Factory is more powerful version of Value recipe, you can construct the same service with it.
Using our previous `clientId` Value recipe example, we can rewrite it as a Factory recipe like
this:
```javascript
myApp.factory('clientId', function clientIdFactory() {
return 'a12345654321x';
});
```
But given that the token is just a string literal, sticking with the Value recipe is still more
appropriate as it makes the code easier to follow.
Let's say, however, that we would also like to create a service that computes a token used for
authentication against a remote API. This token will be called 'apiToken' and will be computed
based on the `clientId` value and a secret stored in browser's local storage:
```javascript
myApp.factory('apiToken', ['clientId', function apiTokenFactory(clientId) {
var encrypt = function(data1, data2) {
// NSA-proof encryption algorithm:
return (data1 + ':' + data2).toUpperCase();
};
var secret = window.localStorage.getItem('myApp.secret');
var apiToken = encrypt(clientId, secret);
return apiToken;
}]);
```
In the code above, we see how the `apiToken` service is defined via the Factory recipe that depends
on `clientId` service. The factory service then uses NSA-proof encryption to produce an authentication
token.
Note: It is a best practice to name the factory functions as "<serviceId>Factory"
(e.g. apiTokenFactory). While this names are not required, they help when navigating the code base
or looking at stack traces in the debugger.
Just like with Value recipe, Factory recipe can create a service of any type, whether it be a
primitive, object literal, function, or even an instance of a custom type.
## Service Recipe
JavaScript developers often use custom types to write object-oriented code. Let's explore how we
could launch a unicorn into the space via our `unicornLauncher` service that is an instance of
custom type:
```javascript
function UnicornLauncher(apiToken) {
this.launchedCount = 0;
this.launch() {
// make a request to the remote api and include the apiToken
...
this.launchedCount++;
}
}
```
We are now ready to launch unicorns, but notice that UnicornLauncher depends on our `apiToken`.
We can satisfy this dependency on `apiToken` using the Factory recipe:
```javascript
myApp.factory('unicornLauncher', ["apiToken", function(apiToken) {
return new UnicornLauncher(apiToken);
}]);
```
This is, however, exactly the use-case that Service recipe is the most suitable for.
The Service recipe produces a service just like the Value or Factory recipes, but it does so by
*invoking a constructor with the `new` operator*. The constructor can take zero or more arguments,
which represent dependencies needed by the instance of this type.
Note: Service recipes follow a design pattern called [constructor
injection](http://www.martinfowler.com/articles/injection.html#ConstructorInjectionWithPicocontainer).
Since we already have a constructor for our UnicornLauncher type, we can replace the Factory recipe
above with a Service recipe like this:
```javascript
myApp.service('unicornLauncher', ["apiToken", UnicornLauncher]);
```
Much simpler!
Note: Yes, we have called one of our service recipes 'Service'. We regret this and know that we'll
be somehow punished for our mis-deed. It's like we named one of our offspring 'Children'. Boy,
that would mess with the teachers.
## Provider Recipe
There are two more recipe types left to cover. They are both fairly specialized and are used
infrequently. As already mentioned in the intro, the Provider recipe is the core recipe type and
all the other recipe types are just syntactic sugar on top of it. It is the most verbose recipe
with the most abilities, but for most services it's overkill.
Provider recipe is syntactically defined as a custom type that implements a `$get` method. This
method is a factory function just like the one we use in Factory recipe. In fact, if you define
a Factory recipe, an empty Provider type with the `$get` method set to your factory function is
automatically created under the hood.
You should use the Provider recipe only when you want to expose an API for application-wide
configuration that must be made before the application starts. This is usually interesting only
for reusable services whose behavior might need to vary slightly between applications.
Let's say that our `unicornLauncher` service is so awesome that many apps use it. By default the
launcher shoots unicorns into space without any protective shielding. But on some planets the
atmosphere is so thick that we must wrap every unicorn in tinfoil before sending it on its
intergalactic trip, otherwise they would burn while passing through the atmosphere. It would then
be great if we could configure the launcher to use the tinfoil shielding for each launch in apps
that need it. We can make it configurable it like so:
```javascript
myApp.provider('unicornLauncher', function UnicornLauncherProvider() {
var useTinfoilShielding = false;
this.useTinfoilShielding = function(value) {
useTinfoilShielding = !!value;
};
this.$get = ["apiToken", function unicornLauncherFactory(apiToken) {
// let's assume that the UnicornLauncher constructor was also changed to
// accept and use the useTinfoilShielding argument
return new UnicornLauncher(apiToken, useTinfoilShielding);
}];
});
```
To turn the tinfoil shielding on in our app, we need to create a config function via the module
API and have the UnicornLauncherProvider injected into it:
```javascript
myApp.config(["unicornLauncherProvider", function(unicornLauncherProvider) {
unicornLauncherProvider.useTinfoilShielding(true);
}]);
```
Notice that the unicorn provider is injected into the config function. This injection is done by a
provider injector which is different from the regular instance injector, in that it instantiates
and wires (injects) all provider instances only.
During application bootstrap, before Angular goes off creating all services, it configures and
instantiates all providers. We call this the configuration phase of the application life-cycle.
During this phase services aren't accessible because they haven't been created yet.
Once the configuration phase is over, interaction with providers is disallowed and the process of
creating services starts. We call this part of the application life-cycle the run phase.
## Constant Recipe
We've just learned how Angular splits the life-cycle into configuration phase and run phase and how
you can provide configuration to your application via the config function. Since the config
function runs in the configuration phase when no services are available, it doesn't have access
even to simple value objects created via Value recipe.
Since simple values, like url prefix, don't have dependencies or configuration, it is often handy
to make them available in both the configuration and run phases. This is what the Constant recipe
is for.
Let's say that our `unicornLauncher` service can stamp a unicorn with the planet name it's being
launched from if this name was provided during the configuration phase. The planet name is
application specific and is used also by various controllers during the runtime of the application.
We can then define the planet name as a constant like this:
```javascript
myApp.constant('planetName', 'Greasy Giant');
```
We could then configure the unicornLauncherProvider like this:
```javascript
myApp.config(['unicornLauncherProvider', 'planetName', function(unicornLauncherProvider, planetName) {
unicornLauncherProvider.useTinfoilShielding(true);
unicornLauncherProvider.stampText(planetName);
}]);
```
And since Constant recipe makes the value also available at runtime just like the Value recipe, we
can also use it in our controller and template:
```javascript
myApp.controller('DemoController', ["clientId", "planetName", function DemoController(clientId, planetName) {
this.clientId = clientId;
this.planetName = planetName;
}]);
```
```html
<html ng-app="myApp">
<body ng-controller="DemoController as demo">
Client ID: {{demo.clientId}}
<br>
Planet Name: {{demo.planetName}}
</body>
</html>
```
## Special Purpose Objects
Earlier we mentioned that we also have special purpose objects that are different from services.
These objects extend the framework as plugins and therefore must implement interfaces specified by
Angular. These interfaces are Controller, Directive, Filter and Animation.
The instructions for the injector to create these special objects (with the exception of the
Controller objects) use the Factory recipe behind the scenes.
Let's take a look at how we would create a very simple component via the directive api that depends
on the `planetName` constant we've just defined and displays the planet name, in our case:
"Planet Name: Greasy Giant".
Since the directives are registered via Factory recipe, we can use the same syntax as with factories.
```javascript
myApp.directive('myPlanet', ['planetName', function myPlanetDirectiveFactory(planetName) {
// directive definition object
return {
restrict: 'E',
scope: {},
link: function($scope, $element) { $element.text('Planet: ' + planetName); }
}
}]);
```
We can then use the component like this:
```html
<html ng-app="myApp">
<body>
<my-planet></my-planet>
</body>
</html>
```
Using Factory recipes you can also define Angular's filters and animations, but the controllers
are a bit special. You create a controller as a custom type that declares its dependencies as
arguments for its constructor function. This constructor is then registered with a module. Let's
take a look at the `DemoController`, created in one of the early examples:
```javascript
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
this.clientId = clientId;
}]);
```
The DemoController is instantiated via its constructor every time the app needs an instance of
DemoController (in our simple app it's just once). So unlike services, controllers are not
singletons. The constructor is called with all the requested services, in our case the `clientId`
service.
## Conclusion
To wrap it up, let's summarize the most important points:
- The injector uses recipes to create two types of objects: services and special purpose objects
- There are five recipe types that define how to create objects: Value, Factory, Service, Provider
and Constant.
- Factory and Service are the most commonly used recipes. The only difference between them is that
Service recipe works better for objects of custom type, while Factory can produce JavaScript
primitives and functions.
- The Provider recipe is the core recipe type and all the other ones are just syntactic sugar on it.
- Provider is the most complex recipe type. You don't need it unless you are building a reusable
piece of code that needs global configuration.
- All special purpose objects except for Controller are defined via Factory recipes.
<table class="table table-bordered code-table">
<thead>
<tr>
<th>Features / Recipe type</th>
<th>Factory</th>
<th>Service</th>
<th>Value</th>
<th>Constant</th>
<th>Provider</th>
</tr>
</thead>
<tbody>
<tr>
<td>can have dependencies</td>
<td class="success">yes</td>
<td class="success">yes</td>
<td class="error">no</td>
<td class="error">no</td>
<td class="success">yes</td>
</tr>
<tr>
<td>uses type friendly injection</td>
<td class="error">no</td>
<td class="success">yes</td>
<td class="success">yes\*</td>
<td class="success">yes\*</td>
<td class="error">no</td>
</tr>
<tr>
<td>object available in config phase</td>
<td class="error">no</td>
<td class="error">no</td>
<td class="error">no</td>
<td class="success">yes</td>
<td class="success">yes\*\*</td>
</tr>
<tr>
<td>can create functions/primitives</td>
<td class="success">yes</td>
<td class="error">no</td>
<td class="success">yes</td>
<td class="success">yes</td>
<td class="success">yes</td>
</tr>
</tbody>
</table>
\* at the cost of eager initialization by using `new` operator directly
\*\* the service object is not available during the config phase, but the provider instance is
(see the `unicornLauncherProvider` example above).
+120 -50
View File
@@ -11,10 +11,10 @@ watch {@link guide/expression expressions} and propagate events.
## Scope characteristics
- Scopes provide APIs ({@link api/ng.$rootScope.Scope#$watch $watch}) to observe
- Scopes provide APIs ({@link api/ng.$rootScope.Scope#methods_$watch $watch}) to observe
model mutations.
- Scopes provide APIs ({@link api/ng.$rootScope.Scope#$apply $apply}) to
- Scopes provide APIs ({@link api/ng.$rootScope.Scope#methods_$apply $apply}) to
propagate any model changes through the system into the view from outside of the "Angular
realm" (controllers, services, Angular event handlers).
@@ -28,8 +28,8 @@ watch {@link guide/expression expressions} and propagate events.
## Scope as Data-Model
Scope is the glue between application controller and the view. During the template {@link compiler
linking} phase the {@link api/ng.$compileProvider#directive directives} set up
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
linking} phase the {@link api/ng.$compileProvider#methods_directive directives} set up
{@link api/ng.$rootScope.Scope#methods_$watch `$watch`} expressions on the scope. The
`$watch` allows the directives to be notified of property changes, which allows the directive to
render the updated value to the DOM.
@@ -110,50 +110,51 @@ new child scopes (refer to directive documentation to see which directives creat
When new scopes are created, they are added as children of their parent scope. This creates a tree
structure which parallels the DOM where they're attached
When Angular evaluates `{{username}}`, it first looks at the scope associated with the given
element for the `username` property. If no such property is found, it searches the parent scope
When Angular evaluates `{{name}}`, it first looks at the scope associated with the given
element for the `name` property. If no such property is found, it searches the parent scope
and so on until the root scope is reached. In JavaScript this behavior is known as prototypical
inheritance, and child scopes prototypically inherit from their parents.
This example illustrates scopes in application, and prototypical inheritance of properties.
This example illustrates scopes in application, and prototypical inheritance of properties. The example is followed by
a diagram depicting the scope boundaries.
<example>
<file name="style.css">
/* remove .doc-example-live in jsfiddle */
.doc-example-live .ng-scope {
border: 1px dashed red;
}
<file name="index.html">
<div class="show-scope-demo">
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">{{name}} from {{department}}</li>
</ol>
</div>
</div>
</file>
<file name="script.js">
function EmployeeController($scope) {
$scope.department = 'Engineering';
$scope.employee = {
name: 'Joe the Manager',
reports: [
{name: 'John Smith'},
{name: 'Mary Run'}
]
};
function GreetCtrl($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
</file>
<file name="index.html">
<div ng-controller="EmployeeController">
Manager: {{employee.name}} [ {{department}} ]<br>
Reports:
<ul>
<li ng-repeat="employee in employee.reports">
{{employee.name}} [ {{department}} ]
</li>
</ul>
<hr>
{{greeting}}
</div>
<file name="style.css">
.show-scope-demo.ng-scope,
.show-scope-demo .ng-scope {
border: 1px solid red;
margin: 3px;
}
</file>
</example>
<img class="center" src="img/guide/concepts-scope.png">
Notice that Angular automatically places `ng-scope` class on elements where scopes are
attached. The `<style>` definition in this example highlights in red the new scope locations. The
child scopes are necessary because the repeater evaluates `{{employee.name}}` expression, but
child scopes are necessary because the repeater evaluates `{{name}}` expression, but
depending on which scope the expression is evaluated it produces different result. Similarly the
evaluation of `{{department}}` prototypically inherits from root scope, as it is the only place
where the `department` property is defined.
@@ -176,14 +177,14 @@ To examine the scope in the debugger:
2. The debugger allows you to access the currently selected element in the console as `$0`
variable.
3. To retrieve the associated scope in console execute: `angular.element($0).scope()`
3. To retrieve the associated scope in console execute: `angular.element($0).scope()` or just type $scope
## Scope Events Propagation
Scopes can propagate events in similar fashion to DOM events. The event can be {@link
api/ng.$rootScope.Scope#$broadcast broadcasted} to the scope children or {@link
api/ng.$rootScope.Scope#$emit emitted} to scope parents.
api/ng.$rootScope.Scope#methods_$broadcast broadcasted} to the scope children or {@link
api/ng.$rootScope.Scope#methods_$emit emitted} to scope parents.
<example>
<file name="script.js">
@@ -225,14 +226,14 @@ more events.
When the browser calls into JavaScript the code executes outside the Angular execution context,
which means that Angular is unaware of model modifications. To properly process model
modifications the execution has to enter the Angular execution context using the {@link
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
api/ng.$rootScope.Scope#methods_$apply `$apply`} method. Only model modifications which
execute inside the `$apply` method will be properly accounted for by Angular. For example if a
directive listens on DOM events, such as {@link
api/ng.directive:ngClick `ng-click`} it must evaluate the
expression inside the `$apply` method.
After evaluating the expression, the `$apply` method performs a {@link
api/ng.$rootScope.Scope#$digest `$digest`}. In the $digest phase the scope examines all
api/ng.$rootScope.Scope#methods_$digest `$digest`}. In the $digest phase the scope examines all
of the `$watch` expressions and compares them with the previous value. This dirty checking is done
asynchronously. This means that assignment such as `$scope.username="angular"` will not
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
@@ -250,20 +251,20 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
2. **Watcher registration**
During template linking directives register {@link
api/ng.$rootScope.Scope#$watch watches} on the scope. These watches will be
api/ng.$rootScope.Scope#methods_$watch watches} on the scope. These watches will be
used to propagate model values to the DOM.
3. **Model mutation**
For mutations to be properly observed, you should make them only within the {@link
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular APIs do this
api/ng.$rootScope.Scope#methods_$apply scope.$apply()}. (Angular APIs do this
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
or asynchronous work with {@link api/ng.$http $http} or {@link
api/ng.$timeout $timeout} services.
4. **Mutation observation**
At the end `$apply`, Angular performs a {@link api/ng.$rootScope.Scope#$digest
At the end `$apply`, Angular performs a {@link api/ng.$rootScope.Scope#methods_$digest
$digest} cycle on the root scope, which then propagates throughout all child scopes. During
the `$digest` cycle, all `$watch`ed expressions or functions are checked for model mutation
and if a mutation is detected, the `$watch` listener is called.
@@ -271,7 +272,7 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
5. **Scope destruction**
When child scopes are no longer needed, it is the responsibility of the child scope creator
to destroy them via {@link api/ng.$rootScope.Scope#$destroy scope.$destroy()}
to destroy them via {@link api/ng.$rootScope.Scope#methods_$destroy scope.$destroy()}
API. This will stop propagation of `$digest` calls into the child scope and allow for memory
used by the child scope models to be reclaimed by the garbage collector.
@@ -279,27 +280,27 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
### Scopes and Directives
During the compilation phase, the {@link compiler compiler} matches {@link
api/ng.$compileProvider#directive directives} against the DOM template. The directives
api/ng.$compileProvider#methods_directive directives} against the DOM template. The directives
usually fall into one of two categories:
- Observing {@link api/ng.$compileProvider#directive directives}, such as
- Observing {@link api/ng.$compileProvider#methods_directive directives}, such as
double-curly expressions `{{expression}}`, register listeners using the {@link
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
api/ng.$rootScope.Scope#methods_$watch $watch()} method. This type of directive needs
to be notified whenever the expression changes so that it can update the view.
- Listener directives, such as {@link api/ng.directive:ngClick
ng-click}, register a listener with the DOM. When the DOM listener fires, the directive
executes the associated expression and updates the view using the {@link
api/ng.$rootScope.Scope#$apply $apply()} method.
api/ng.$rootScope.Scope#methods_$apply $apply()} method.
When an external event (such as a user action, timer or XHR) is received, the associated {@link
expression expression} must be applied to the scope through the {@link
api/ng.$rootScope.Scope#$apply $apply()} method so that all listeners are updated
api/ng.$rootScope.Scope#methods_$apply $apply()} method so that all listeners are updated
correctly.
### Directives that Create Scopes
In most cases, {@link api/ng.$compileProvider#directive directives} and scopes interact
In most cases, {@link api/ng.$compileProvider#methods_directive directives} and scopes interact
but do not create new instances of scope. However, some directives, such as {@link
api/ng.directive:ngController ng-controller} and {@link
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
@@ -315,7 +316,7 @@ Scopes and controllers interact with each other in the following situations:
- Controllers define methods (behavior) that can mutate the model (properties on the scope).
- Controllers may register {@link api/ng.$rootScope.Scope#$watch watches} on
- Controllers may register {@link api/ng.$rootScope.Scope#methods_$watch watches} on
the model. These watches execute immediately after the controller behavior executes.
See the {@link api/ng.directive:ngController ng-controller} for more
@@ -329,3 +330,72 @@ the dirty checking function must be efficient. Care should be taken that the dir
function does not do any DOM access, as DOM access is orders of magnitude slower then property
access on JavaScript object.
## Integration with the browser event loop
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
The diagram and the example below describe how Angular interacts with the browser's event loop.
1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event,
or network event (response from a server).
2. The event's callback gets executed. This enters the JavaScript context. The callback can
modify the DOM structure.
3. Once the callback executes, the browser leaves the JavaScript context and
re-renders the view based on DOM changes.
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
splits the JavaScript into classical and Angular execution context. Only operations which are
applied in Angular execution context will benefit from Angular data-binding, exception handling,
property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in
mind that in most places (controllers, services) $apply has already been called for you by the
directive which is handling the event. An explicit call to $apply is needed only when
implementing custom event callbacks, or when working with third-party library callbacks.
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
api/ng.$rootScope.Scope#methods_$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
the work you wish to do in Angular execution context.
2. Angular executes the `stimulusFn()`, which typically modifies application state.
3. Angular enters the {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue and the {@link
api/ng.$rootScope.Scope#methods_$watch $watch} list. The {@link
api/ng.$rootScope.Scope#methods_$digest $digest} loop keeps iterating until the model
stabilizes, which means that the {@link api/ng.$rootScope.Scope#methods_$evalAsync
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#methods_$watch
$watch} list does not detect any changes.
4. The {@link api/ng.$rootScope.Scope#methods_$evalAsync $evalAsync} queue is used to
schedule work which needs to occur outside of current stack frame, but before the browser's
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
suffers from slowness and may cause view flickering since the browser renders the view after
each event.
5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list is a set of expressions
which may have changed since last iteration. If a change is detected then the `$watch`
function is called which typically updates the DOM with the new value.
6. Once the Angular {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop finishes
the execution leaves the Angular and JavaScript context. This is followed by the browser
re-rendering the DOM to reflect any changes.
Here is the explanation of how the `Hello world` example achieves the data-binding effect when the
user enters text into the text field.
1. During the compilation phase:
1. the {@link api/ng.directive:ngModel ng-model} and {@link
api/ng.directive:input input} {@link guide/directive
directive} set up a `keydown` listener on the `<input>` control.
2. the {@link api/ng.$interpolate &#123;&#123;name&#125;&#125; } interpolation
sets up a {@link api/ng.$rootScope.Scope#methods_$watch $watch} to be notified of
`name` changes.
2. During the runtime phase:
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
2. The {@link api/ng.directive:input input} directive
captures the change to the input's value and calls {@link
api/ng.$rootScope.Scope#methods_$apply $apply}`("name = 'X';")` to update the
application model inside the Angular execution context.
3. Angular applies the `name = 'X';` to the model.
4. The {@link api/ng.$rootScope.Scope#methods_$digest $digest} loop begins
5. The {@link api/ng.$rootScope.Scope#methods_$watch $watch} list detects a change
on the `name` property and notifies the {@link api/ng.$interpolate
&#123;&#123;name&#125;&#125; } interpolation, which in turn updates the DOM.
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
the JavaScript execution context.
7. The browser re-renders the view with update text.
@@ -1,5 +1,5 @@
@ngdoc overview
@name Developer Guide: Understanding Angular Templates
@name Templates
@description
An Angular template is the declarative specification that, along with information from the model
@@ -14,7 +14,7 @@ These are the types of Angular elements and element attributes you can use in a
augments an existing DOM element or represents a reusable DOM component - a widget.
* {@link api/ng.$interpolate Markup} — The double
curly brace notation `{{ }}` to bind expressions to elements is built-in angular markup.
* {@link dev_guide.templates.filters Filter} — Formats your data for display to the user.
* {@link filter Filter} — Formats your data for display to the user.
* {@link forms Form controls} — Lets you validate user input.
Note: In addition to declaring the elements above in templates, you can also access these elements
@@ -49,7 +49,7 @@ eight.
## Related Topics
* {@link dev_guide.templates.filters Angular Filters}
* {@link filter Angular Filters}
* {@link forms Angular Forms}
## Related API
+79 -201
View File
@@ -1,157 +1,94 @@
@ngdoc overview
@name Contributing
@name Develop
@description
# Building and Testing AngularJS
* <a href="#H1_1">License</a>
* <a href="#H1_2">Contributing to Source Code</a>
* <a href="#H1_3">Applying Code Standards</a>
* <a href="#H1_4">Checking Out and Building `Angular`</a>
* <a href="#H1_5">Submitting Your Changes</a>
This document describes how to set up your development environment to build and test AngularJS, and
explains the basic mechanics of using `git`, `node`, `npm`, `grunt`, and `bower`.
See the [contributing guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
for how to contribute your own code to AngularJS.
<a name="H1_1"></a>
# License
1. {@link #building-and-testing-angularjs_installing-dependencies Installing Dependencies}
2. {@link #building-and-testing-angularjs_forking-angular-on-github Forking Angular on Github}
3. {@link #building-and-testing-angularjs_building-angularjs Building AngularJS}
4. {@link #building-and-testing-angularjs_running-a-local-development-web-server Running a Local Development Web Server}
5. {@link #building-and-testing-angularjs_running-the-unit-test-suite Running the Unit Test Suite}
6. {@link #building-and-testing-angularjs_running-the-end-to-end-test-suite Running the End-to-end Test Suite}
AngularJS is an open source project licensed under the {@link
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
always welcome. When working with AngularJS code base, please follow the guidelines provided on
this page.
## Installing Dependencies
<a name="H1_2"></a>
# Contributing to Source Code
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
* Major changes that you intend to contribute to the project should be discussed first on our {@link
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
is successfully accepted upstream.
* Small changes and bug fixes can be crafted and submitted to Github as a <a href="#H1_5">pull
request</a>.
<a name="H1_3"></a>
# Applying Code Standards
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes must be tested by one or more <a href="#unit-tests">specs</a>.
* All public API methods must be documented with ngdoc, an extended version of jsdoc (we added
support for markdown and templating via `@ngdoc` tag). To see how we document our APIs, please
check out the existing ngdocs.
* With the exceptions listed below, we follow the rules contained in {@link
http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml Google's JavaScript Style
Guide}:
* Do not use namespaces: Instead, we 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
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, internally we use aliases that map to the
external API. See our existing code to see what we mean.
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
<a name="H1_4"></a>
# Checking Out and Building Angular
The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. The AngularJS repository can be found at **<https://github.com/angular/angular.js>**.
Several steps are needed to check out and build AngularJS:
## Installation Dependencies
Before you can build AngularJS, you must install or configure the following dependencies on your
Before you can build AngularJS, you must install and configure the following dependencies on your
machine:
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
quite a good source for information on Git.
* {@link http://git-scm.com/ Git}: The {@link http://help.github.com/mac-git-installation Github Guide to
Installing Git} is a good source of information.
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation, run a
development web server, run tests, and generate a build. Depending on your system, you can install Node either from source or as a
development web server, run tests, and generate distributable files. Depending on your system, you can install Node either from source or as a
pre-packaged bundle.
* {@link http://www.java.com Java}: JavaScript is minified using
* {@link http://www.java.com Java}: We minify JavaScript using our
{@link https://developers.google.com/closure/ Closure Tools} jar. Make sure you have Java (version 6 or higher) installed
and included in your {@link http://docs.oracle.com/javase/tutorial/essential/environment/paths.html PATH} variable.
Once installed, you'll also need several npms (node packages), which you can install once you checked out a local copy
of the Angular repository (see below) with:
* `cd angular.js`
* `npm install`
* `bower install`
* {@link http://gruntjs.com Grunt}: We use Grunt as our build system. Install the grunt command-line tool globally with:
* `sudo npm install -g grunt-cli`
```shell
npm install -g grunt-cli
```
* {@link http://bower.io/ Bower}: Bower is used to manage packages for the docs. Install the bower tool globally with:
* {@link http://bower.io/ Bower}: We use Bower to manage client-side packages for the docs. Install the `bower` command-line tool globally with:
* `sudo npm install -g bower`
```shell
npm install -g bower
```
## Creating a Github Account and Forking Angular
## Forking Angular on Github
To create a Github account, follow the instructions {@link https://github.com/signup/free here}.
Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
https://github.com/angular/angular.js main angular repository}.
https://github.com/angular/angular.js main AngularJS repository}.
## Building AngularJS
To build AngularJS, you check out the source code and use Grunt to generate the non-minified and
To build AngularJS, you clone the source code repository and use Grunt to generate the non-minified and
minified AngularJS files:
1. To clone your Github repository, run:
```shell
# Clone your Github repository:
git clone git@github.com:<github username>/angular.js.git
git clone git@github.com:<github username>/angular.js.git
# Go to the AngularJS directory:
cd angular.js
2. To go to the AngularJS directory, run:
# Add the main AngularJS repository as an upstream remote to your repository:
git remote add upstream https://github.com/angular/angular.js.git
cd angular.js
# Install node.js dependencies:
npm install
3. To add the main AngularJS repository as an upstream remote to your repository, run:
# Install bower components:
bower install
git remote add upstream https://github.com/angular/angular.js.git
# Build AngularJS:
grunt package
```
4. To add node.js dependencies
npm install
5. To add docs components
bower install
6. To build AngularJS, run:
grunt package
NOTE: If you're using Windows you must run your command line with administrative privileges (right click, run as
Administrator).
<div class="alert alert-warning">
**Note:** If you're using Windows, you must use an elevated command prompt (right click, run as
Administrator). This is because `grunt package` creates some symbolic links.
</div>
The build output can be located under the `build` directory. It consists of the following files and
directories:
* `angular-<version>.zip` — This is the complete zip file, which contains all of the release build
* `angular-<version>.zip` — The complete zip file, containing all of the release build
artifacts.
* `angular.js` — The non-minified `angular` script.
@@ -167,34 +104,37 @@ artifacts.
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
<a name="webserver"></a>
## Running a Local Development Web Server
To debug code and run end-to-end tests, it is often useful to have a local HTTP server. For this purpose, we have
made available a local web server based on Node.js.
1. To start the web server, run:
```shell
grunt webserver
```
grunt webserver
2. To access the local server, go to this website:
http://localhost:8000/
2. To access the local server, enter the following URL into your web browser:
```
http://localhost:8000/
```
By default, it serves the contents of the AngularJS project directory.
<a name="unit-tests"></a>
## Running the Unit Test Suite
Our unit and integration tests are written with Jasmine and executed with Karma. To run all of the
We write unit and integration tests with Jasmine and execute them with Karma. To run all of the
tests once on Chrome run:
grunt test:unit
```shell
grunt test:unit
```
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
grunt test:unit --browsers Opera,Firefox
```shell
grunt test:unit --browsers Opera,Firefox
```
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
@@ -203,96 +143,34 @@ change. To execute tests in this mode run:
1. To start the Karma server, capture Chrome browser and run unit tests, run:
grunt autotest:jqlite
```shell
grunt autotest
```
2. To capture more browsers, open this url in the desired browser (url might be different if you have multiple instance
of Karma running, read Karma's console output for the correct url):
2. To capture more browsers, open this URL in the desired browser (URL might be different if you have multiple instance
of Karma running, read Karma's console output for the correct URL):
http://localhost:9876/
```shell
http://localhost:9876/
```
3. To re-run tests just change any source or test file.
To learn more about all of the preconfigured Grunt tasks run:
grunt --help
```shell
grunt --help
```
## Running the end-to-end Test Suite
## Running the End-to-end Test Suite
To run the E2E test suite:
Simply run:
1. Start the local web server if it's not running already.
```shell
grunt test:e2e
```
grunt webserver
This will start the webserver and run the tests.
2. In a browser, go to:
http://localhost:8000/build/docs/docs-scenario.html
or in terminal run:
grunt test:end2end
For convenience you can also simply run:
grunt test:e2e
This will start the webserver for you and run the tests.
<a name="H1_5"></a>
# Submitting Your Changes
To create and submit a change:
1. <a name="CLA"></a>
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
accepted, the CLA must be signed. It's a quick process, we promise!
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form](http://code.google.com/legal/corporate-cla-v1.0.html).
2. Create and checkout a new branch off the master branch for your changes:
git checkout -b my-fix-branch master
3. Create your patch, make sure to have plenty of tests (that pass).
4. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
please check out our
[commit message conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
and our commit message presubmit hook `validate-commit-msg.js`):
git commit -a
5. Push your branch to Github:
git push origin my-fix-branch
6. In Github, send a pull request to `angular:master`.
7. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
from the main (upstream) repository:
1. To delete the branch in Github, run:
git push origin :my-fix-branch
2. To check out the master branch, run:
git checkout master
3. To delete a local branch, run:
git branch -D my-fix-branch
4. To update your master with the latest upstream version, run:
git pull --ff upstream master
That's it! Thank you for your contribution!
+17 -6
View File
@@ -9,20 +9,20 @@ This way, you don't have to download anything or maintain a local copy.
There are two types of angular script URLs you can point to, one for development and one for
production:
* __angular-<version>.js__ — This is the human-readable, non-minified version, suitable for web
* __angular.js__ — This is the human-readable, non-minified version, suitable for web
development.
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
* __angular.min.js__ — This is the minified version, which we strongly suggest you use in
production.
To point your code to an angular script on the Google CDN server, use the following template. This
example points to the minified version 1.0.2:
example points to the minified version 1.2.0:
<pre>
<!doctype html>
<html ng-app>
<head>
<title>My Angular App</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
</head>
<body>
</body>
@@ -58,7 +58,7 @@ for this angular version. Use this file to get everything in a single download.
* __`angular-mocks.js`__ — This file contains an implementation of mocks that makes
testing angular apps even easier. Your unit/integration test harness should load this file after
`angular-<version>.js` is loaded.
`angular.js` is loaded.
* __`angular-scenario.js`__ — This file is a very nifty JavaScript file that allows you
to write and execute end-to-end tests for angular applications.
@@ -68,8 +68,19 @@ to write and execute end-to-end tests for angular applications.
contents of this file are copy&pasted into the `index.html` to avoid even the initial request to `angular-loader.min.js`.
See [angular-seed](https://github.com/angular/angular-seed/blob/master/app/index-async.html) for an example of usage.
* __`angular-resource.js`__, __`angular-cookies.js`__, etc - extra Angular modules with additional functionality.
* __Additional Angular modules:__ optional modules with additional functionality. These files should be loaded
after the core `angular.js` file:
* __`angular-animate.js`__ - Enable animation support
* __`angular-cookies.js`__ - A convenient wrapper for reading and writing browser cookies
* __`angular-resource.js`__ - Interaction support with RESTful services via the $resource service
* __`angular-route.js`__ - Routing and deeplinking services and directives for angular apps
* __`angular-sanitize.js`__ - Functionality to sanitize HTML
* __`angular-touch.js`__ - Touch events and other helpers for touch-enabled devices
* __`docs`__ — this directory contains all the files that compose the
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
our docs, or even more importantly, view the docs offline.
* __`i18n`__ - this directory contains locale specific `ngLocale` angular modules to override the defaults
defined in the `ng` module.
+2 -2
View File
@@ -67,7 +67,7 @@ illustration we typically build snappy apps with hundreds or thousands of active
### How big is the angular.js file that I need to include?
The size of the file is < 29KB compressed and minified.
The size of the file is < 36KB compressed and minified.
### Can I use the open-source Closure Library with Angular?
@@ -81,7 +81,7 @@ Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your a
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
Due to a change to use `on()`/`off()` rather than `bind()`\`unbind()`, Angular 1.2 only operates with
Due to a change to use `on()`/`off()` rather than `bind()`/`unbind()`, Angular 1.2 only operates with
jQuery 1.7.1 or above.
+16 -13
View File
@@ -54,25 +54,28 @@ and follow the instructions for setting up your computer.
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
don't have it already:</p>
<pre>npm install -g karma</pre>
<li><p>You'll also need Git, which you can get from
<li><p>You'll need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at
<a href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<pre>git clone https://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the <code>angular-phonecat</code> directory in your current
directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
<p>The tutorial instructions, from now on, assume you are running all commands from the <code>angular-phonecat</code>
directory.</p></li>
<li><p>You will also need Node.js and Karma to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.10 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p></li>
<pre>node --version</pre>
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> and its plugins if you
don't have it already:</p>
<pre>
npm install -g karma
npm install
</pre></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
@@ -82,7 +85,7 @@ to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></l
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
<a href="http://nodejs.org/">Node.js</a> v0.10 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
@@ -94,7 +97,7 @@ to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></l
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<pre>git clone https://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the <code>angular-phonecat</code> directory in your current directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
+3 -4
View File
@@ -26,7 +26,7 @@ angular-seed, and run the application in the browser.
<ol>
<li>In a <i>separate</i> terminal tab or window, run <code>node ./scripts/web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
href="http://localhost:8000/app/index.html" target="_blank">`http://localhost:8000/app/index.html`</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
@@ -54,7 +54,7 @@ angular-seed, and run the application in the browser.
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run <code>node scripts\web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
<li>Open a browser window for the app and navigate to <a href="http://localhost:8000/app/index.html" target="_blank">`http://localhost:8000/app/index.html`</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
@@ -147,8 +147,7 @@ for most cases. In advanced cases, such as when using script loaders, you can us
There are 3 important things that happen during the app bootstrap:
1. The {@link api/AUTO.$injector injector} that will be used for dependency injection
when this app is created.
1. The {@link api/AUTO.$injector injector} that will be used for dependency injection is created.
2. The injector will then create the {@link api/ng.$rootScope root scope} that will
become the context for the model of our application.
+17 -8
View File
@@ -81,7 +81,7 @@ __`app/js/controllers.js`:__
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function PhoneListCtrl($scope) {
phonecatApp.controller('PhoneListCtrl', function ($scope) {
$scope.phones = [
{'name': 'Nexus S',
'snippet': 'Fast just got faster with Nexus S.'},
@@ -104,7 +104,7 @@ the model and the view. We connected the dots between the presentation, data, an
as follows:
* The {@link api/ng.directive:ngController ngController} directive, located on the `<body>` tag,
references the the name of our controller, `PhoneListCtrl` (located in the JavaScript file
references the name of our controller, `PhoneListCtrl` (located in the JavaScript file
`controllers.js`).
* The `PhoneListCtrl` controller attaches the phone data to the `$scope` that was injected into our
@@ -151,13 +151,15 @@ Angular. Since testing is such a critical part of software development, we make
tests in Angular so that developers are encouraged to write them.
### Testing non-Global Controllers
In practice, you will not want to have your controller functions in the global namespace. In this
case Angular provides a service, `$controller`, which will retrieve your controller by name. Here
is the same test using `$controller`:
In practice, you will not want to have your controller functions in the global namespace. Instead,
we have registered our controllers in the `phonecatApp` module. In this case Angular provides a
service, `$controller`, which will retrieve your controller by name. Here is the same test using
`$controller`:
__`test/unit/controllersSpec.js`:__
<pre>
describe('PhoneCat controllers', function() {
beforeEach(module('phonecatApp'));
describe('PhoneListCtrl', function(){
@@ -171,15 +173,22 @@ describe('PhoneCat controllers', function() {
});
</pre>
Don't forget that we need to load up the `phonecatApp` module into the test so that the controller
is available to be injected.
### Writing and Running Tests
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
this tutorial in Jasmine. You can learn about Jasmine on the {@link
http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
http://pivotal.github.com/jasmine/ Jasmine home page} and at the {@link
http://pivotal.github.io/jasmine/ Jasmine docs}.
The angular-seed project is pre-configured to run all unit tests using {@link
http://karma-runner.github.io/ Karma}. To run the test, do the following:
http://karma-runner.github.io/ Karma}. Ensure that the necessary karma plugins are installed.
You can do this by issuing `npm install` into your terminal.
To run the test, do the following:
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
`./scripts/test.sh` to start the Karma server (the config file necessary to start the server
+4 -4
View File
@@ -55,7 +55,7 @@ __`app/index.html`:__
</pre>
We added a standard HTML `<input>` tag and used Angular's
{@link api/ng.filter:filter $filter} function to process the input for the
{@link api/ng.filter:filter filter} function to process the input for the
{@link api/ng.directive:ngRepeat ngRepeat} directive.
This lets a user enter search criteria and immediately see the effects of their search on the phone
@@ -127,8 +127,8 @@ end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests
with unit tests, Karma will exit after the test run and will not automatically rerun the test
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
Note: You must ensure you've installed karma-ng-scenario prior to running the `e2e-test.sh` script.
You can do this by issuing `npm install karma-ng-scenario` into your terminal.
Note: You must ensure you've installed the karma-ng-scenario framework plugin prior to running the
`e2e-test.sh` script. You can do this by issuing `npm install` into your terminal.
This test verifies that the search box and the repeater are correctly wired together. Notice how
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
@@ -154,7 +154,7 @@ really is that easy to set up any functional, readable, end-to-end test.
`ngController` declaration to the HTML element because it is the common parent of both the body
and title elements:
<html ng-app ng-controller="PhoneListCtrl">
<html ng-app="phonecatApp" ng-controller="PhoneListCtrl">
Be sure to __remove__ the `ng-controller` declaration from the body element.
+7 -6
View File
@@ -67,7 +67,7 @@ __`app/js/controllers.js`:__
<pre>
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function PhoneListCtrl($scope) {
phonecatApp.controller('PhoneListCtrl', function ($scope) {
$scope.phones = [
{'name': 'Nexus S',
'snippet': 'Fast just got faster with Nexus S.',
@@ -112,11 +112,12 @@ describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
var scope, ctrl;
beforeEach(function() {
scope = {},
ctrl = new PhoneListCtrl(scope);
});
beforeEach(module('phonecatApp'));
beforeEach(inject(function($controller) {
scope = {};
ctrl = $controller('PhoneListCtrl', {$scope:scope});
}));
it('should create "phones" model with 3 phones', function() {
expect(scope.phones.length).toBe(3);
+4 -4
View File
@@ -6,7 +6,7 @@
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
from our server using one of Angular's built-in {@link api/ng services} called {@link
from our server using one of Angular's built-in {@link guide/dev_guide.services services} called {@link
api/ng.$http $http}. We will use Angular's {@link guide/di dependency
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
@@ -56,7 +56,7 @@ __`app/js/controllers.js:`__
<pre>
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function PhoneListCtrl($scope, $http) {
phonecatApp.controller('PhoneListCtrl', function ($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
@@ -79,7 +79,7 @@ json response and parsed it for us!
To use a service in angular, you simply declare the names of the dependencies you need as arguments
to the controller's constructor function, as follows:
function PhoneListCtrl($scope, $http) {...}
phonecatApp.controller('PhoneListCtrl', function ($scope, $http) {...}
Angular's dependency injector provides services to your controller when the controller is being
constructed. The dependency injector also takes care of creating any transitive dependencies the
@@ -145,7 +145,7 @@ __`app/js/controllers.js:`__
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http',
function PhoneListCtrl($scope, $http) {
function ($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
+1 -1
View File
@@ -64,7 +64,7 @@ We also added phone images next to each record using an image tag with the {@lin
api/ng.directive:ngSrc ngSrc} directive. That directive prevents the
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
specified an attribute binding in a regular `src` attribute (`<img src="{{phone.imageUrl}}">`).
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
+4 -3
View File
@@ -107,7 +107,7 @@ module `phonecatControllers`. By listing these two modules as dependencies of `p
can use the directives and services they provide.
Thus using the `config` API we request the `$routeProvider` to be injected into our config function
and use the {@link api/ngRoute.$routeProvider#when `$routeProvider.when`} API to define our routes.
and use the {@link api/ngRoute.$routeProvider#methods_when `$routeProvider.when`} API to define our routes.
Our application routes are defined as follows:
@@ -149,7 +149,7 @@ __`app/js/controllers.js`:__
var phonecatControllers = angular.module('phonecatControllers', []);
phonecatControllers.controller('PhoneListCtrl', ['$scope', '$http',
function PhoneListCtrl($scope, $http) {
function ($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
@@ -165,7 +165,7 @@ phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
Again, note that we created a new module called `phonecatControllers`. For small AngularJS applications,
it's common to create just one module for all of your controllers if there are just a few. For larger apps,
you will rpobbaly want to create separate modules for each major feature of your app.
you will probably want to create separate modules for each major feature of your app.
Because our example app is relatively small, we'll add all of our controllers to this module.
@@ -183,6 +183,7 @@ tag to your `index.html` file as shown below.
__`app/index.html`:__
<pre>
<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
...
+1 -1
View File
@@ -119,7 +119,7 @@ You should now see the following output in the Karma tab:
# Experiments
* Let's experiment with some of the {@link api/ng.$filter built-in Angular filters} and add the
* Let's experiment with some of the {@link api/ng.$filterProvider built-in Angular filters} and add the
following bindings to `index.html`:
* `{{ "lower cap string" | uppercase }}`
* `{{ {foo: "bar", baz: 23} | json }}`
+1 -1
View File
@@ -120,7 +120,7 @@ Angular's server}.
<button ng-click="hello('Elmo')">Hello</button>
to the `phone-details.html` template.
to the `phone-detail.html` template.
<div style="display: none">
TODO!
+1 -1
View File
@@ -62,7 +62,7 @@ api/ng.$http $http} service.
__`app/js/app.js`.__
<pre>
...
angular.module('phonecatApp', ['phonecatFilters', 'phonecatServices']).
angular.module('phonecatApp', ['ngRoute', 'phonecatControllers','phonecatFilters', 'phonecatServices']).
...
</pre>
+7 -7
View File
@@ -43,7 +43,7 @@ __`app/index.html`.__
<pre>
...
<!-- jQuery is used for JavaScript animations (include this before angular.js) -->
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<!-- required module to enable animation support in AngularJS -->
<script src="lib/angular/angular-animate.js"></script>
@@ -56,6 +56,10 @@ __`app/index.html`.__
...
</pre>
<div class="alert alert-error">
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
</div>
Animations can now be created within the CSS code (`animations.css`) as well as the JavaScript code (`animations.js`).
But before we start, let's create a new module which uses the ngAnimate module as a dependency just like we did before
with `ngResource`.
@@ -153,7 +157,7 @@ __`app/css/animations.css`__
</pre>
As you can see our `phone-listing` CSS class is combined together with the animation hooks that occur when items are
inserted info and removed from the list:
inserted into and removed from the list:
* The `ng-enter` class is applied to the element when a new phone is added to the list and rendered on the page.
* The `ng-move` class is applied when items are moved around in the list.
@@ -194,7 +198,7 @@ This time, instead of the `ng-repeat` element, let's add it to the element conta
In order to do this, we'll have to make some small changes to the HTML code so that we can have more control over our
animations between view changes.
__`app/partials/phone-list.html`.__
__`app/index.html`.__
<pre>
<div class="view-container">
<div ng-view class="view-frame"></div>
@@ -383,10 +387,6 @@ isn't required to do JavaScript animations with AngularJS, but we're going to us
your own JavaScript animation library is beyond the scope of this tutorial. For more on
`jQuery.animate`, see the {@link http://api.jquery.com/animate/ jQuery documentation}.
<div class="alert alert-error">
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
</div>
The `addClass` and `removeClass` callback functions are called whenever an a class is added or removed
on the element that contains the class we registered, which is in this case `.phone`. When the `.active`
class is added to the element (via the `ng-class` directive) the `addClass` JavaScript callback will
Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

+62 -3
View File
@@ -1,4 +1,5 @@
var DOM = require('../src/dom.js').DOM;
var normalizeHeaderToId = require('../src/dom.js').normalizeHeaderToId;
describe('dom', function() {
var dom;
@@ -7,6 +8,31 @@ describe('dom', function() {
dom = new DOM();
});
describe('html', function() {
it('should add ids to all h tags', function() {
dom.html('<h1>Some Header</h1>');
expect(dom.toString()).toContain('<h1 id="some-header">Some Header</h1>');
});
it('should collect <a name> anchors too', function() {
dom.html('<h2>Xxx <a name="foo"></a> and bar <a name="bar"></a>');
expect(dom.anchors).toContain('foo');
expect(dom.anchors).toContain('bar');
})
});
it('should collect h tag ids', function() {
dom.h('Page Title', function() {
dom.html('<h1>Second</h1>xxx <h2>Third</h2>');
dom.h('Another Header', function() {});
});
expect(dom.anchors).toContain('page-title');
expect(dom.anchors).toContain('second');
expect(dom.anchors).toContain('second_third');
expect(dom.anchors).toContain('another-header');
});
describe('h', function() {
it('should render using function', function() {
@@ -25,7 +51,7 @@ describe('dom', function() {
this.html('<h1>sub-heading</h1>');
});
expect(dom.toString()).toContain('<h1 id="heading">heading</h1>');
expect(dom.toString()).toContain('<h2>sub-heading</h2>');
expect(dom.toString()).toContain('<h2 id="sub-heading">sub-heading</h2>');
});
it('should properly number nested headings', function() {
@@ -40,12 +66,45 @@ describe('dom', function() {
expect(dom.toString()).toContain('<h1 id="heading">heading</h1>');
expect(dom.toString()).toContain('<h2 id="heading2">heading2</h2>');
expect(dom.toString()).toContain('<h3>heading3</h3>');
expect(dom.toString()).toContain('<h3 id="heading2_heading3">heading3</h3>');
expect(dom.toString()).toContain('<h1 id="other1">other1</h1>');
expect(dom.toString()).toContain('<h2>other2</h2>');
expect(dom.toString()).toContain('<h2 id="other2">other2</h2>');
});
it('should add nested ids to all h tags', function() {
dom.h('Page Title', function() {
dom.h('Second', function() {
dom.html('some <h1>Third</h1>');
});
});
var resultingHtml = dom.toString();
expect(resultingHtml).toContain('<h1 id="page-title">Page Title</h1>');
expect(resultingHtml).toContain('<h2 id="second">Second</h2>');
expect(resultingHtml).toContain('<h3 id="second_third">Third</h3>');
});
});
describe('normalizeHeaderToId', function() {
it('should ignore content in the parenthesis', function() {
expect(normalizeHeaderToId('One (more)')).toBe('one');
});
it('should ignore html content', function() {
expect(normalizeHeaderToId('Section <a name="section"></a>')).toBe('section');
});
it('should ignore special characters', function() {
expect(normalizeHeaderToId('Section \'!?')).toBe('section');
});
it('should ignore html entities', function() {
expect(normalizeHeaderToId('angular&#39;s-jqlite')).toBe('angulars-jqlite');
});
});
});
+32 -37
View File
@@ -34,8 +34,8 @@ describe('ngdoc', function() {
var d1 = new Doc('@name a.b.c').parse();
var d2 = new Doc('@name a.b.ng-c').parse();
var d3 = new Doc('@name some text: more text').parse();
expect(ngdoc.metadata([d1])[0].shortName).toEqual('c');
expect(ngdoc.metadata([d2])[0].shortName).toEqual('ng-c');
expect(ngdoc.metadata([d1])[0].shortName).toEqual('a.b.c');
expect(ngdoc.metadata([d2])[0].shortName).toEqual('a.b.ng-c');
expect(ngdoc.metadata([d3])[0].shortName).toEqual('more text');
});
@@ -114,17 +114,8 @@ describe('ngdoc', function() {
function property(name) {
return function(obj) {return obj[name];};
}
function noop() {}
function doc(type, name){
return {
id: name,
ngdoc: type,
keywords: noop
};
}
var dev_guide_overview = doc('overview', 'dev_guide.overview');
var dev_guide_bootstrap = doc('function', 'dev_guide.bootstrap');
var dev_guide_overview = new Doc({ngdoc:'overview', id:'dev_guide.overview', text: ''});
var dev_guide_bootstrap = new Doc({ngdoc:'function', id:'dev_guide.bootstrap', text: ''});
it('should put angular.fn() in front of dev_guide.overview, etc', function() {
expect(ngdoc.metadata([dev_guide_overview, dev_guide_bootstrap]).map(property('id')))
@@ -262,33 +253,37 @@ describe('ngdoc', function() {
expect(docs[0].events).toEqual([eventA, eventB]);
expect(docs[0].properties).toEqual([propA, propB]);
});
});
describe('checkBrokenLinks', function() {
var docs;
describe('links checking', function() {
var docs;
beforeEach(function() {
spyOn(console, 'log');
docs = [new Doc({section: 'api', id: 'fake.id1', links: ['non-existing-link']}),
new Doc({section: 'api', id: 'fake.id2'}),
new Doc({section: 'api', id: 'fake.id3'})];
});
beforeEach(function() {
spyOn(console, 'log');
docs = [new Doc({section: 'api', id: 'fake.id1', anchors: ['one']}),
new Doc({section: 'api', id: 'fake.id2'}),
new Doc({section: 'api', id: 'fake.id3'})];
});
it('should log warning when any link doesn\'t exist', function() {
ngdoc.merge(docs);
expect(console.log).toHaveBeenCalled();
expect(console.log.argsForCall[0][0]).toContain('WARNING:');
});
it('should log warning when a linked page does not exist', function() {
docs.push(new Doc({section: 'api', id: 'with-broken.link', links: ['non-existing-link']}))
ngdoc.checkBrokenLinks(docs);
expect(console.log).toHaveBeenCalled();
var warningMsg = console.log.argsForCall[0][0]
expect(warningMsg).toContain('WARNING:');
expect(warningMsg).toContain('non-existing-link');
expect(warningMsg).toContain('api/with-broken.link');
});
it('should say which link doesn\'t exist', function() {
ngdoc.merge(docs);
expect(console.log.argsForCall[0][0]).toContain('non-existing-link');
});
it('should say where is the non-existing link', function() {
ngdoc.merge(docs);
expect(console.log.argsForCall[0][0]).toContain('api/fake.id1');
});
it('should log warning when a linked anchor does not exist', function() {
docs.push(new Doc({section: 'api', id: 'with-broken.link', links: ['api/fake.id1#non-existing']}))
ngdoc.checkBrokenLinks(docs);
expect(console.log).toHaveBeenCalled();
var warningMsg = console.log.argsForCall[0][0]
expect(warningMsg).toContain('WARNING:');
expect(warningMsg).toContain('non-existing');
expect(warningMsg).toContain('api/with-broken.link');
});
});
@@ -524,7 +519,7 @@ describe('ngdoc', function() {
doc.ngdoc = 'filter';
doc.parse();
expect(doc.html()).toContain(
'<h3 id="Animations">Animations</h3>\n' +
'<h3 id="usage_animations">Animations</h3>\n' +
'<div class="animations">' +
'<ul>' +
'<li>enter - Add text</li>' +
@@ -541,7 +536,7 @@ describe('ngdoc', function() {
var doc = new Doc('@ngdoc overview\n@name angular\n@description\n#heading\ntext');
doc.parse();
expect(doc.html()).toContain('text');
expect(doc.html()).toContain('<h2>heading</h2>');
expect(doc.html()).toContain('<h2 id="heading">heading</h2>');
expect(doc.html()).not.toContain('Description');
});
});
+1 -1
View File
@@ -20,7 +20,7 @@ describe('Docs Links', function() {
});
it('should have an "view source" button', function() {
spyOn(gruntUtil, 'getVersion').andReturn({cdn: '1.2.299'});
spyOn(gruntUtil, 'getVersion').andReturn({full: '1.2.299'});
expect(doc.html()).
toContain('<a href="http://github.com/angular/angular.js/tree/v1.2.299/test.js#L42" class="view-source btn btn-action"><i class="icon-zoom-in"> </i> View source</a>');
+56 -17
View File
@@ -4,6 +4,7 @@
exports.DOM = DOM;
exports.htmlEscape = htmlEscape;
exports.normalizeHeaderToId = normalizeHeaderToId;
//////////////////////////////////////////////////////////
@@ -16,10 +17,36 @@ function htmlEscape(text){
.replace(/\}\}/g, '<span>}}</span>');
}
function nonEmpty(header) {
return !!header;
}
function idFromCurrentHeaders(headers) {
if (headers.length === 1) return headers[0];
// Do not include the first level title, as that's the title of the page.
return headers.slice(1).filter(nonEmpty).join('_');
}
function normalizeHeaderToId(header) {
if (typeof header !== 'string') {
return '';
}
return header.toLowerCase()
.replace(/<.*>/g, '') // html tags
.replace(/[\!\?\:\.\']/g, '') // special characters
.replace(/&#\d\d;/g, '') // html entities
.replace(/\(.*\)/mg, '') // stuff in parenthesis
.replace(/\s$/, '') // trailing spaces
.replace(/\s+/g, '-'); // replace whitespaces with dashes
}
function DOM() {
this.out = [];
this.headingDepth = 0;
this.currentHeaders = [];
this.anchors = [];
}
var INLINE_TAGS = {
@@ -44,17 +71,28 @@ DOM.prototype = {
},
html: function(html) {
if (html) {
var headingDepth = this.headingDepth;
for ( var i = 10; i > 0; --i) {
html = html
.replace(new RegExp('<h' + i + '(.*?)>([\\s\\S]+)<\/h' + i +'>', 'gm'), function(_, attrs, content){
var tag = 'h' + (i + headingDepth);
return '<' + tag + attrs + '>' + content + '</' + tag + '>';
});
}
this.out.push(html);
}
if (!html) return;
var self = this;
// rewrite header levels, add ids and collect the ids
html = html.replace(/<h(\d)(.*?)>([\s\S]+?)<\/h\1>/gm, function(_, level, attrs, content) {
level = parseInt(level, 10) + self.headingDepth; // change header level based on the context
self.currentHeaders[level - 1] = normalizeHeaderToId(content);
self.currentHeaders.length = level;
var id = idFromCurrentHeaders(self.currentHeaders);
self.anchors.push(id);
return '<h' + level + attrs + ' id="' + id + '">' + content + '</h' + level + '>';
});
// collect anchors
html = html.replace(/<a name="(\w*)">/g, function(match, anchor) {
self.anchors.push(anchor);
return match;
});
this.out.push(html);
},
tag: function(name, attr, text) {
@@ -85,17 +123,18 @@ DOM.prototype = {
h: function(heading, content, fn){
if (content==undefined || (content instanceof Array && content.length == 0)) return;
this.headingDepth++;
this.currentHeaders[this.headingDepth - 1] = normalizeHeaderToId(heading);
this.currentHeaders.length = this.headingDepth;
var className = null,
anchor = null;
if (typeof heading == 'string') {
var id = heading.
replace(/\(.*\)/mg, '').
replace(/[^\d\w\$]/mg, '.').
replace(/-+/gm, '-').
replace(/-*$/gm, '');
var id = idFromCurrentHeaders(this.currentHeaders);
this.anchors.push(id);
anchor = {'id': id};
var classNameValue = id.toLowerCase().replace(/[._]/mg, '-');
var classNameValue = this.currentHeaders[this.headingDepth - 1]
if(classNameValue == 'hide') classNameValue = '';
className = {'class': classNameValue};
}
+2
View File
@@ -55,6 +55,8 @@ writer.makeDir('build/docs/', true).then(function() {
fileFutures.push(writer.output('partials/' + doc.section + '/' + id + '.html', doc.html()));
});
ngdoc.checkBrokenLinks(docs);
writeTheRest(fileFutures);
return Q.deep(fileFutures);
+152 -40
View File
@@ -36,6 +36,7 @@ exports.trim = trim;
exports.metadata = metadata;
exports.scenarios = scenarios;
exports.merge = merge;
exports.checkBrokenLinks = checkBrokenLinks;
exports.Doc = Doc;
exports.ngVersions = function() {
@@ -52,6 +53,7 @@ exports.ngVersions = function() {
return expandVersions(sortVersionsNatrually(versions), exports.ngCurrentVersion().full);
function expandVersions(versions, latestVersion) {
var RC_VERSION = /rc\d/;
//copy the array to avoid changing the versions param data
//the latest version is not on the git tags list, but
//docs.angularjs.org will always point to master as of 1.2
@@ -62,20 +64,10 @@ exports.ngVersions = function() {
var version = versions[i],
split = version.split('.'),
isMaster = version == latestVersion,
isStable = split[1] % 2 == 0;
isStable = split[1] % 2 === 0 && !RC_VERSION.test(version);
var title = 'AngularJS - v' + version;
//anything that is stable before being unstable is a rc1 version
//just like with AngularJS 1.2.0rc1 (even though it's apart of the
//1.1.5 API
if(isMaster || (isStable && !firstUnstable)) {
isStable = false;
}
else {
firstUnstable = firstUnstable || version;
}
var docsPath = version < '1.0.2' ? 'docs-' + version : 'docs';
var url = isMaster ?
@@ -169,6 +161,7 @@ function Doc(text, file, line) {
this.methods = this.methods || [];
this.events = this.events || [];
this.links = this.links || [];
this.anchors = this.anchors || [];
}
Doc.METADATA_IGNORE = (function() {
var words = fs.readFileSync(__dirname + '/ignore.words', 'utf8');
@@ -211,6 +204,15 @@ Doc.prototype = {
return words.join(' ');
},
shortDescription : function() {
if (!this.description) return this.description;
var text = this.description.split("\n")[0];
text = text.replace(/<.+?\/?>/g, '');
text = text.replace(/{/g,'&#123;');
text = text.replace(/}/g,'&#125;');
return text;
},
getMinerrNamespace: function () {
if (this.ngdoc !== 'error') {
throw new Error('Tried to get the minErr namespace, but @ngdoc ' +
@@ -242,6 +244,14 @@ Doc.prototype = {
* @returns {string} Absolute url
*/
convertUrlToAbsolute: function(url) {
var hashIdx = url.indexOf('#');
// Lowercase hash parts of the links,
// so that we can keep correct API names even when the urls are lowercased.
if (hashIdx !== -1) {
url = url.substr(0, hashIdx) + url.substr(hashIdx).toLowerCase();
}
if (url.substr(-1) == '/') return url + 'index';
if (url.match(/\//)) return url;
return this.section + '/' + url;
@@ -461,11 +471,20 @@ Doc.prototype = {
(this.ngdoc === 'error' ? this.name : '') ||
(((this.file||'').match(/.*(\/|\\)([^(\/|\\)]*)\.ngdoc/)||{})[2]) || // try to extract it from file name
this.name; // default to name
this.moduleName = parseModuleName(this.id);
this.description = this.markdown(this.description);
this.example = this.markdown(this.example);
this['this'] = this.markdown(this['this']);
return this;
function parseModuleName(id) {
var module = id.split('.')[0];
if(module == 'angular') {
module = 'ng';
}
return module;
}
function flush() {
if (atName) {
var text = trim(atText.join('\n')), match;
@@ -528,10 +547,22 @@ Doc.prototype = {
self = this,
minerrMsg;
var gitTagFromFullVersion = function(version) {
var match = version.match(/-(\w{7})/);
if (match) {
// git sha
return match[1];
}
// git tag
return 'v' + version;
};
if (this.section === 'api') {
dom.tag('a', {
href: 'http://github.com/angular/angular.js/tree/v' +
gruntUtil.getVersion().cdn + '/' + self.file + '#L' + self.line,
href: 'http://github.com/angular/angular.js/tree/' +
gitTagFromFullVersion(gruntUtil.getVersion().full) + '/' + self.file + '#L' + self.line,
class: 'view-source btn btn-action' }, function(dom) {
dom.tag('i', {class:'icon-zoom-in'}, ' ');
dom.text(' View source');
@@ -569,6 +600,8 @@ Doc.prototype = {
dom.h('Example', self.example, dom.html);
});
self.anchors = dom.anchors;
return dom.toString();
//////////////////////////
@@ -606,7 +639,7 @@ Doc.prototype = {
dom.html('<a href="api/ngAnimate.$animate">Click here</a> to learn more about the steps involved in the animation.');
}
if(params.length > 0) {
dom.html('<h2 id="parameters">Parameters</h2>');
dom.html('<h2>Parameters</h2>');
dom.html('<table class="variables-matrix table table-bordered table-striped">');
dom.html('<thead>');
dom.html('<tr>');
@@ -660,7 +693,7 @@ Doc.prototype = {
html_usage_returns: function(dom) {
var self = this;
if (self.returns) {
dom.html('<h2 id="returns">Returns</h2>');
dom.html('<h2>Returns</h2>');
dom.html('<table class="variables-matrix">');
dom.html('<tr>');
dom.html('<td>');
@@ -784,7 +817,7 @@ Doc.prototype = {
dom.text(prefix);
dom.text(param.optional ? '[' : '');
var parts = param.name.split('|');
dom.text(parts[skipSelf ? 0 : 1] || parts[0]);
dom.text(dashCase(parts[skipSelf ? 0 : 1] || parts[0]));
}
if (BOOLEAN_ATTR[param.name]) {
dom.text(param.optional ? ']' : '');
@@ -1078,7 +1111,7 @@ function scenarios(docs){
function metadata(docs){
var pages = [];
docs.forEach(function(doc){
var path = (doc.name || '').split(/(\.|\:\s*)/);
var path = (doc.name || '').split(/(\:\s*)/);
for ( var i = 1; i < path.length; i++) {
path.splice(i, 1);
}
@@ -1094,10 +1127,12 @@ function metadata(docs){
name: title(doc),
shortName: shortName,
type: doc.ngdoc,
keywords:doc.keywords()
moduleName: doc.moduleName,
shortDescription: doc.shortDescription(),
keywords: doc.keywords()
});
});
pages.sort(keywordSort);
pages.sort(sidebarSort);
return pages;
}
@@ -1130,7 +1165,60 @@ var KEYWORD_PRIORITY = {
'.dev_guide.di': 8,
'.dev_guide.unit-testing': 9
};
function keywordSort(a, b){
var GUIDE_PRIORITY = [
'introduction',
'overview',
'concepts',
'dev_guide.mvc',
'dev_guide.mvc.understanding_controller',
'dev_guide.mvc.understanding_model',
'dev_guide.mvc.understanding_view',
'dev_guide.services.understanding_services',
'dev_guide.services.managing_dependencies',
'dev_guide.services.creating_services',
'dev_guide.services.injecting_controllers',
'dev_guide.services.testing_services',
'dev_guide.services.$location',
'dev_guide.services',
'databinding',
'dev_guide.templates.css-styling',
'dev_guide.templates.filters.creating_filters',
'dev_guide.templates.filters',
'dev_guide.templates.filters.using_filters',
'dev_guide.templates',
'di',
'providers',
'module',
'scope',
'expression',
'bootstrap',
'directive',
'compiler',
'forms',
'animations',
'dev_guide.e2e-testing',
'dev_guide.unit-testing',
'i18n',
'ie',
'migration',
];
function sidebarSort(a, b){
priorityA = GUIDE_PRIORITY.indexOf(a.id);
priorityB = GUIDE_PRIORITY.indexOf(b.id);
if (priorityA > -1 || priorityB > -1) {
return priorityA < priorityB ? -1 : (priorityA > priorityB ? 1 : 0);
}
function mangleName(doc) {
var path = doc.id.split(/\./);
var mangled = [];
@@ -1211,22 +1299,7 @@ function merge(docs){
});
for(var i = 0; i < docs.length;) {
var doc = docs[i];
// check links - do they exist ?
doc.links.forEach(function(link) {
// convert #id to path#id
if (link[0] == '#') {
link = doc.section + '/' + doc.id.split('#').shift() + link;
}
link = link.split('#').shift();
if (!byFullId[link]) {
console.log('WARNING: In ' + doc.section + '/' + doc.id + ', non existing link: "' + link + '"');
}
});
// merge into parents
if (findParent(doc, 'method') || findParent(doc, 'property') || findParent(doc, 'event')) {
if (findParent(docs[i], 'method') || findParent(docs[i], 'property') || findParent(docs[i], 'event')) {
docs.splice(i, 1);
} else {
i++;
@@ -1255,6 +1328,39 @@ function merge(docs){
}
//////////////////////////////////////////////////////////
function checkBrokenLinks(docs) {
var byFullId = Object.create(null);
docs.forEach(function(doc) {
byFullId[doc.section + '/' + doc.id] = doc;
if (doc.section === 'api') {
doc.anchors.push('directive', 'service', 'filter', 'function');
}
});
docs.forEach(function(doc) {
doc.links.forEach(function(link) {
// convert #id to path#id
if (link[0] == '#') {
link = doc.section + '/' + doc.id.split('#').shift() + link;
}
var parts = link.split('#');
var pageLink = parts[0];
var anchorLink = parts[1];
var linkedPage = byFullId[pageLink];
if (!linkedPage) {
console.log('WARNING: ' + doc.section + '/' + doc.id + ' (defined in ' + doc.file + ') points to a non existing page "' + link + '"!');
} else if (anchorLink && linkedPage.anchors.indexOf(anchorLink) === -1) {
console.log('WARNING: ' + doc.section + '/' + doc.id + ' (defined in ' + doc.file + ') points to a non existing anchor "' + link + '"!');
}
});
});
}
function property(name) {
return function(value){
return value[name];
@@ -1280,10 +1386,16 @@ function explainModuleInstallation(moduleName){
' &lt;script src=&quot;angular.js&quot;&gt;\n' +
' &lt;script src=&quot;' + modulePackageFile + '&quot;&gt;</pre></code>' +
'<p>You can also find this file on the [Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs), ' +
'<a href="http://bower.io/">Bower</a> (as <code>' + modulePackage + '</code>), ' +
'and on <a href="http://code.angularjs.org/">code.angularjs.org</a>.</p>' +
'<p>You can download this file from the following places:</p>' +
'<ul>' +
'<li>[Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs)<br>' +
'e.g. <code>"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/' + modulePackageFile + '"</code></li>' +
'<li>[Bower](http://bower.io)<br>' +
'e.g. <code>bower install ' + modulePackage + '@X.Y.Z</code></li>' +
'<li><a href="http://code.angularjs.org/">code.angularjs.org</a><br>' +
'e.g. <code>"//code.angularjs.org/X.Y.Z/' + modulePackageFile + '"</code></li>' +
'</ul>' +
'<p>where X.Y.Z is the AngularJS version you are running.</p>' +
'<p>Then load the module in your application by adding it as a dependent module:</p><pre><code>' +
' angular.module(\'app\', [\'' + ngMod + '\']);</pre></code>' +
-42
View File
@@ -37,40 +37,6 @@
opacity:1;
}
.expand.ng-enter,
.expand.ng-move,
.expand.ng-leave {
-webkit-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all;
-moz-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all;
-o-transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all;
transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all;
}
.expand.ng-move,
.expand.ng-enter {
opacity:0;
line-height:0;
height:0!important;
}
.expand.ng-move.ng-move-active,
.expand.ng-enter.ng-enter-active {
opacity:1;
line-height:20px;
height:20px!important;
}
.expand.ng-leave {
opacity:1;
height:20px;
}
.expand.ng-leave.ng-leave-active {
opacity:0;
height:0;
}
.fade-in.ng-enter,
.fade-in.ng-move,
.fade-in.ng-hide-add,
.fade-in.ng-hide-remove,
.foldout.ng-enter,
.foldout.ng-move,
.foldout.ng-hide-add,
@@ -81,10 +47,6 @@
transition:0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) all;
}
.fade-in.ng-enter,
.fade-in.ng-move,
.fade-in.ng-hide-remove,
.fade-in.ng-hide-add.ng-hide-active,
.foldout.ng-hide-remove,
.foldout.ng-hide-add.ng-hide-active,
.foldout.ng-enter,
@@ -92,10 +54,6 @@
opacity:0;
}
.fade-in.ng-enter.ng-enter-active,
.fade-in.ng-move.ng-move-active,
.fade-in.ng-hide-remove.ng-hide-remove-active,
.fade-in.ng-hide-add,
.foldout.ng-move.ng-move-active,
.foldout.ng-hide-remove.ng-hide-remove-active,
.foldout.ng-hide-add,
+43 -12
View File
@@ -45,62 +45,62 @@
/* =============================== */
.form-search .dropdown-menu {
.side-navigation .dropdown-menu {
margin-left: 10px;
}
.form-search .code {
.side-navigation .code {
font-family: monospace;
font-weight: bold;
font-size: 13px;
color: black;
}
.form-search > ul.nav > li.module {
.side-navigation > ul.nav > li.module {
background-color: #d3d3d3;
}
.form-search > ul.nav > li.section {
.side-navigation > ul.nav > li.section {
background-color: #ebebeb;
min-height: 14px;
}
.form-search > ul.nav > li.last {
.side-navigation > ul.nav > li.last {
padding-bottom: 1em;
}
.form-search > ul.nav > li.last + li.api-list-item {
.side-navigation > ul.nav > li.last + li.api-list-item {
margin-top:-1em;
padding-bottom: 1em;
}
.form-search .well {
.side-navigation .well {
border-color: #d3d3d3;
padding-top: 0;
padding-bottom: 0;
margin-bottom: 15px;
}
.form-search .well .nav-header {
.side-navigation .well .nav-header {
text-transform: none;
margin-top: 0;
margin-left: -15px;
margin-right: -15px;
}
.form-search .well .nav-header a {
.side-navigation .well .nav-header a {
text-transform: none;
color: black;
}
.form-search .well .nav-header a:hover {
.side-navigation .well .nav-header a:hover {
background-color: inherit;
}
.form-search .well li {
.side-navigation .well li {
line-height: 14px;
}
.form-search .well .guide {
.side-navigation .well .guide {
float: right;
padding-top: 0;
color: gray;
@@ -508,3 +508,34 @@ pre ol li {
font-size: 16px;
word-break: normal;
}
.text-info {
color:#3a87ad;
}
.definition-table tr > td:first-child {
font-weight:bold;
width:30%;
}
.definition-table.spaced {
margin-bottom:30px;
}
.component-heading {
text-transform:capitalize;
}
.component-breakdown {
margin-bottom:30px;
padding-bottom:30px;
border-bottom:1px solid #aaa;
}
td.success {
background-color: #dff0d8;
}
td.error {
background-color: #f2dede;
}
+18 -33
View File
@@ -191,22 +191,22 @@
<input type="text"
name="as_q"
class="search-query"
placeholder="Search"
placeholder="Click to focus or press '/' to search"
ng-change="search(q)"
ng-model="q"
docs-search-input
autocomplete="off" />
</form>
<div ng-show="hasResults" class="search-results">
<a href="" ng-click="hideResults()" class="search-close">
<span class="icon-remove-sign"></span>
</a>
<div ng-repeat="(key, value) in results" class="search-group" ng-class="colClassName">
<h4>{{ key }}</h4>
<div ng-repeat="item in value" class="search-result">
<a ng-click="hideResults()" href="{{ item.url }}">{{ item.shortName }}</a>
</div>
</div>
<a href="" ng-click="hideResults()" class="search-close">
<span class="icon-remove-sign"></span>
</a>
</div>
</div>
</div>
@@ -256,38 +256,24 @@
class="docs-version-jump">
</select>
</div>
<form class="form-search" ng-submit="submitForm()">
<div class="dropdown search"
ng-class="{open: focused && bestMatch.rank > 0 && bestMatch.page != currentPage}">
<input type="text" ng-model="search" placeholder="search the docs"
tabindex="1" accesskey="s" class="input-medium search-query" />
<ul class="dropdown-menu">
<li>
<a href="{{bestMatch.page.url}}">{{bestMatch.page.shortName}}</a>
</li>
</ul>
</div>
<div class="spacer"></div>
<div ng-show="search">Filtered results:</div>
<div class="side-navigation">
<ul class="nav nav-list" ng-hide="page">
<li ng-repeat="page in pages track by page.url" ng-class="navClass(page)" class="expand api-list-item">
<li ng-repeat="page in pages track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
</ul>
<ul class="nav nav-list well api-list-item fade-in" ng-repeat="namespace in namespaces track by namespace.url">
<ul class="nav nav-list well api-list-item" ng-repeat="namespace in namespaces track by namespace.url">
<li class="nav-header module">
<a class="code" href="{{namespace.url}}">{{namespace.name}}</a>
</li>
<li ng-repeat="page in namespace.errors track by page.url" ng-class="navClass(page)" class="expand api-list-item">
<li ng-repeat="page in namespace.errors track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
</ul>
<ul class="nav nav-list well api-list-item fade-in" ng-repeat="module in modules track by module.url">
<ul class="nav nav-list well api-list-item" ng-repeat="module in modules track by module.url">
<li class="nav-header module">
<a class="guide" href="{{URL.module}}">module</a>
<a class="code" href="{{module.url}}">{{module.name}}</a>
@@ -296,21 +282,21 @@
<li class="nav-header section" ng-show="module.directives">
<a href="{{URL.directive}}" class="guide">directive</a>
</li>
<li ng-repeat="page in module.directives track by page.url" ng-class="navClass(page)" class="expand api-list-item">
<li ng-repeat="page in module.directives track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
<li class="nav-header section" ng-show="module.filters">
<a href="{{URL.filter}}" class="guide">filter</a>
</li>
<li ng-repeat="page in module.filters track by page.url" ng-class="navClass(page)" class="expand api-list-item">
<li ng-repeat="page in module.filters track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
<li class="nav-header section" ng-show="module.services">
<a href="{{URL.service}}" class="guide">service</a>
</li>
<li ng-repeat="service in module.services track by service.instance.url" ng-class="navClass(service.instance, service.provider)" class="api-list-item expand">
<li ng-repeat="service in module.services track by service.instance.url" ng-class="navClass(service.instance, service.provider)" class="api-list-item">
<a ng-show="service.provider" class="pull-right" href="{{service.provider.url}}" tabindex="2"><i class="icon-cog"></i></a>
<a href="{{service.instance.url}}" tabindex="2">{{service.name}}</a>
</li>
@@ -318,7 +304,7 @@
<li class="nav-header section" ng-show="module.types">
<a href="{{URL.type}}" class="guide">Types</a>
</li>
<li ng-repeat="page in module.types track by page.url" ng-class="navClass(page)" class="expand api-list-item">
<li ng-repeat="page in module.types track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.shortName}}</a>
</li>
@@ -326,13 +312,13 @@
<a href="{{URL.api}}" class="global guide">global APIs</a>
&nbsp;
</li>
<li ng-repeat="page in module.globals track by page.url" ng-class="navClass(page)" class="expand api-list-item">
<li ng-repeat="page in module.globals track by page.url" ng-class="navClass(page)" class="api-list-item">
<a href="{{page.url}}" tabindex="2">{{page.id}}</a>
</li>
</ul>
</form>
</div>
</div>
</div>
<div class="span9">
@@ -349,9 +335,8 @@
<div ng-hide="loading" ng-include src="currentPage.partialUrl" onload="afterPartialLoaded()" autoscroll class="content slide-reveal"></div>
<div id="disqus" class="disqus">
<h2>Discussion</h2>
<div id="disqus_thread" class="content-panel-content"></div>
<div class="alert alert-info">
<a href="http://blog.angularjs.org/2013/11/farewell-disqus.html">Where did Disqus go?</a>
</div>
</div>
</div>
@@ -379,7 +364,7 @@
<footer class="footer">
<div class="container">
<p class="pull-right"><a href="#">Back to top</a></p>
<p class="pull-right"><a back-to-top href="#">Back to top</a></p>
<p>
Super-powered by Google ©2010-2012
+82 -74
View File
@@ -132,9 +132,19 @@ docsApp.directive.focused = function($timeout) {
};
};
docsApp.directive.docsSearchInput = function() {
docsApp.directive.docsSearchInput = ['$document',function($document) {
return function(scope, element, attrs) {
var ESCAPE_KEY_KEYCODE = 27;
var ESCAPE_KEY_KEYCODE = 27,
FORWARD_SLASH_KEYCODE = 191;
angular.element($document[0].body).bind('keydown', function(event) {
var input = element[0];
if(event.keyCode == FORWARD_SLASH_KEYCODE && document.activeElement != input) {
event.stopPropagation();
event.preventDefault();
input.focus();
}
});
element.bind('keydown', function(event) {
if(event.keyCode == ESCAPE_KEY_KEYCODE) {
event.stopPropagation();
@@ -145,7 +155,7 @@ docsApp.directive.docsSearchInput = function() {
}
});
};
};
}];
docsApp.directive.code = function() {
@@ -197,6 +207,50 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
}
};
docsApp.directive.docModuleComponents = function() {
return {
template: ' <div class="component-breakdown">' +
' <h2>Module Components</h2>' +
' <div ng-repeat="(key, section) in components">' +
' <h3 class="component-heading" id="{{ section.type }}">{{ section.title }}</h3>' +
' <table class="definition-table">' +
' <tr>' +
' <th>Name</th>' +
' <th>Description</th>' +
' </tr>' +
' <tr ng-repeat="component in section.components">' +
' <td><a ng-href="{{ component.url }}">{{ component.shortName }}</a></td>' +
' <td>{{ component.shortDescription }}</td>' +
' </tr>' +
' </table>' +
' </div>' +
' </div>',
scope : {
module : '@docModuleComponents'
},
controller : ['$scope', '$anchorScroll', '$timeout', 'sections',
function($scope, $anchorScroll, $timeout, sections) {
var validTypes = ['property','function','directive','service','object','filter'];
var components = {};
angular.forEach(sections.api, function(item) {
if(item.moduleName == $scope.module) {
var type = item.type;
if(type == 'object') type = 'service';
if(validTypes.indexOf(type) >= 0) {
components[type] = components[type] || {
title : type,
type : type,
components : []
};
components[type].components.push(item);
}
}
});
$scope.components = components;
$timeout($anchorScroll, 0, false);
}]
};
};
docsApp.directive.docTutorialNav = function(templateMerge) {
var pages = [
@@ -318,6 +372,21 @@ docsApp.directive.errorDisplay = ['$location', 'errorLinkFilter', function ($loc
}];
/**
* backToTop Directive
* @param {Function} $anchorScroll
*
* @description Ensure that the browser scrolls when the anchor is clicked
*/
docsApp.directive.backToTop = ['$anchorScroll', function($anchorScroll) {
return function link(scope, element) {
element.on('click', function(event) {
scope.$apply($anchorScroll);
});
};
}];
docsApp.serviceFactory.angularUrls = function($document) {
var urls = {};
@@ -359,7 +428,7 @@ docsApp.serviceFactory.prepareDefaultAppModule = function() {
var moduleName = 'App';
return {
module : moduleName,
script : "angular.module('" + moduleName + "', [" +
script : "angular.module('" + moduleName + "', [" +
(deps.length ? "'" + deps.join("','") + "'" : "") + "]);\n\n"
};
};
@@ -622,15 +691,10 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
};
};
$scope.submitForm = function() {
$scope.bestMatch && $location.path($scope.bestMatch.page.url);
};
$scope.afterPartialLoaded = function() {
var currentPageId = $location.path();
$scope.partialTitle = $scope.currentPage.shortName;
$window._gaq.push(['_trackPageview', currentPageId]);
loadDisqus(currentPageId);
};
/** stores a cookie that is used by apache to decide which manifest ot send */
@@ -660,6 +724,9 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
cookbook: 'Examples',
error: 'Error Reference'
};
populateComponentsList();
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
// ignore non-doc links which are used in examples
if (DOCS_PATH.test(path)) {
@@ -675,8 +742,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
$scope.partialTitle = 'Error: Page Not Found!';
}
updateSearch();
populateComponentsList();
// Update breadcrumbs
var breadcrumb = $scope.breadcrumb = [],
@@ -717,10 +783,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
}
});
$scope.$watch('search', updateSearch);
/**********************************
Initialize
***********************************/
@@ -752,27 +814,22 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
Private methods
***********************************/
function updateSearch() {
function populateComponentsList() {
var area = $location.path().split('/')[1];
area = /^index-\w/.test(area) ? 'api' : area;
var moduleCache = {},
namespaceCache = {},
pages = sections[$location.path().split('/')[1]],
pages = sections[area],
modules = $scope.modules = [],
namespaces = $scope.namespaces = [],
globalErrors = $scope.globalErrors = [],
otherPages = $scope.pages = [],
search = $scope.search,
bestMatch = {page: null, rank:0};
search = $scope.search;
angular.forEach(pages, function(page) {
var match,
id = page.id;
if (!(match = rank(page, search))) return;
if (match.rank > bestMatch.rank) {
bestMatch = match;
}
if (page.id == 'index') {
//skip
} else if (page.section != 'api') {
@@ -808,10 +865,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
});
$scope.bestMatch = bestMatch;
/*************/
function module(name) {
var module = moduleCache[name];
@@ -852,51 +905,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
}
return namespace;
}
function rank(page, terms) {
var ranking = {page: page, rank:0},
keywords = page.keywords,
title = page.shortName.toLowerCase();
terms && angular.forEach(terms.toLowerCase().split(' '), function(term) {
var index;
if (ranking) {
if (keywords.indexOf(term) == -1) {
ranking = null;
} else {
ranking.rank ++; // one point for each term found
if ((index = title.indexOf(term)) != -1) {
ranking.rank += 20 - index; // ten points if you match title
}
}
}
});
return ranking;
}
}
function loadDisqus(currentPageId) {
// http://docs.disqus.com/help/2/
window.disqus_shortname = 'angularjs-next';
window.disqus_identifier = currentPageId;
window.disqus_url = 'http://docs.angularjs.org' + currentPageId;
if ($location.host() == 'localhost') {
return; // don't display disqus on localhost, comment this out if needed
//window.disqus_developer = 1;
}
// http://docs.disqus.com/developers/universal/
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://angularjs.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] ||
document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
angular.element(document.getElementById('disqus_thread')).html('');
}
};
+1
View File
@@ -159,6 +159,7 @@ function outputLocale(localeInfo, localeID) {
localeObj.id = correctedLocaleId(localeID);
var prefix =
"'use strict';\n" +
'angular.module("ngLocale", [], ["$provide", function($provide) {\n' +
'var PLURAL_CATEGORY = {' +
'ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"' +

Some files were not shown because too many files have changed in this diff Show More