Compare commits

...

1557 Commits

Author SHA1 Message Date
Igor Minar 56817e9faa chore(release): cut the 1.0.8 bubble-burst release 2013-08-22 11:20:23 -07:00
Igor Minar e87fb8a8e1 chore(grunt): ensure that grunt uses zip for compression 2013-08-22 11:19:53 -07:00
Igor Minar 5be0fc40ed docs(changelog): release notes for 1.0.8 bubble-burst 2013-08-22 11:07:45 -07:00
Igor Minar a98337b359 docs(CHANGELOG): update changelog 2013-08-22 11:07:41 -07:00
Igor Minar 143d016899 docs(CHANGELOG): release notes for 1.2.0-rc1 spooky-giraffe 2013-08-22 11:07:36 -07:00
ghodss 3d70e55d72 docs(guide): warn about module creation versus retrieval
Updated Module documentation to include the suggestion of the top-rated comment: "This documentation should warn that "angular.module('myModule', [])" always creates a new module, but "angular.module('myModule')" always retrieves an existing reference."
2013-08-22 10:59:29 -07:00
Igor Minar dbcc44dc80 revert: feat(ngForm): Supports expression in form names
This reverts commit 4407e81c61.

No features or breaking changes in the stable branch please.
2013-08-22 10:22:17 -07:00
Igor Minar db87fd52ca chore(changelog.js): pickup breaking changes f/ chore/refactor commits 2013-08-22 10:07:41 -07:00
Marcel Morgan 792509e987 docs(guide): grammatical corrections to Form and Control definitions 2013-08-22 09:15:50 -07:00
Igor Minar 166e0d63d0 revert: fix($compile): correct controller instantiation...
fix($compile): correct controller for async directives

This reverts commit 51d32243fe
as well as commit   9c51d50318

Changing ordering of events in stable branch is not a good idea.
2013-08-21 01:27:58 -07:00
Igor Minar 0d7f19bb62 revert: fix($compile): always instantiate controllers...
fix($compile): always instantiate controllers in parent->child order

This reverts commit 683fd713c4.

It turns out that there is some existing code that relies on the
incorrect timing. Rather than breaking these apps that depend on
stable releases, we are going to keep this changeo only in master
and the apps will need to migrate to the correc timing during the
1.2 upgrade.
2013-08-21 01:21:02 -07:00
Michał Gołębiowski 607045d592 fix(package.json): add a repository field
The `npm install` command complains about the missing repository field.

Closes #3674
2013-08-20 23:56:38 -07:00
Chirayu Krishnappa 51d32243fe fix($compile): correct controller instantiation for async directives
This fixes regression introduced by #3514 (9c51d503) - this commit is being
reverted here and a better fix is included.

The regression caused the controller to be instantiated before the isolate scope
was initialized.

Closes #3493
Closes #3482
Closes #3537
Closes #3540
2013-08-20 18:51:07 -07:00
Reto Aebersold 1c1a1bc9ed style(docs): replace CRLF by LF in svg header logo 2013-08-16 20:06:35 -07:00
Brian Ford 553fdb318f fix(grunt): fix regex in grunt util to handle pre-release versions
NOTE: this also includes a temporary work-around for Bower
2013-08-15 12:43:05 -07:00
Rob Dodson 607ed4ee46 docs($cookies): add info about angular-cookies.js
per the [top comment here](http://docs.angularjs.org/api/ngCookies.$cookies#comment-912064775)

updating documentation so it matches [$resource](http://docs.angularjs.org/api/ngResource.$resource)
and instructs the user to include the `angular-cookies.js` and load `ngCookies`.

Closes #3607
2013-08-15 10:25:00 -07:00
ItsLeeOwen ec1cece270 fix(orderBy): remove redundant if statement
Removed unnecessary additional conditional statement.
2013-08-14 17:01:58 -07:00
Vojta Jina 4656e386fb chore: fix Travis build
Specify hostname/port for connect server to avoid
https://github.com/joyent/libuv/issues/826

Conflicts:
	Gruntfile.js
2013-08-14 16:12:37 -07:00
Vojta Jina f29f2f99b1 chore: disable npm install on Travis
Grunt is configured to run `npm install` before every task. That is convenient when switching a branch for example.

On Travis, this makes no sense and is causing tons of NPM warnings (eg. packages not defining repository field etc).
2013-08-14 16:12:37 -07:00
Vojta Jina cc27f08588 chore: update Node.js on Travis 2013-08-14 16:12:37 -07:00
Vojta Jina 99fe398b59 chore: update Karma to v0.10 2013-08-14 16:12:36 -07:00
Vojta Jina cb89e02432 chore(sauce): use tunnel-identifier and ready-file only on Travis
When running locally, there's not TRAVIS_JOB_NUMBER env variable defined and it screws
the Sauce Connect (it uses a tunnel with empty name), this makes it work locally without defining
TRAVIS_JOB_NUMBER env variable.

Also, if you run the sauce_connect_setup.sh locally, without having SAUCE_CONNECT_READY_FILE, it
does not pass the `--ready-file` argument to avoid Sauce Connect blowing up.
2013-08-14 16:12:36 -07:00
Andy Gurden ac69392cd7 fix($timeout): clean deferreds immediately after callback exec/cancel
Make sure $timeout callbacks are forgotten about immediately after
execution or cancellation.

Previously when passing invokeApply=false, the cleanup used $q and so
would be pending until the next $digest was triggered. This does not
make a large functional difference, but can be very visible when
looking at memory consumption of an app or debugging around the
$$asyncQueue - these callbacks can have a big retaining tree.
2013-08-14 16:04:48 -07:00
Vojta Jina a5fb372e1e fix(mocks.$timeout): forward delay argument
The $timeout decorator was not forwarding the delay argument to `browser.defer.flush(delay)`.
2013-08-14 16:04:48 -07:00
ebeal da720712f3 fix(tutorial): fix broken link caused by bad line break 2013-08-14 15:46:48 -07:00
Mikk Kirstein 0cb3dc8782 docs($http): added return to interceptors success callback 2013-08-14 14:19:10 -07:00
Igor Minar dfd95f0115 revert: docs($interpolate): add example for the provider
This reverts commit 1a01e80b9c.

This example is bogus, breaks docs.angularjs.org and karma e2e tests
2013-08-14 14:08:18 -07:00
David Bennett 7636670a77 docs(input): add missing ngChange directive for email type
All other input types already have it.
2013-08-13 10:17:44 -07:00
Siddique Hameed fe6247a7f8 docs(guide/unit-testing): add expression example
* Improved developer guide, directive unit testing documentation code with scope expression
* Removed documentation block with nothing on it
2013-08-12 16:23:39 -07:00
Vojta Jina 2b90ef1694 test(matchers): update toThrow matcher 2013-08-12 16:23:39 -07:00
Chirayu Krishnappa 099138fb9a fix($parse): move global getter out of parse.js 2013-08-12 16:23:39 -07:00
Igor Minar cbe31d8dfd fix($location): default to / for the url base if no base[href]
With the recent refactoring of $location service we changed this behavior
resulting in a regression.

Previously we thought that html5 mode always required base[href]
to be set in order for urls to resolve properly. It turns out that
base[href] is problematic because it makes anchor urls (#foo) to
always resolve to the base url, which is almost always incorrect
and results in all anchors links and other anchor urls (e.g. svg
references) to be broken.

For this reason, we should now start recommending that people just
deploy to root context (/) and not set the base[href] when using
the html5 mode (push/pop history state).

If it's impossible to deploy to the root context then either all
urls in the app must be absolute or base[href] must be set with the
caveat that anchor urls in such app won't work.

Closes #2762
2013-08-12 16:23:38 -07:00
Vineet Kumar 06b0930b6a fix(ngCloak): hide element even when CSS 'display' is set
Previously an element like
<div class="foo ng-cloak">...</div>
would still be annoyingly visible if it matched a CSS rule like
.foo { display: inline-block; }, overriding ng-cloak's display: none.
2013-08-12 16:23:38 -07:00
Sebastian Müller 7b7be341b6 refactor(core): use native String.prototype.trim if available 2013-08-12 16:23:38 -07:00
Lucas Galfasó 751c77f87b fix(i18n): Do not transform arrays into objects
Do not trasnform arrays into objects when generating the locale objects
Add unit test for this check
2013-08-12 16:23:38 -07:00
Ben Holley 634ac03c5e style(sanitize): fix typo in variable names 2013-08-12 16:23:38 -07:00
Vojta Jina 8cab53c64d chore(package.json): fix name to work with latest NPM 2013-08-12 16:23:38 -07:00
Igor Minar edef295b11 fix(grunt): cache version number
caching the version number speeds up the build and preserves resources.

this also fixed EMFILE error that now occurs on some macs.
2013-08-12 16:23:38 -07:00
Jeff Cross 64e447354e fix(dump): Prevented window.dump from being overridden by karma-jasmine.
In commit 6820322db562382fac903be35831275948825317 of Karma-Jasmine, the
dependency on angular.dump was removed. This caused two undesirable side
effects in the angular.js project. 1) Tests for presence of mock dump were failing,
and 2) the default window.dump was not outputting valuable angular-aware info. This
simple fix adds window.dump in testabilityPatch, to preprocess dumped input prior
to passing it to the global dump method.
2013-08-12 16:23:38 -07:00
Brenton da1f7c762d fix(equals): {} and [] should not be considered equivalent
angular.equals was returning inconsistent values for the comparison between
{} and []:

    angular.equals({}, []) // true
    angular.equals([], {}]) // false

Since these object are not of the same type, they should not be considered
equivalent.
2013-08-12 16:23:38 -07:00
Roland 89366bdbf9 docs(guide): remove superfluous }); 2013-08-12 16:23:37 -07:00
Igor Minar 78efa0e36c fix($compile): don't check attr.specified on non-ie7
the specified attribute is depricated and creates warnings in Firefox

Closes #3231
Closes #2160
2013-08-12 16:23:37 -07:00
Matias Niemelä 3a8b3db174 chore(.gitignore): ignore npm-debug.log file 2013-08-12 16:23:37 -07:00
Emmanuel 1a01e80b9c docs($interpolate): add example for the provider 2013-08-12 16:23:37 -07:00
Pete Bacon Darwin d59027c40e fix($q): call reject() even if $exceptionHandler rethrows
Normally $exceptionHandler doesn't throw an exception.  It is normally
used just for logging and so on.  But if an application developer
implemented a version that did throw an exception then $q would never
have called reject() when converting an exception thrown inside a `then`
handler into a rejected promise.
2013-08-12 16:23:37 -07:00
jankuca c197c2aa27 chore(bower): add a .bowerrc file 2013-08-12 16:23:37 -07:00
Eric Hagman 01cd34957e fix(jqLite): return array from multi select in val() 2013-08-12 12:00:47 -07:00
OpherV 864517e5a2 docs($compile): update directive type signature
To avoid "Argument type Array is not assignable to parameter type function" validation error  When using the minifcation-safe array style

(eg .directive('myDirective', ['$http','$timeout','$compile', function($http,$timeout $compile).... )

Closes #3392
2013-08-09 10:34:26 -07:00
Niall Smart 1dd5d2ec1f docs(ngModel): validators should return undefined for invalid values.
Closes #3525
2013-08-09 10:24:48 -07:00
Santi Albo 6da835f4bc docs(httpBackend): update documentation for expect methods
`expect` methods can receive an Object as the data parameter, which was
undocumented.
2013-08-09 10:10:45 -07:00
Andy Hitchman 5cca077e4a fix(angular.copy): change angular.copy to correcly clone RegExp
angular.copy previously copied RegExp as an empty object. Change detects
RegExp instance and clones into new RegExp. This change is based on a previous
fix to allow Date to be copied.

Closes #3473
Closes #3474
2013-08-09 00:17:34 -07:00
Igor Minar e290aa8c13 docs(ngModel): clarify docs for NgModelController#
Closes #3498
2013-08-08 23:08:08 -07:00
jankuca 9c51d50318 fix($compile): always instantiate controllers before pre-link fns run
Controllers should be always instantiated after compile fn runs, but before
pre-link fn runs. This way, controllers are available to pre-link fns that
request them.

Previously this was broken for async directives (directives with templateUrl).

Closes #3493
Closes #3482
Closes #3514
2013-08-08 22:58:51 -07:00
Matias Niemelä 1c3a46adda chore(ngdoc): wrap all pages inside of a container tag for easy styling 2013-08-07 22:11:45 +01:00
Matthew Windwer 4407e81c61 feat(ngForm): Supports expression in form names
<form name="ctrl.form"> form controller will accessible
as $scope.ctrl.form instead of $scope['ctrl.form']

BREAKING CHANGE:
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:

  function($scope) {
    $scope['ctrl.form'] // form controller instance
  }

  After:

  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.
2013-08-07 13:59:41 -07:00
neilmcgibbon ad76e77fce fix(input): fix the email regex to accept TLDs up to 6 characters long
The input field email regex does't not match long domain extensions. This commit extends the email regexp to take a 6 character TLD.

Example 6-character TLDs include .museum and .travel - (e.g. allabout.travel).
2013-08-07 14:18:22 -04:00
Pawel Kozlowski ac5b9055f6 fix(jqLite): forgive unregistration of a non-registered handler 2013-08-07 19:09:04 +02:00
Michael Stewart c18074a310 docs(compile): fix minor spelling mistake
Closes: #3468
2013-08-06 16:31:11 +01:00
Mark Campbell ed703d8e2c docs(guide/controller): fix wording in list of 'Do not use'
Wording has been changed in two of the examples to read naturally.
For example:

From: 'Do not use controllers for to run stateless or stateful code
shared across controllers'

To: 'Do not use controllers for sharing stateless or stateful code
across controllers'

Closes #3454
2013-08-03 22:06:03 +01:00
Igor Minar 9c53d0769e revert: fix(location): fix parameter handling on search()
This reverts commit 90532f5e3c.

The commit contains references to minErr that are not available
in the stable branch.
2013-08-01 09:34:56 -07:00
Misko Hevery 90532f5e3c fix(location): fix parameter handling on search() 2013-07-31 17:10:10 -07:00
Brenton 2bc04d23fb docs(header): replace logo.png with logo.svg
The current logo looks awful on high-density displays.  SVG is a
better choice because it can scale to any resolution without
increasing file size.

Amending #2775 to add support for IE 8 by falling back to existing PNG
with img.onerror

Using relative URLs as directed by @btford and @petebacondarwin.

(commit by Brenton Simpson - @appsforartists)

Closes #2874

Conflicts:

	docs/src/templates/css/docs.css
	docs/src/templates/index.html
2013-07-31 12:06:04 -07:00
Roland 7f6da764e1 docs(tutorial): mention the controller along the scope 2013-07-27 17:14:30 +01:00
Roland 6926ef8f67 docs(tutorial): add formatting
the string literal {{query}} was missing as it was not enclosed into ``
2013-07-27 16:07:51 +01:00
Roland bba2b7cfce docs(tutorial): add that the test also creates a controller 2013-07-27 15:53:35 +01:00
Pawel Kozlowski dc1e55ce1a fix(form): pick the right attribute name for ngForm
Closes #2997
2013-07-24 14:41:54 -07:00
Paul Meskers 408e868237 fix(numberFilter): always convert scientific notation to decimal
Previously, the number filter would format small and large numbers
as scientific notation. It now uses toFixed() to ensure that all
requested digits are shown.
2013-07-24 12:06:19 -07:00
Pavel Vasek 97abb12473 fix($location): prevent infinite digest error due to IE bug
If an app uses HTML5 mode and we open an html5 url on IE8 or 9 which
don't support location href, we use location.replace to reload the page
with the hashbang equivalent of the url but this fails with infinite
digest. This is because location.replace doesn't update location.href
synchronously on IE8 and 9.

Closes #2802, #3305, #1417
2013-07-24 10:38:29 -07:00
Braden Shepherdson d26bffbc3f docs(bootstrap): Note that ngScenario requires ngApp
ngScenario expects an ngApp directive to be used, and doesn't work for
manually bootstrapped apps. The failure mode is to hang on navigation.

Trying to make this wont-fix bug less obscure by documenting it.
Eventually Protractor will replace ngScenario and fix this.
2013-07-23 20:35:03 +01:00
Spencer 2f3bd9dae7 docs(cacheFactory): correct typos 2013-07-23 20:16:58 +01:00
Richard John 256e5dff55 docs(index): add seed app link to menu item 2013-07-23 20:11:03 +01:00
Igor Minar acb6b75fe9 chore(dump): remove dead code
This code is not being used any more and the test is now failing
due to Karma changes. Karma used to expose window.dump but that
changed recently and that's why our build is now failing.

I'm removing the code and test, but we still need to figure out
how to route window.dump through angular.mock.dump, but that will
have to be a separate commit.
2013-07-22 14:01:38 -07:00
Igor Minar 683fd713c4 fix($compile): always instantiate controllers in parent->child order
Previously it was possible to get into a situation where child controller
was being instantiated before parent which resulted in an error.

Closes #2738
2013-07-22 11:32:50 -07:00
Jérémy 3591ae0103 docs(input): fix example
The input [number] error spans did not show on the example, as they were
relying on an non-existing property (myForm.list.$error) vs the working
property (myForm.input.$error)
2013-07-21 21:24:53 +02:00
Vineet Kumar 5fedfd79a5 docs(ngController): remove obsolete mention of scope as this in controller
Controllers are now (since angular 1.0) instantiated as regular constructorsand the scope
is injectable as $scope rather than being referenced as `this` in controller methods.
2013-07-21 20:30:40 +02:00
David Sanders bdde40e755 docs($window): improve style and clarify wording 2013-07-21 20:24:49 +02:00
Pete Bacon Darwin 88c4963328 docs(jqLite): document "$destroy" event 2013-07-18 19:53:13 +01:00
Matias Niemelä 67a81eff42 chore(ngdocs): fix improve button overlap 2013-07-18 18:56:08 +01:00
Spencer add43e91dc docs($templateCache): add examples of usage 2013-07-17 16:41:09 +01:00
Bruno Coelho b3c7a6d566 docs(dateFilter): fix typos
Fix closing parenthesis, quotes around string literal and remove
trailing whitespace.

Closes #3250
2013-07-17 11:28:01 +01:00
James deBoer 424bd49ede test(utils): Adds a missing test for snake_case 2013-07-16 11:18:11 -07:00
Matias Niemelä 6a58404507 chore(gitignore): add libpeerconnection.log
Google chrome (when tested using karma) spits out a log file called libpeerconnection.log
2013-07-15 09:28:54 -07:00
Matias Niemelä d4ce8362b1 chore(ngdocs): remove autofocus for the filtering search 2013-07-15 14:57:47 +01:00
sdesmond caa12dbc57 docs(di): promote registering controllers on modules 2013-07-14 16:23:04 +02:00
David 1122b3c14d style(ngMock): add missing whitespace 2013-07-14 16:06:38 +02:00
Ben Ripkens a357649da5 fix(angular.equals): add support for regular expressions
Regular expression objects didn't used to be considered to be equal when using
'angular.equals'. Dirty checking therefore failed to recognize a
property modification.

Closes #2685

Conflicts:

	test/AngularSpec.js
2013-07-13 22:35:17 -07:00
Greg Thornton 332a3c7984 feat(Angular.js): skip JSON.stringify for undefined
Return early in `angular.toJson` if the object to be stringified is `undefined`.
IE8 stringifies `undefined` to `'undefined'` whereas other browsers return
`undefined`. This normalizes behavior and passes currently broken unit tests
in IE8.
2013-07-12 20:49:50 +02:00
Pete Bacon Darwin fcd761b9d7 fix(sanitize): match URI schemes case-insensitively
According to RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
schemes such as http or mailto are case-insensitive. So links such as
http://server/ and HTTP://server/ are valid and equivalent.

Closes #3210
2013-07-12 09:32:23 +01:00
Wesley Cho b0d5f062e3 fix(ngSubmit): expose $event to ngSubmit callback 2013-07-11 17:27:36 -07:00
Brian Ford 2c0753225a revert: feat(ngDocs): add links to source for API
This reverts commit 61fb5863df.
2013-07-11 15:32:33 -07:00
Mikk Kirstein 3b898664ee fix(ngValue): made ngValue to write value attribute to element 2013-07-11 14:59:38 -07:00
Julien Bouquillon 61fb5863df feat(ngDocs): add links to source for API
- add tests
 - the link points to the gruntUtil.getVersion().number tree on github
2013-07-11 14:40:06 -07:00
Paulo Scardine a4ec297925 fix(scope): watches can be safely unregistered inside watch handlers
Closes #2915
2013-07-11 22:07:15 +01:00
Brian Ford 93d7e60d43 chore(build): add check for merge conflicts, ddescribe, and iit 2013-07-11 11:59:38 -07:00
Igor Minar 338264b5f6 test(ngPattern): fix disabled test 2013-07-11 11:58:47 -07:00
Igor Minar 19b51caa2c test(ngList): remove disabled test
this test fails and we don't have intentions on making it pass since
we never made a commitment to implement this feature.
2013-07-11 11:12:17 -07:00
Igor Minar 8c08b4373c docs(ngList): fix example and add e2e test 2013-07-11 09:23:18 -07:00
Igor Minar 0b38882a91 style(input): remove ws 2013-07-11 09:23:18 -07:00
sdesmond 3364d69a3b docs(guide): clarify example 2013-07-10 22:58:43 +02:00
sdesmond e6c9bfa4a9 docs(guide): example filter does not conditionally assign a color 2013-07-10 22:55:03 +02:00
Robert Fauver 7a3e182e9c docs(guide/di): fix typo 2013-07-10 22:30:53 +02:00
Tay Ray Chuan 2471f6b01c docs(contribute): improve git instructions 2013-07-10 22:23:12 +02:00
Lefteris Paraskevas 1fefafd09f docs(overview): fix typo
Removed repeated "the" in the sentence: The input invalidates itself by turning red when you enter invalid data or leave "the" the input fields blank (Line 137).
2013-07-10 22:12:27 +02:00
Mark Striemer 8a63dc3151 docs(ngMock): correct verifyNoOutstandingExpectation example 2013-07-10 20:32:53 +02:00
Marco Vito Moscaritolo 403008816c docs(angular.identity): fix missing 'angular' in identity function 2013-07-09 14:32:59 +01:00
Pete Bacon Darwin 62d552ffe2 docs(ngModelController): provide a more intuitive example
The example directive, using contenteditable was not showing required
even if you cleared the content from it.

Closes #3156
2013-07-08 14:53:15 +01:00
Pete Bacon Darwin bcaa4217bc docs(numberFilter): fix explanation of default fraction size
The default fraction size for the number filter is actually computed
from the `NUMBER_FORMATS.PATTERNS.maxFrac` value in the current locale.

Closes #3157
2013-07-08 11:23:37 +01:00
tgkokk 0823f6dfab docs(guide/e2e-testing): fix typos 2013-07-07 20:32:06 +01:00
basarat 87bb554aec docs(input): ng-model doesn't work well with isolated scope directive
Closes #3123
2013-07-04 00:35:52 +01:00
Andrew O'Brien 36447cb2b5 docs(guide/directive): make directive controller minification-safe
It is best to emphasize that the "controller" property needs to be min safe

Closes #3125
2013-07-04 00:29:10 +01:00
Anders Hessellund Jensen 3b2c6f09cb fix($compile): empty normalized href should pass sanitation check
Sometimes IE returns an empty string for its normalized href on a tags.
This should pass the sanitation check in $compile.

Closes #2219, #2593
2013-07-04 00:13:04 +01:00
Joao Sa 63414b9653 fix(jqLite): prepend array in correct order
Match jQuery behavior when prepending array into empty element
2013-07-03 20:25:28 +01:00
exex zian 5f24bb0267 docs(tutorial/step9): formatted Unicode character line
Add tick and cross mark corresponding to their respective unicodes.
2013-07-02 22:50:52 -07:00
Vojta Jina 52519d45b9 chore(travis): speed up the build
- parallelize the tasks
- cache requests (e2e tests)

This reduces the time from ~18min to ~12min.

It makes the output little messy. We could buffer output of each task and display it once it's fully finished, nicely. I think giving instant feedback is better.
2013-07-02 15:12:03 -07:00
Niall Smart 78728df099 docs(guide/location): fix example code - hashPrefix is a method 2013-07-02 10:01:51 +01:00
Vojta Jina 732db27cd6 chore: add karma-script-launcher plugin
This plugin is shipped as a default one with Karma. It's specified as a peer dependency.

I assume, there's an old version of NPM on the CI server, which does not support peerDependencies and therefore it didn't get installed.

This will make the dependency explicit.
2013-07-01 10:15:56 -07:00
Itamar Rogel 3cad63fbd8 docs($cacheFactory): show that you can access existing caches 2013-07-01 12:03:10 +01:00
Spencer Applegate d2be5939dc docs(Angular.js): explain that toJson strips $... properties
In Angular.toJson, any properties with a leading '$' character will be
stripped from the resulting string since angular uses this notation
internally for services.  There have been complaints of not knowing
about this functionality until it breaks within their code.
2013-07-01 11:36:17 +01:00
Vojta Jina 9a77d03047 chore: set up Sauce Labs with Travis
This should not affect the Jenkins build at all.

Now, the Travis build uses Chrome on Sauce Labs, which in theory gives us opportunity to use any
browser/platform that Sauce Labs offers.
2013-06-28 16:36:30 -07:00
Vojta Jina 8efcec67cc chore: clean up angularFiles.js 2013-06-28 16:35:05 -07:00
Vojta Jina 4fbd4bbd8d chore: update karma to 0.9.4
And also add shared config to make karma configs a bit simpler.
2013-06-28 16:30:48 -07:00
Vojta Jina 2fae296cbc chore: remove jstd leftovers 2013-06-28 16:29:09 -07:00
Igor Minar cef8466419 docs(misc/faq): remove obsolte t-shirt instructions 2013-06-28 11:27:55 -07:00
Andrew Peterson 083159ebbe docs(ngBind): clarify some of the writing 2013-06-27 21:20:56 +01:00
Andrew Peterson 32e440cffc docs(ngPluralize): improve wording 2013-06-27 21:15:33 +01:00
Adam 89c8c93b9a docs(guide/e2e-testing): clarify description of input(name) selector
The description of the input selector made it seem that you were selecting
an input element based upon it's name attribute. In reality, you are
selecting an element by the string in the ng-model attribute.
2013-06-27 20:46:09 +01:00
Pete Bacon Darwin 296074f548 docs(ngMock/$httpBackend): fix testing example
Closes #3075
2013-06-27 20:38:15 +01:00
Nelson Blaha 2ccfaffa74 docs(tutorial): add experiment showing reverse sort 2013-06-27 19:36:46 +01:00
Jeffrey Palmer 192672a162 docs(guide/controller): fix an error in the scope inheritance example
The chained scope creation example at the bottom of this document was using the childCtrl to create the babyScope, instead of the childScope.
2013-06-25 23:54:33 +01:00
Domenic Denicola 7f4e658d3d docs(guide/expression): remove reference to NullPointerException 2013-06-25 21:13:56 +01:00
Pete Bacon Darwin ff57695855 refactor(angular.bootstrap): rename internal function 2013-06-20 15:23:04 +01:00
NimaVaziri ae8deb1246 docs(cookbook/helloworld): display "World" if no name is entered 2013-06-20 14:40:07 +01:00
Pete Bacon Darwin b9dcb35e9b fix(Angular.js): don't crash on invalid query parameters 2013-06-20 14:32:05 +01:00
Caio Cunha 25d9f5a804 fix($http): ensure case-insens. header overriding
If user send content-type header, both content-type and default
Content-Type headers were sent. Now default header overriding is
case-insensitive.
2013-06-19 22:43:19 +01:00
sarkasm 1b234cb7af docs(directive): fix typo 2013-06-19 11:51:18 +01:00
gdi2290 d219442945 docs(tutorial): add missing 'node' command and <code> tags 2013-06-18 22:05:43 +01:00
John Bohn 2b33be47cb docs(tutorial/step_07): add commas make tutorial read more clearly 2013-06-18 21:57:21 +01:00
Ore Landau 499baced12 docs(loader): fix typo and minor semantic error 2013-06-18 21:23:00 +01:00
Ore Landau 7aa9fecab8 docs(guide/di): fix headings hierarchy 2013-06-13 22:51:11 +01:00
Misha Moroshko 9b6c82d804 docs(select): fix typos in ngOptions 2013-06-13 22:48:03 +01:00
Ore Landau c3117b7544 docs($q): fix a few issues 2013-06-13 22:42:26 +01:00
Jad Naous 67744384e8 docs(guide/e2e-testing): fix verb tense 2013-06-13 22:37:33 +01:00
Ore Landau 17c401d09a docs(tutorial/step_05): apply more useful link to services 2013-06-13 21:15:32 +01:00
Dean Sofer 488aea15f4 docs(FormController): add methods for FormController 2013-06-12 21:49:52 +01:00
Dean Peterson 43df853ee3 docs(ngModelController): improve $parsers/$formatters with example 2013-06-12 21:23:16 +01:00
Ore Landau 28d5dcb578 docs(ngClass): fix minor typo. 2013-06-12 20:47:59 +01:00
Pete Bacon Darwin 7eb15c46a2 docs(guide/bootstrap): clarify manual bootstrapping 2013-06-12 20:42:12 +01:00
Pete Bacon Darwin 1fac36e2cb docs(ngRoute): clarify when gets updated 2013-06-11 22:35:47 +01:00
Pete Bacon Darwin 4b6c87b6e7 docs(ngSubmit): clarify that there must be no action attribute 2013-06-11 21:30:10 +01:00
Igor Minar ce6c2b2072 chore(docs): fix memory leak in example embed code
we need to sever the link between the main root scope and the example
root scope - this is only needed because we are embedding one app
in the other.
2013-06-10 13:10:38 -07:00
Igor Minar 3e94a2c54d docs(faq): update customink order info 2013-06-10 11:39:26 -07:00
Jared Forsyth b1e488f5d7 docs(guide/unit-testing): fix typo 2013-06-04 22:28:58 +01:00
Jared Forsyth 03d867160f docs(guide/injecting_controllers): add a hint in example
Add a hint to tell the user that they need to click 3 times before an alert is shown.
2013-06-04 22:25:38 +01:00
Marcin Wosinek 9870e65c5f docs(ngTransclude): fix outdated scope definition in example 2013-06-04 22:14:15 +01:00
Pete Bacon Darwin aa839b9ff0 docs(guide/unit-testing): fix controller test example 2013-06-04 22:10:27 +01:00
Robbie Ferrero fdb66aa237 docs(Angular.js): clarify ngApp usage 2013-06-04 22:01:26 +01:00
Robb Shecter e0ca5fdd51 docs(angular-mocks): fix typo in example
fromJSON() should be fromJson()
2013-06-04 21:54:05 +01:00
Alan Klement 681c1c53e4 docs(sanitize): add @description section 2013-06-04 21:50:38 +01:00
Siddique Hameed 631c4863d8 docs(index): make menu links relative
Before the Develop drop down menu items were hard coded with an absolute url,
which meant that they did not work correctly on local or ci server builds.
2013-06-04 21:08:56 +01:00
Luc Morin 944bda12c7 docs(ngClass): clarify the use of object map 2013-06-04 21:01:43 +01:00
Ehsan Ghandhari bc36c4dea4 docs(guide/concepts): add comment as a type of directive 2013-06-04 20:54:03 +01:00
Robb Shecter 722766958b docs(guide/understanding_model): improve example consistency 2013-06-04 20:50:35 +01:00
Manuel Kiessling 73fd3ca2eb docs(guide/compiler): fix some minor language errors 2013-06-04 20:38:27 +01:00
Alex Young efe8ad51ed docs(guide/di): fix some small grammatical issues 2013-06-04 20:31:06 +01:00
Jens Rantil d5b62465f0 docs(validate-commit-msg): fix incorrect comment
If you `cd` into the repo, `validate-commit-msg.js` will be in the root
of it.
2013-06-04 20:24:27 +01:00
Luc Morin bc76e7255b docs(input): provide explanation of how ngModel will affect the local scope 2013-06-04 20:16:37 +01:00
Eduardo Garcia 8dd23ad2f2 docs(guide): format snippets of code in plain text 2013-06-04 20:07:09 +01:00
adamshaylor bce75d7c68 docs(overview.ngdoc): clarify wording 2013-06-04 20:02:18 +01:00
Michał Gołębiowski 815053e403 fix(jqLite): correctly monkey-patch core jQuery methods
When real jQuery is present, Angular monkey patch it to fire `$destroy` event.

This commit fixes two issues in the jQuery patch:
- passing a selector to the $.fn.remove method (only fire `$destroy` on the matched elements)
- using `$.fn.html` without parameters as a getter (do not fire `$destroy`)
2013-05-23 11:45:57 -07:00
Igor Minar 6173abe20b docs(changelog): fix changelog formatting 2013-05-22 21:48:37 -07:00
Igor Minar 6fcf0afa35 docs(changelog): add note about animation breaking change 2013-05-22 21:48:37 -07:00
Eddie Monge 05521e276f style(docs/template): add in missing semicolons 2013-05-22 22:56:51 +01:00
Jens Rantil 38ffbbd7dd docs(guide/directive): clarify directive priority
Fixes #2644.
2013-05-22 21:10:03 +01:00
Igor Minar 47e1878e4c chore(release): start 1.1.8 bubble-burst iteration 2013-05-22 01:14:09 -07:00
Igor Minar dc6f149973 chore(release): cut the 1.0.7 monochromatic-rainbow release 2013-05-22 01:05:53 -07:00
Igor Minar 420f6bfccb docs(CHANGELOG.md): release notes for 1.1.5 and 1.0.7 releases 2013-05-22 01:03:55 -07:00
Anatoly Shikolay ae33e11694 style(*): fix up semicolon and var usage
Conflicts:

	src/ng/animation.js
	src/ng/animator.js
	src/ng/http.js
2013-05-21 14:41:22 -07:00
Lucas Galfasó 4d8b0282b4 test(parse): Test for the parsing not invoking twice to get self
New tests to not call twice a function to get self
2013-05-21 14:41:22 -07:00
Igor Minar 00845fca88 docs(changelog): fix the 1.0.6 header 2013-05-21 14:41:22 -07:00
Joakim Blomskøld 84fe86c7fd docs(Angular.js): add missing @returns to extend() 2013-05-21 21:39:53 +01:00
Matias Niemelä 5e1ed9d5d2 docs(tutorial): fix the float issue with the improve docs button 2013-05-21 14:09:42 +01:00
Ben Ripkens 2ba668732a docs(ngScenario): provide examples for element(...).query(fn)
element(selector, label).query(fn) is a very useful function, yet barely
explained. The developer guide should show how this function can be used
to conditionally execute behavior and assertions.
2013-05-21 13:36:35 +01:00
Jens Rantil 2cb73b71d1 doc($compile): clarify compile function return value
If a compile function (within a directive) returns a function, it is a
post-link function.

Closes: #2713
2013-05-21 13:18:59 +01:00
Jens Rantil 16a2ce2b13 docs(guide/type): remove empty "Type" page in guide
Closes #1316
2013-05-21 13:13:28 +01:00
Igor Minar 18e87a7544 chore(version.js): remove unused/obsolete script 2013-05-21 03:43:10 -07:00
Igor Minar f81431dd72 chore(package.json): kill version.yaml in favor of package.json
all versioning info is now in package.json and that's where the build scripts read it from
2013-05-20 16:48:21 -07:00
Dan Kohn 04bdb9f813 chore(package.json): use devDependencies instead of dependencies 2013-05-20 16:46:11 -07:00
Daniel Tse 1cfe281a76 docs(filters): fix minor typographical error
Fix a typographical error "it's" -> "its" in the dateFilter
documentation
2013-05-20 15:37:14 +01:00
David Holmes 6165bd7d1e doc(guide/compiler): fix grammatical error
"The compilation process happens into two phases." should be "The compilation process happens in two phases."
2013-05-20 10:24:29 +01:00
Misha Moroshko 0135564ad9 doc(filter): remove invalid character 2013-05-20 10:21:28 +01:00
Pete Bacon Darwin 6847cbeff8 docs(guide::testing): fix link to angular-seed 2013-05-18 22:17:28 +01:00
Chris M 84daf33c03 docs(ngMock::$log): improve the $log.*.logs descriptions
Because ngDoc generation only takes the last segment of a property name,
each $log.[error|warn|log...].logs property has the same name and is
confusing in the docs.
This commit helps this by adding a link to the $log.* method and also an
appropriate usage example.
2013-05-18 22:14:20 +01:00
Joakim Blomskøld 86cbdb893a doc(ngModel): $setViewValue calls all parsers, not formatters 2013-05-18 21:18:15 +01:00
Ben Ripkens 11ee680d38 docs(guide): add API documentation for ngScenario matchers
Matchers are briefly mentioned in the e2e test guide, but there is no
documentation for the available matchers.
2013-05-18 21:01:57 +01:00
Andrew Vida 4c5b382b69 docs(tutorial): update test config file name 2013-05-18 20:29:34 +01:00
Jeremy Wilken 39f4a776d6 doc(guide:$location): fix example for two way databinding.
When you are watching the $location.path(), it has to be wrapped in a
function since it is not attached to the scope and if you pass a string
to $scope.$watch it is evaluated against the $scope.
2013-05-17 19:17:28 +01:00
Matt Haggard a250116694 doc(guide): add links to angular-seed examples
The examples in the angular-seed project are better than nothing,
which is what we currently have here!
2013-05-16 22:03:23 +01:00
Dean Sofer 9a73d71f47 docs(ngCsp): add more informative details
Transferred from https://github.com/angular/angular.js/wiki/Using-AngularJS-in-a-Chrome-Extension-environment
2013-05-16 21:28:05 +01:00
jamesBrennan 73aaca05f8 docs(guide:understanding_controllers): remove outdated info
Remove the outdated info in this document related to this API change
https://github.com/angular/angular.js/blob/master/src/ng/rootScope.js#L166
2013-05-15 21:33:30 +01:00
Siddique Hameed a993112098 docs($timeout): minor cleanup
Added a comma separator in the statement
Removed the word the from the statement
Used whose instead of who's in the following statement
Italicized false in the statement
Used a comma separator in the statement
2013-05-14 21:22:04 +01:00
Chirayu Krishnappa 9145d5ec3e fix($browser): should use first value for a cookie.
With this change, $browser.cookies()["foo"] will behave like
docCookies.getItem("foo") where docCookies is defined at
https://developer.mozilla.org/en-US/docs/DOM/document.cookie

This fixes the issue where, if there's a value for the XSRF-TOKEN cookie
value with the path /, then that value is used for all applications in
the domain even if they set path specific values for XSRF-TOKEN.

Closes #2635
2013-05-11 09:28:14 -07:00
willtj efc863844c docs($scope): clarify documentation for $broadcast 2013-05-10 21:24:38 +01:00
veselinn cc260e7864 docs(guide): fix a typo 2013-05-10 20:52:44 +01:00
Lucas Galfasó 42ce8f7f55 fix(ngPluralize): handle the empty string as a valid override
Fix the check for overrides so it is able to handle the empty string

Closes #2575
2013-05-10 20:04:59 +01:00
Alfred Nutile 661390aef3 docs(guide): fix typo on model name 2013-05-10 14:58:15 +01:00
Pete Bacon Darwin ed4a70e765 docs(Angular.js): move forEach docs to correct position 2013-05-09 22:15:22 +01:00
Pete Bacon Darwin 1866968310 docs(tutorial): add comment about injection annotation
Closes: #1163
2013-05-09 13:58:02 +01:00
Igor Minar 5fbf98ec23 chore(docs): use done() in gen-docs.js 2013-05-09 05:23:39 -07:00
Igor Minar 5d2bb2c1b9 test(sortedHtml): ignore bogus rowspan=1 and colspan=1 in IE 2013-05-09 05:23:39 -07:00
Igor Minar 9039ddbb56 test(sortedHtml): fix comment support in sortedHtml helper 2013-05-09 05:23:39 -07:00
Igor Minar 8f8510fc22 style($compile): clarify argument name 2013-05-09 05:23:39 -07:00
Pete Bacon Darwin 1e99ea6a51 docs($window): fix example 2013-05-09 13:02:30 +01:00
R. Merkert 016e1e675e fix(angular): do not copy $$hashKey in copy/extend functions.
Copying the $$hashKey as part of copy/extend operations makes little
sense since hashkey is used primarily as an object id, especially in
the context of the ngRepeat directive. This change maintains the
existing $$hashKey of an object that is being copied into (likewise for
extend).
It is not uncommon to take an item in a collection, copy it,
and then append it to the collection. By copying the $$hashKey, this
leads to duplicate object errors with the current ngRepeat.

Closes #1875
2013-05-08 13:04:08 +01:00
Illniyar 1240641f76 feat($cookieStore): $cookieStore.get now parses blank string as blank string
closes #1918
2013-05-08 10:07:24 +01:00
Chad Smith f1a34f0908 fix(select): ensure empty option is not lost in IE9
Fix a check inside render for select elements with ngOptions, which
compares the selected property of an element with it's desired state.
Ensure the placeholder, if available, is explicitly selected if the model
value can not be found in the option list.
Without these fixes it's up to the browser implementation to decide which
option to choose. In most browsers, this has the effect of displaying the
first item in the list. In IE9 however, this causes the select to display
nothing.

Closes #2150, #1826
2013-05-07 21:29:44 +01:00
Pete Bacon Darwin 01bda54e05 fix(dateFilter): correctly format ISODates on Android<=2.1
In older Android browsers, `undefined` does not act like `0` in some
arithmetic operations. This leads to dates being formatted with `NaN`
strings in the dateFilter because the implementation of the `dateGetter`
function allows offset to be an optional parameter.
The fix is to convert offset to 0 if it is undefined.

Closes #2277, #2275
2013-05-07 11:44:46 +01:00
Hamish Macpherson bc04afe183 doc(input): fix small typo in code example 2013-05-07 09:48:59 +01:00
quazzie ac086ae616 fix($location): back-button should fire $locationChangeStart
Before $locationChangeStart event is not broadcast when pressing the back-button on the browser.

Closes #2109
2013-05-01 14:51:05 +01:00
Siddique Hameed f75a2b093f docs(injector): fix typo
Closes: #2551
2013-05-01 13:15:17 +01:00
Chris Nicola 4dba7b0203 docs(guide:directive): add directive controller usage
Specifically adding a directive controller to the example definition
and how to use declare injectables to avoid minification errors.
2013-04-30 10:53:17 +01:00
Robin Böhm d3cd3c0a9b style($injector): add a comment to explain the distinction with isArray 2013-04-30 10:40:19 +01:00
Eugene Wolfson e351874a0a docs($provide): fix parentheses in example 2013-04-30 10:17:01 +01:00
Lucas Galfasó dcdf4fc78b fix(parse): fix context access and double function call
Fix a context duplication and invocation to a previous context when
doing an access modifier function on the result of a function
Currently, when doing `foo().bar()`, `foo` is called twice, the first
time to get the context and the second one for `bar` to get the
underlying object. Then the call to `bar` is called using the second
instance as self
This is equivalent to doing:
```
var instance1 = foo();
var instance2 = foo();
instance2.bar.apply(instance1);
```

Closes #2496
2013-04-29 23:02:51 +01:00
Matias Niemelä cf38d8c55b feat(ngdocs): support for HTML table generation from docs code 2013-04-29 17:47:53 -04:00
gockxml b0233a33a1 fix(jqLite): correct implementation of mouseenter/mouseleave event
Implement mouseenter/mouseleave event referring to
http://www.quirksmode.org/js/events_mouse.html#link8 and jQuery source
code(not dependent on jQuery).
The old implementation is wrong. When moving mouse from a parent element
into a child element, it would trigger mouseleave event, which should not.
And the old test about mouseenter/mouseleave is wrong too. It just
triggers mouseover and mouseout events, cannot describe the process of mouse
moving from one element to another element, which is important for
mouseenter/mouseleave.

Closes #2131, #1811
2013-04-29 18:28:29 +01:00
Oren Avissar c3235db9ee test(browser/compile): fix calls to Jasmine fail()
The fail() function in Jasmine expects an Error object parameter.
Also, there is no global alias for fail() so it must be accessed using
`this.fail(new Error())`.
2013-04-29 16:57:33 +01:00
Robin Böhm 738113bac8 refact(ngClass): improve performance through bitwise operations
Change modulo % 2 operations to bitwise & 1
Read about this in Nicholas C. Zakas book "High Performance JavaScript"(ISBN: 978-0-596-80279-0)
Use the Fast Parts --> Bitwise Operators --> Page 156++
Proven at http://jsperf.com/modulo-vs-bitwise/11
2013-04-29 10:19:32 +01:00
Jamie R. Rytlewski 6613ee40e6 docs($q): fix typo 2013-04-28 18:45:01 +01:00
Anton ce6035d953 docs(contribute): add Java as dependency
Current build process leverages closure jar for javascript minification.
If Java is not installed and included in the PATH the build will fail.
2013-04-28 18:37:45 +01:00
Paulo Ávila 2bc4793ee8 docs(filter): improve syntax for usage in templates 2013-04-24 21:57:48 +01:00
Jeff Pickelman 9c6e34bfc1 docs(di): fix typos and grammar 2013-04-24 20:52:59 +02:00
Timothy Ahong 4e65ff31a8 docs(guide:unit-testing): add an example unit test for directives 2013-04-23 13:23:16 +01:00
Pete Bacon Darwin 15461c7883 docs(compiler): don't drag selected content
In the example with draggable, the mouseDown handler needs to start with an event.preventDefault(). Otherwise the following bug occurs:
1) Select the text of the draggable span by clicking outside the span and dragging the mouse to the left or right through the span. Release the mouse button.
2) Now click on the span's inner text, and start to Drag it. The browser's default functionality that drags highlighted text so that it can be pasted into something else (say a document in a text editor) is invoked.
3) Release the mouse button. Now suddenly, you'll be dragging the span. But you won't be able to place it down on the page. It'll just follow the mouse around until the page is refreshed.

Closes: #2465
2013-04-22 13:38:49 +01:00
Keir Mierle de5352cfcf docs(compiler): fix variable scope in drag sample
Note that without this fix, if you add a second draggable element, the
two instances clobber each other since there is only one set of
startx/starty/x/y variables.
Here is an example: http://plnkr.co/edit/aGrLXcIo2SuaePuAdfmQ?p=preview.
On the surface it looks like it would be fine because you only have one
mouse but in practice the start position jumps when you start dragging.
Here it is fixed: http://plnkr.co/edit/VuvPasuumtCeiVRisYKQ?p=preview
2013-04-22 12:52:43 +01:00
Keir Mierle ae26ed994e docs(forms): fix formatting 2013-04-22 12:38:58 +01:00
Ron Yang 94745f6274 docs(forms): fix typo 2013-04-22 12:35:05 +01:00
Paulo Ávila dbfa0d88bb docs(guide): minor grammatical change 2013-04-21 20:06:29 +02:00
Pete Bacon Darwin cf3b5cb2fc chore(ngDoc): fix a typo with IE warning 2013-04-19 22:08:07 +01:00
Merrick Christensen 192a225854 docs(concepts): fix spelling error 2013-04-19 14:44:44 +01:00
Jared Beck 3508f76719 docs(overview): correct the input validation example
The documentation says that the input should be red if you enter
invalid values or leave it blank. Because the type="integer" is not
supported this does not happen in practice.  This fix changes the
input type to number and adds an ng-pattern to ensure that the number
is an integer.
2013-04-19 14:40:39 +01:00
leesei a7d081fac0 docs(input): fix typo on max attribute 2013-04-19 13:43:37 +01:00
Shyam Seshadri ee774f6e5b docs(select): fix attribute documentation
Select documentation was still referring to binding to name, when it should be ng-model instead. Fixed it.
2013-04-19 13:37:04 +01:00
Michal Reichert 80f34598f8 docs(ngBind): fix typo 2013-04-19 11:58:52 +01:00
Pete Bacon Darwin 7e168c8ad2 fix(i18n): escape all chars above \u007f in locale files
Modify the script that writes the locales so all characters above \u007f are escaped
Includes the updated locale files after running the closureI18nExtractor.

Closes #2417
2013-04-17 22:16:57 +01:00
Mark Dalgleish 3ebc2c2442 fix(ngModel): use paste/cut events in IE to support context menu
In IE the model is not updated when the input value is modified using the context
menu, e.g. pasting from the clipboard, or cutting all or part of the current value.
To capture these changes, we bind to the proprietary 'paste' and 'cut' events.

Closes #1462
2013-04-17 21:50:07 +01:00
es128 631d86f723 doc(ngClassEven): make consistent with ngClassOdd 2013-04-17 14:52:24 +01:00
@fbiville 3ac97f2b3d docs(directive guide) typo in compile/link section
The code snippet shows `{{action.description}}`, the explanation referred to it as `{{action.descriptions}}`.
2013-04-17 14:49:55 +01:00
@fbiville ed55346be7 docs(injector): fix typo in inlining example
The actual invoke call in the documentation was referring to the non-existent tempFn instead of tmpFn
2013-04-17 14:46:53 +01:00
Timothy Ahong e31ec1f7ed docs(guide.unit-testing): fix typo 2013-04-16 21:06:10 +01:00
Francesc Rosàs 70e4fd2865 docs($q): fix incorrect @returns tag for $q.when() 2013-04-16 13:38:11 +01:00
Pete Bacon Darwin 7898490779 fix(ngClass): should remove classes when object is the same but property has changed
If you wire up ngClass directly to an object on the scope, e.g. ng-class="myClasses",
where scope.myClasses = { 'classA': true, 'classB': false },
there was a bug that changing scope.myClasses.classA = false, was not being picked
up and classA was not being removed from the element's CSS classes.

This fix uses angular.equals for the comparison and ensures that oldVal is a copy of
(rather than a reference to) the newVal.
2013-04-16 13:22:37 +01:00
Pete Bacon Darwin 0893e83c92 fix(Grunt): also remove \r chars when joining files 2013-04-16 13:14:09 +01:00
Pete Bacon Darwin ef334d0070 docs(tutorial): testacular renamed to karma
Replaced instances of 'Testacular' with 'Karma' to reflect name change of test runner.
Replaced instances of 'http://vojtajina.github.com/testacular' with 'http://karma-runner.github.io/' to reflect dedicated page for Karma Test Runner.
Added location of config file needed to start the Karma server. This is still labeled 'testacular.conf.js' and needs file name to be updated in the phone example repo.
2013-04-15 12:30:33 +01:00
Pete Bacon Darwin 9f08d03978 docs(rootScope): fix typo 2013-04-15 11:46:21 +01:00
Laurent 3ca6c4bfb9 docs(rootScope): Fix various typos 2013-04-15 11:46:21 +01:00
Laurent cfea2095ca docs(Angular.js): fix typo 2013-04-15 11:46:21 +01:00
Pete Bacon Darwin 171bec3b0e doc(overview): add link to angular demo slides to overview 2013-04-15 11:23:00 +01:00
brandonjp 93891ad2e9 docs(ngController): fix docs link to api/ng.$route 2013-04-13 18:26:07 +02:00
Seunghoon Yeon eece726651 docs(module): fix typo 2013-04-13 18:17:04 +02:00
uberspeck dc6665caed docs(faq): added note to FAQ re: legacy IE support 2013-04-12 16:00:53 -07:00
Dave Geddes 5b592cbaf4 chore(Grunt) update grunt-contrib-copy
grunt-contrib-copy@0.4.1 has the cleaner summary output by default
2013-04-11 16:31:05 -07:00
Lee Leathers 348138d7cd style(exceptionHandler): add ws 2013-04-11 15:32:32 -07:00
Lee Leathers 6a34a4ebeb chore(NPM): Add license info 2013-04-11 15:32:31 -07:00
Prathan Thananart 5ca247c749 docs(guide): Update $locationProvider docs.
Default hashPrefix setting is not `'!'`, it's actually `""`.
Source: https://github.com/angular/angular.js/blob/master/src/ng/location.js#L472
2013-04-11 15:29:24 -07:00
kamagatos b16bffbf76 docs(guide/i18n): fix a typo 2013-04-11 15:22:25 -07:00
Christoph Burgdorf b2aec3706d docs(jqLite): clarified that children/parent do not support selectors 2013-04-11 15:11:51 -07:00
Matt Haggard d577c5def1 docs: fix typos 2013-04-11 15:05:16 -07:00
玉黍 a4dd14952e set ng-app as personalLog 2013-04-11 15:00:54 -07:00
Brent Morrow 8879b3733e docs(ngApp): fixed typo
Use this directive to auto-bootstrap **an** application.
2013-04-11 14:59:30 -07:00
Brent Morrow 35b02226ca docs(guide/concepts): fix typo
An event is a user **interaction**, timer event, or network event (response from a server).
2013-04-11 14:57:03 -07:00
Brent Morrow 814feaa2ab docs(guide/concepts): wording change
... or when working with --> a <-- third-party library callbacks.
... or when working with third-party library callbacks.
2013-04-11 14:55:31 -07:00
{Qingping,Dave} Hou aa2e66dcaf docs(guide): Added $ sign to controller example 2013-04-11 14:33:21 -07:00
urenmj 7b7b12e477 docs(dev-guide): Fixed a typo. 2013-04-11 14:19:18 -07:00
Artur Ostrega 187cd0a058 docs(http): spelling, grammar, capitalization, etc.
Conflicts:
	src/ng/http.js
2013-04-11 14:09:12 -07:00
Brent Morrow 0c690af2fe docs(guide/concepts): wording change 2013-04-11 14:07:59 -07:00
Brent Morrow 40ecd2d8e5 docs(guide/expression): wording changes 2013-04-11 14:05:08 -07:00
Luc Morin 484286d536 docs(guide/directives): give more details about directive declaration 2013-04-11 14:02:06 -07:00
Colin Kahn d56b62dcda docs(guide/filters): document multiple arguments syntax
Add example of using a filter with that accepts multiple arguments.
2013-04-11 13:55:47 -07:00
Brent Morrow b94125ac14 docs(angular-mocks): fix wording 2013-04-11 13:52:02 -07:00
Brent Morrow 3f34319398 docs($inject): wording change 2013-04-11 13:48:31 -07:00
David Sanders ba076a29b9 docs($compile): improve docs 2013-04-11 13:06:56 -07:00
Brian Campbell 13000c7350 docs(guide): updates for legacy IE7 support
- note re: id="ng-app" to bootstrap/IE partials
- added doctype/xmlns to markup
- add cond comment re: json2/3 to markup
2013-04-11 13:00:41 -07:00
Igor Minar fd2649fc65 chore(release): start 1.0.7 monochromatic-rainbow iteration 2013-04-11 12:55:32 -07:00
Chad Whitacre 437b09c155 docs($http): fix a typo 2013-04-11 12:50:26 -07:00
Takashi Matsuo b2b015a53b chore(docs): Fixed incomplete merge 2013-04-11 10:28:10 -07:00
Heath Matlock 5bea4c5692 docs(concespts): correct spelling and remove unnecessary word 2013-04-06 23:08:52 +02:00
Igor Minar 1b527b7acf docs(changelog): add release notes for 1.1.4 and 1.0.6 2013-04-04 12:15:42 -07:00
Igor Minar 4b8629b6b8 chore(release): cut 1.0.6 universal-irreversibility release 2013-04-04 10:48:05 -07:00
Misko Hevery ed81d19ce9 chore(docs): correct few unclosed elements
Conflicts:

	src/ng/filter/filter.js
2013-04-04 09:46:46 -07:00
Felipe Lahti 3497bf2d82 docs(guide): add missing closing div tag 2013-04-04 09:43:47 -07:00
Felipe Lahti afcf03fd2c docs(guide): fix typo in DI. angualar -> angular 2013-04-04 09:43:35 -07:00
Gert Goet 582612b000 docs(mocks): fix typos
Conflicts:

	src/ngMock/angular-mocks.js
2013-04-04 09:43:16 -07:00
Srinivas Kusunam 7bf32ccadb docs(directive): fix typo 2013-04-04 09:42:12 -07:00
Matthew McComb f5c18861b6 docs(controller): improve $controller function doc readability
Improved $controller function doc readability.
2013-04-04 09:42:01 -07:00
Misko Hevery 4acd75b904 fix(mock): prevent NPE when module definition outside of it. 2013-04-04 09:30:07 -07:00
James deBoer cd6dd22b19 Update forms.ngdoc
docs(forms): Fixed a typo. render -> $render
2013-04-04 09:29:51 -07:00
Chirayu Krishnappa 139c532019 chore($ngLocale): refactor slurper & parse extended datetime symbols 2013-04-04 09:28:23 -07:00
Chirayu Krishnappa e5b57bf01c chore($ngLocale): generate ngLocale files from the Closure code (includes datetimesymbolsext.js) 2013-04-04 09:00:36 -07:00
Mark Chapman 5ecd6d4e0a refactor(ngRepeat): make use of declared variable
Rename unused arrayLength variable to arrayBound and use it inside loop
2013-04-04 08:59:19 -07:00
Igor Minar 03bbe9aab1 docs($resource): improve installation section 2013-04-04 08:57:14 -07:00
Ciro Nunes 0ef9d54ccd docs($resource): Added an installation section. 2013-04-04 08:54:45 -07:00
Igor Minar 6ade77efa2 chore(karma): upgrade karma to 0.8.4
we needed this upgrade to disable animations in scenario runner
(karma ships with its own copy of angular-scenario.js which
got update in 0.8.4)
2013-04-03 18:22:31 -07:00
Vojta Jina 91fa865bf2 chore: use Karma 2013-04-03 18:22:03 -07:00
Igor Minar 10ae76673c docs(ngSwitch): improve the @usage example 2013-04-01 21:35:02 -07:00
Arlen Christian Mart Cuss 9497757842 chore(select): Fix ngOptions regexp capture comment.
Off-by-one error.
2013-03-20 11:45:42 -07:00
Javier Mendiara Cañardo bb5abe0e9c chore(Angular): remove superfluous fromCharCode function
Remove fromCharCode function as it was used only in two inner
functions in the code, and its functionality is achieved in several
other places by using String.fromCharCode

Breaks fromCharCode closure function, String.fromCharCode should be
used instead
2013-03-20 11:41:14 -07:00
Bruno Coelho 76c0ddfc0b docs(filter): Using indefinite article
This doc was using both definite article and indefinite article at the same time.
2013-03-20 11:41:14 -07:00
Arlen Christian Mart Cuss 36b888e781 docs(directive): Fix entity confusion in example. 2013-03-20 11:41:14 -07:00
Manuel Braun a476972e2e fix($location): parse FirefoxOS packaged app urls
FirefoxOS uses special URLs like
app://{d0419af1-8b42-41c5-96f4-ef4179e52315}/index.html for packaged Apps.

Closes #2112
2013-03-15 21:19:58 -07:00
Jamie Mason 866d3fb573 $routeChangeSuccess documentation
I hope this helps someone, I ran into some issues when following the API as described - handlers of this event receive 3 arguments, not 2.

Although this is mentioned [elsewhere](http://docs.angularjs.org/api/ng.$rootScope.Scope#$on) it's not clear when viewing the docs for this behaviour in isolation. 

The first argument is an Event Object, not the current route. The previous route argument can also be omitted on occasions.
2013-03-15 21:02:14 -07:00
Shyam Seshadri 70cf0a389f feat(docs): Add Improve this doc link in each doc page, which links to the edit mode of that file in github 2013-03-15 20:56:22 -07:00
Sujeet Pillai 7d4ccea579 fix(timezone): correct timezone date filter for 1/2 hour offsets 2013-03-14 22:18:20 -07:00
Shyam Seshadri 654dd1d5e8 Fix failing test in IE 10 2013-03-14 22:04:06 -07:00
Arlen Christian Mart Cuss bf114f6ee3 docs($injector): correct misuse of $inject
$inject was used where $injector was appropriate; confusing and
misleading.
2013-03-12 13:00:46 -07:00
Igor Minar 5727eaf767 chore(Gruntfile): run webserver on 0.0.0.0
... so that we can access it from local VMs.

The security risk of doing this is very low since only the current
working directory is being made accessible to everyone. There is also
an option to run a local firewall, which is a better way to secure the
developer's machine anyway.
2013-03-11 15:27:35 -07:00
Thibault Leruitte 346e98330c fix($location): correctly rewrite html5 url to hashbang url
In situations where path() matched basepath and we needed to
convert from html5 url to hashbang url, the $location service
considered the url to be already rewritten, which resulted in
an error.
2013-03-11 15:27:31 -07:00
Christian Vuerings 2b1f10266a docs(ngCloak): update the CSS rule with data-ng-cloak 2013-03-08 17:26:07 -08:00
Chirayu Krishnappa fc7970fdf0 chore($ngLocale): Generate ngLocale files from the Closure code. 2013-03-08 17:00:03 -08:00
Jason Morrison 65957e99ba docs($injector): remove extranneous 'the' from injector docs 2013-03-08 23:49:03 +01:00
Niel de la Rouviere 7f9a94f8bc docs(directive): minor typo fix
Changed "obeject" to "object"
2013-03-08 23:30:00 +01:00
Igor Minar cb560e2441 test($route): add tests for matching 'otherwise' routes 2013-03-08 12:01:09 -08:00
Igor Minar 55856565c2 fix($route): make nextRoute.$route private
the `nextRoute` object available in `$routeChangeStart` handler
accidentaly leaked  property which pointed to the route definition
currently being matched.

this was done just for the internal needs of the `$route` implementation
and was never documented as public api.

Some confusion arouse around why the $route property was not always
available on the `nextRoute` object (see #1907). The right thing for us
to do is to prefix the property with $$ for now and refactor the code
to remove the property completely in the future. Application developers
should use the `nextRoute` object itself rather than its `$route` property.
The main diff is that nextRoute inherits from the object referenced by $route.

BREAKING CHANGE: in $routeChangeStart event, nextRoute.$route property is gone.

Use the nextRoute object instead of nextRoute.$route.

Closes #1907
2013-03-08 12:01:05 -08:00
Julie 13968343d4 feat(angular.bootstrap): support deferred bootstrap
This features 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.

If window.name contains prefix NG_DEFER_BOOTSTRAP! when
angular.bootstrap is called, the bootstrap process will be paused
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.

Conflicts:

	src/Angular.js
2013-03-06 16:25:21 -08:00
Dave Geddes 4c428121b9 docs(contribute): add note about running command line as admin on win 2013-03-06 14:55:42 -08:00
Igor Minar 4816f7ee5c chore(Grunt): include dot files in the final zip 2013-03-06 14:23:05 -08:00
Dave Geddes ce53fbde50 chore(Grunt): don't remove root dir from zip 2013-03-06 13:20:54 -08:00
Igor Minar 1516a69cd2 docs($http): add more info about transform function 2013-03-06 11:20:49 -08:00
Dave Geddes 7a77fdae4f chore(Grunt): switch from Rake to Grunt
Migrates the Angular project from Rake to Grunt.

Benefits:
- Drops Ruby dependency
- Lowers barrier to entry for contributions from JavaScript ninjas
- Simplifies the Angular project setup and build process
- Adopts industry-standard tools specific to JavaScript projects
- Support building angular.js on Windows platform (really?!? why?!?)

BREAKING CHANGE: Rake is completely replaced by Grunt. Below are the deprecated Rake tasks and their Grunt equivalents:

rake --> grunt
rake package --> grunt package
rake init --> N/A
rake clean --> grunt clean
rake concat_scenario --> grunt build:scenario
rake concat --> grunt build
rake concat_scenario --> grunt build:scenario
rake minify --> grunt minify
rake version --> grunt write:version
rake docs --> grunt docs
rake webserver --> grunt webserver
rake test --> grunt test
rake test:unit --> grunt test:unit
rake test:<jqlite|jquery|modules|e2e> --> grunt test:<jqlite|jquery|modules|end2end|e2e>
rake test[Firefox+Safari] --> grunt test --browsers Firefox,Safari
rake test[Safari] --> grunt test --browsers Safari
rake autotest --> grunt autotest

NOTES:
* For convenience grunt test:e2e starts a webserver for you, while grunt test:end2end doesn't.
  Use grunt test:end2end if you already have the webserver running.
* Removes duplicate entry for Describe.js in the angularScenario section of angularFiles.js
* Updates docs/src/gen-docs.js to use #done intead of the deprecated #end
* Uses grunt-contrib-connect instead of lib/nodeserver (removed)
* Removes nodeserver.sh, travis now uses grunt webserver
* Built and minified files are identical to Rake's output, with the exception of one less
  character for git revisions (using --short) and a couple minor whitespace differences

Closes #199

Conflicts:

	Rakefile
2013-03-05 23:35:13 -08:00
Andrew McLeod b13da18e11 fix($http): don't encode URL query substring "null" to "+"
Fixes issue in encodeUriQuery used by $http and $resource that
treats null as a string and replaces the characters "null" with "+".
2013-02-26 17:29:08 -08:00
Matt Ginzton f98f8a3892 docs(ngMock): fix minor typo in comment
Change "constroctor" to "constructor".
2013-02-25 23:55:54 -08:00
danilsomsikov 77c4a7fd66 fix($compile): compile replace directives in external template
Passing DOMNode#childNodes to compileNodes when compiling remote
template, so that directives with replace:true can be compiled.
The previous version used jqLite#contents which returned collection
that was not updated during the compilation.

Closes #1859
2013-02-25 21:45:44 -08:00
Igor Minar e281413919 chore(sortedHtml): print attributes with empty value
I had to also fix some tests as they started failing on IE8.

We should figure out why these extra attributes are set in IE8,
but I'm too tired of IE to worry about it now. Since I'm
not introducing this issue just making it visible, I'm going
to commit this as is.
2013-02-25 21:45:39 -08:00
Vineet Kumar 2007ddd3f8 docs(guide/directives): update obsolete doc reference
Replace an obsolete reference to a nonexistent "Creating Widgets"
section with a real link to "Creating Components".
2013-02-25 14:51:59 -08:00
Pawel Kozlowski d8922fe3e9 docs(dateFilter): properly specify range for the Z format modifier
Closes #1533
2013-02-25 13:51:38 -08:00
Igor Minar 6c611df8f0 fix($compile): whitelist file:// in url sanitization 2013-02-25 10:02:50 -08:00
Steven Davidson 6be24df5bc chore(nodeserver): fix log message for 301 response 2013-02-23 23:44:46 -08:00
Igor Minar 4759aacba9 fix($compile): handle elements with no childNodes property
see the test for more details
2013-02-23 23:40:03 -08:00
Igor Minar 802bfc259c chore(release): start 1.0.6 universal-irreversibility iteration 2013-02-23 21:11:14 -08:00
Igor Minar 64db8d166e docs(changelog): fix release notes 2013-02-20 15:44:09 -08:00
Igor Minar d2a769e196 chore(release): cut the 1.0.5 flatulent-propulsion release 2013-02-20 12:58:02 -08:00
Igor Minar 68a8c8907d docs(changelog): add release notes for 1.0.5 and 1.1.3 2013-02-20 12:57:08 -08:00
Igor Minar 701d61080a chore(matchers): fix hasBeenCalledOnceWith matcher
the error message was wrong and misleading
2013-02-20 08:44:53 -08:00
Igor Minar a8cc449706 fix($compile): sanitize values bound to a[href] 2013-02-20 00:40:51 -08:00
Per Rovegård 2aa212b19c fix(ngClass): keep track of old ngClass value manually
ngClassWatchAction, when called as a $watch function, gets the wrong old
value after it has been invoked previously due to observation of the
interpolated class attribute. As a result it doesn't remove classes
properly. Keeping track of the old value manually seems to fix this.

Closes #1637
2013-02-18 20:35:40 -08:00
Pete Bacon Darwin 1f23cfe9c7 fix(compile): should not leak memory when there are top level empty text nodes
The change to prevent <span> elements being wrapped around empty text nodes caused these empty text nodes to have scopes and controllers attached, through jqLite.data() calls, which led to memory leaks and errors in IE8.
Now we exclude all but document nodes and elements from having jqLite.data() set both in the compiler and in ng-view.

Fixes: #1968 and #1876
2013-02-18 13:04:24 +00:00
Will Moore 0fa8e47fb5 fix($httpBackend): patch for Firefox bug w/ CORS and response headers
A workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=608735
In FF getAllResponseHeaders() returns null if the request is the result of CORS.

Tried to format the code so that when a FF patch is released and gains enough
traction it can easily be selected and deleted. Heavily inspired by jQuery's
patch for the same bug. This patch falls short of passing through custom headers
but covers all of the "simple response headers" in the spec at
http://www.w3.org/TR/cors/

This commit should get reverted once Firefox 21 gets out.

Closes #1468

Conflicts:
	src/ng/httpBackend.js
2013-02-14 16:52:02 -08:00
Igor Minar 8043784fd7 fix(a): workaround IE bug affecting mailto urls
Apparently there is a really weird bug in IE6-8 that causes anchor textContent
to be reset with href content when both contain @ symbol.

Inserting a bogus comment node into all anchor elements in IE works around this
browser bug.

I'm fixing the issue via directive because that way we'll fix it for jQuery as
well.

I fixed an e2e test too because it was incorrect.

Closes #1949
2013-02-14 16:43:28 -08:00
Igor Minar 526a6b31e5 fix(*): don't use instanceof to detect arrays
this breaks when multiple javascript contexts are involved - like in node-webkit

see original PR: #1966

Closes #1966
2013-02-14 16:40:58 -08:00
Cedric Soulas 14fd064a62 docs($resource): fix bad indentation producing a code block 2013-02-14 15:45:37 -08:00
Ewen Cumming 3178afbf0c docs($rootScope): rearrange event listener docs 2013-02-14 15:42:51 -08:00
deboer ce3b616432 fix(ngSwitch): make ngSwitch compatible with controller BC module
add a $scope to the ngSwitch's controller to fool the controller
BC (backwards compatibility) module used by DFA.
2013-02-14 15:38:20 -08:00
Vineet Kumar 54a761905d docs($q): fix a few typos 2013-02-14 15:19:49 -08:00
Dylan Pyle aa531d7bd1 docs(guide): fix some invalid javascript in directive documentation
Use double quotes to maintain consistency with other HTML
2013-02-14 15:15:06 -08:00
Daniel Luz d7e9ae1215 fix($rootScope): minor typo fixes 2013-02-14 14:43:32 -08:00
Daniel Luz 6cf9ede88e docs($parse): document function argument types, fix minor typo 2013-02-14 14:43:32 -08:00
Trotter Cashion 6092291bd7 chore(reakefile): auto install npm packages 2013-02-14 14:43:31 -08:00
Shyam Seshadri 3d0f11212f fix(compiler): Allow startingTag method to handle text / comment nodes 2013-02-14 14:43:31 -08:00
Fredrik Bonander 6194e002e2 fix(resource): Update RegExp to allow urlParams with out leading slash
Will allow reoucese to be loaded from a relative path
Example:
var R = $resource(':path');
R.get({ path : 'data.json' });

Example usage:
Load resources in applications not using webserver, ie local webapp in
on a tablet.
2013-02-14 14:43:31 -08:00
Kury Kruitbosch 75545d4d1c fix(numberFilter): fix formatting when "0" passed as fractionSize
When checking to add decimal and trialing 0s number filter used to check
trueness of fractionSize. "0" evaluating to true causes "123" to return "123."
2013-02-14 13:46:07 -08:00
Jesse Cooke d67eb2f2db docs(guide): Fix typos in concepts/model,view. 2013-02-14 13:09:40 -08:00
Igor Minar 6b8153ff0f chore(Rakefile): parallelize the build on Travis
now that the forking issue is solved we can run regular build there

https://github.com/travis-ci/travis-ci/issues/845
2013-02-14 12:52:20 -08:00
Cedric Soulas fb132732f1 docs($resource): fix missing punctuation 2013-02-14 12:14:13 -08:00
Igor Minar 336b157497 test(angular.copy): add tests for scenarios when target is missing 2013-02-11 22:10:58 -08:00
Igor Minar d16975a9de revert: refactor(angular.copy): use slice(0) to clone arrays
This reverts commit a5b3bcf41c.

slice(0) doesn't perform deep copy of the array so its unsuitable
for our purposes.
2013-02-11 22:01:15 -08:00
Igor Minar 87f6b36bab chore(docs): improve docs parser type
previously we barfed on function type definition with optional arguments
like {function(number=)}

this fixes it

I also added a bunch of code that helps to debug incorrectly parsed docs.
2013-02-11 14:08:27 -08:00
Igor Minar 43fccf5617 refactor(angular.copy): use array.length=0 to empty arrays 2013-02-11 14:07:57 -08:00
Igor Minar a5b3bcf41c refactor(angular.copy): use slice(0) to clone arrays
slice(0) is way faster on most browsers
2013-02-11 14:07:10 -08:00
Igor Minar 8801d9c286 fix(angular.forEach): correctly iterate over objects with length prop
Should handle JQLite, jQuery, NodeList and other objects like arrays
but not other generic objects or instances of user defined types
with length property.

Closes #1840
2013-02-11 12:46:13 -08:00
radu a8e114f351 docs($q): fix typos 2013-02-07 04:16:49 -08:00
Julie 9a3a9b46e5 fix(scenario): include error messages in XML output
Fix the XML output of scenario tests so that it properly includes error
messages from failing specs.
2013-02-07 04:10:17 -08:00
Enrique Paredes 934204ec18 fix($compile): rename $compileNote to compileNode
Directives was observing different instances of Attributes than the one
that interpolation was registered with because we failed to realize
that the compile node and link node were the same (one of them
was a wrapper rather than raw node)

Closes #1941
2013-02-07 02:49:18 -08:00
Fredrik Bonander 7cb8f8fb44 fix($cookies): set cookies on Safari&IE when base[href] is undefined
Safari and IE don't like being told to store cookies with path set to
undefined. This change ensures that if base[href] (from which cookie path
is derived) is undefined then the cookie path defaults to ''.

The test verifies that the cookie is set instead of checking that cookie has correct path,
this is due to that cookie meta information is not avabile once the cookie is set.

Closes #1190, #1191
2013-02-07 02:36:52 -08:00
Philip Roberts 8d34bf2fea fix(date): invert timezone sign and always display sign
This commit fixes #1261 and #1532. This covers
two separate issues:

- Positive timezones were being formatted without
a leading `+` resulting in a formatting string
like: "HH:MM:ssZ" giving "12:13:141000" instead
of "12:13:14+1000". Fixed by checking if timezone
is > 0 and adding a leading "+".

- Timezone output signs were inverted.
mock.TzDate expects the timezone _offset_ as it's
first argument, _not_ the timezone. This means
that a mock.TzDate with a positive offset should
result in a date string with a negative timezone,
and vice-versa.

Closes #1261, #1532
2013-02-07 01:47:19 -08:00
Igor Minar 8801e69dba docs(guide): remove stale info about filters changing DOM
as of v0.10.6 this is not the case any more
2013-02-06 14:15:43 -08:00
Thomas Schultz f4afa398a1 docs(tutorial): remove extra back-tick character 2013-02-06 22:22:55 +01:00
theotheo 32063278bd docs(module): fix code example 2013-02-06 21:36:21 +01:00
radu 92208d2f85 docs(ngApp): fix typo 2013-02-05 22:14:43 +01:00
Igor Minar ab7c74b4b9 docs(contributing): add CLA anchor for deeplinking 2013-02-04 09:38:55 -08:00
PowerKiKi e283abe171 docs(ngClass): fix typo in description 2013-02-04 10:37:19 +00:00
Brian Ford d7620f68bb feat(Scope): expose transcluded and isolate scope info for batarang
test($compile): add test for exposing transclude and isolate scope info to batarang
2013-01-30 10:44:35 -05:00
Dean Sofer 971d97e2ec docs($cookies): added example to $cookies api docs
Better than nothing.
2013-01-29 16:17:12 -08:00
radu 559d5efc04 docs(nextUid): fix typo
Update src/Angular.js

removed redundant 'the' from nextUid()'s ngdoc
2013-01-29 15:50:03 -08:00
radu 85042820fb docs(tutorial): fix typo
Update docs/content/tutorial/step_00.ngdoc

removed redundant verb
2013-01-29 15:47:43 -08:00
Fred Sauer 24a2eec815 docs(Scope): fix argument docs for $on 2013-01-29 15:39:10 -08:00
metaweta d987a79ab1 test(ngBindHtml): prevent variable name leak
Add "var" so element is local instead of global

Strict mode doesn't allow undeclared global vars, and these really should be local anyway.
2013-01-29 15:35:03 -08:00
metaweta eba09353e6 refactor(Angular.js): prevent Error variable name leak in tests
Remove var Error = window.Error

window.Error is a read-only property in Apps Script.

Igor says, "we should just delete that line instead. I think it was
misko's attempt to get better closure minification, but it turns out
that it's actually hurting us after gzip (I verified it)."
2013-01-29 15:35:03 -08:00
Igor Minar 297660c9a3 chore(release): start 1.0.5 flatulent-propulsion iteration 2013-01-29 15:34:04 -08:00
Fred Sauer 8343c05fd8 docs(a): escape sample code in ng a directive 2013-01-26 23:03:40 +01:00
Igor Minar 7c3d064786 fix(docs): properly generate angular.js urls in doc examples 2013-01-24 11:36:42 -08:00
Igor Minar c2ccc1cbdf docs(date): add missing doc about TZ behavior 2013-01-24 10:51:47 -08:00
Igor Minar 04e080660a docs(changelog): correct 1.0.4 release notes 2013-01-24 09:50:51 -08:00
Vineet Kumar f3cca88384 docs($injector): clarify $inject property description
Section heading about `$inject` property refers to it as `$injector` property.
2013-01-24 00:18:48 -05:00
Igor Minar 978bbd2d49 chore(release): update the CDN version 2013-01-23 12:07:01 -08:00
Igor Minar 652feebd86 chore(release): cut the 1.0.4 bewildering-hair release 2013-01-23 10:57:51 -08:00
Igor Minar 16ccbc4f61 docs(changelog): release notes for 1.1.2 and 1.0.4 2013-01-23 10:57:51 -08:00
Igor Minar 072d45fd01 chore(changelog.js): improve the changelog script 2013-01-23 10:57:51 -08:00
pavelgj 4439e39319 fix(ngResource): correct leading slash removal.
Fixed an issues with ngResource param substitution where it was incorrectly removing leading slash when param was followed by a non-slash character.
Ex:
'/:foo/:bar.baz/:aux'

params = {
  foo: 'aaa',
  bar: undefined,
  aux: undefined
}

The above params were incorrectly producing '/aaa.baz' but now it results in '/aaa/.baz'.
2013-01-22 11:32:27 -08:00
Miško Hevery b49c3a1a1e docs(q): added testing information 2013-01-22 11:32:27 -08:00
Igor Minar c7addd4886 fix(angular.equals): relax the comparison for undefined properties
in 5ae63fd3 the comparison was made consistent but strict, so that

angular.equals({}, {foo: undefined}) // always returns false

this turns out to cause issues for data that is being roundtripped via network
and serialized via JSON because JSON.stringify serializes {foo: undefined} as {}.

Since angular.equals() behaved like this before the 5ae63fd3 in 50% of the cases,
changing the behavior in this way should not introduce any significant issues.

Closes #1648
2013-01-22 07:35:06 -08:00
Igor Minar 6df60aff52 chore(Rakefile): skip build parallelization on Travis
Due to a infrastructure change on Travis starting JVMs in forked
processes doesn't currently work. Since we don't really care that
much about the build speed on Travis, I'm going to disable it there.

Related issue: https://github.com/travis-ci/travis-ci/issues/845
2013-01-21 07:50:24 -08:00
sergiopantoja e7a080d6e6 docs(jqLite): fix typo 2013-01-20 18:59:43 +01:00
Will Moore 661a728764 docs(contribute): adding npm install to step-by-step
npm install is listed in the dependencies section of the contribute guide but
is missing from the step-by-step. This adds it as step 4.
2013-01-18 21:33:58 -08:00
danilsomsikov 89303fd2dc fix(ngSwitch): don't leak when destroyed while not attached
The leak can occur when ngSwich is used inside ngRepeat or any other
directive which is destroyed while its transcluded content (which
includes ngSwitch) is not attached to the DOM.

Refactor ngSwitch to use controller instead of storing data on compile
node. This means that we don't need to clean up the jq data cache.
Controller reference is released when the linking fn is released.

Closes #1621
2013-01-18 00:03:42 -08:00
Fred Sauer 1f8be1ca66 docs(exceptionHandler): document testing
Update src/ng/exceptionHandler.js

Here's an iniitla attempt at documenting how one might write a
test using $exceptionHandlerProvider. The key take-away is the use
of this pattern:

it(...

 module(...
   $exceptionHandlerProvider.mode('log');
 });

 inject(...
 );

});
2013-01-17 23:11:02 -08:00
Matthew Browne cbc2024092 docs(rootScope): correct code examples 2013-01-17 23:11:02 -08:00
Amir H. Hajizamani f0ff7023c3 docs(cookbook): change prototype methods to scope methods in Buzz
As explained in 'Understanding the Controller Component', Controllers
written for new (post 1.0 RC) versions of Angular need to add methods to
the scope directly, not the function's prototype. Correcting this
example should remove any ambiguity, especially for beginners.
2013-01-18 00:56:52 -05:00
Amir H. Hajizamani 6e8728a364 docs(guide): change prototype methods to scope methods in DI examples
As explained in 'Understanding the Controller Component', Controllers
written for new (post 1.0 RC) versions of Angular need to add methods to
the scope directly, not the function's prototype. Correcting this
example should remove any ambiguity, especially for beginners.
2013-01-18 00:56:52 -05:00
Fred Sauer f179a63dd4 docs(ngMock.$httpBackend): fix variable declaration 2013-01-18 00:15:20 -05:00
Shai Reznik 3a71c1e595 doc(guide): Fix examples of $location.html5mode 2013-01-17 23:46:19 -05:00
Shai Reznik ef7a61a67e doc(guide): Fixed typos at the unit tests guide 2013-01-17 23:46:19 -05:00
Igor Minar a6b2ee785b fix(angular.equals): consistently compare undefined object props
previously:

a = {};
b = {x:undefined};
angular.equals(a, b) == angular.equals(b, a) // returns false.

both should return false because these objects are not equal.

unlike in implemented in #1695 the comparison should be stricter
and return false not true. if we need to relax this in the future
we can always do so.

Closes #1648
2013-01-17 17:49:07 -08:00
Daniel Demmel d5a1336e6b docs: recommend using Google CDN 2013-01-17 16:53:32 -08:00
Matt Rohrer d4312b731a docs(guide): minor grammar fixes 2013-01-17 19:36:14 -05:00
Martin Probst 66f051386e feat($compile): support modifying the DOM structure in postlink fn
Support modifying the DOM structure in the post link function of a directive
by creating a defensive copy of the node list, as opposed to a live DOM list.
This is useful for directives to actually replace their entire DOM fragment,
e.g. with the HTML fragment generated by a 3rd party component (Closure, Bootstrap ...).
Fix the indentation of the compileNodes function (was one too little).
2013-01-17 12:57:36 -08:00
Igor Minar 8b3f9684e0 style($compile): fix indentation 2013-01-17 12:55:21 -08:00
Gergely Imreh 331f32deac chore(Rakefile): force 32bit JVM mode only when java supports it
Some Java installs don't have '-d32' flag (e.g. OpenJDK which is standard
for some Linux systems), and the closure_compile fails because of forcing
that flag. Test, and only run in faster 32bit mode if supported, or
else just run with no flag (default mode).
2013-01-17 10:44:39 -08:00
Igor Minar bb80c96754 chore(docs): use done() instead of end() in gen-docs.js 2013-01-17 00:52:19 -08:00
Pete Bacon Darwin 0d8e19c26f fix($compile): do not wrap empty root text nodes in spans
Closes #1059
2013-01-17 00:28:56 -08:00
Pete Bacon Darwin ed2fd2d0ca fix(ngRepeat): correctly apply $last if repeating over object
If the $last property is calculated from the original collectionLength
on an object and properties starting with $ were filtered out, then $last
is never applied and $middle is applied erroniously.

Closes #1789
2013-01-17 00:25:07 -08:00
James deBoer 7c60151cb8 chore(Rakefile): remove a duplicate file in angularFiles.js 2013-01-16 23:45:13 -08:00
James deBoer 965308a32c chore(Rakefile): generate version.json
Changes 'rake version' to output a version.json file which
contains the structured version info which can be used in other tools.
2013-01-16 23:41:51 -08:00
Igor Minar 92c612a9de fix(scenario): don't trigger input events on IE9
input.enter() should trigger 'change' rather than 'input' event on IE9 because
input events on IE9 are broken and angular doesn't rely on them
2013-01-16 23:30:16 -08:00
Kanwei Li a7b53abcad docs(CHANGELOG): fix typo 2013-01-16 23:29:11 -08:00
Martin Probst d575e1f613 fix($route): support route params not separated with slashes.
Commit 773ac4a broke support for route parameters that are not seperated
from other route parts by slashes, which this change fixes. It also adds
some documentation about path parameters to the when() method and
escapes all regular expression special characters in the URL, not just
some.
2013-01-16 09:42:35 -08:00
Igor Minar 2ba458387d fix($compile): safely create transclude comment nodes
Closes #1740
2013-01-14 21:59:23 -08:00
Lucas Galfasó 98489a1d0c doc(directive): Fix typos in dialog widget
Fixes #1799
2013-01-13 10:09:22 +00:00
Igor Minar 51d501aab2 chore(*): remove obsolete files 2013-01-09 21:29:13 -08:00
naomiblack 841bdf1c07 Update docs/content/misc/faq.ngdoc
Updated the canonical video to a recent one. Fixed a typo.
2013-01-09 09:50:27 +00:00
Pete Bacon Darwin 86cac55c7c fix(jqLite): children() should only return elements
The jQuery implementation of children only returns child nodes of the given element that are elements themselves. The previous jqLite implementation was returning all nodes except those that are text nodes. Use jQLite.contents() to get all the child nodes.

The jQuery implementation of contents returns [] if the object has no child nodes.  The previous jqLite implementation was returning undefined, causing a stack overflow in test/testabilityPatch.js when it tried to `cleanup()` a window object.

The testabilityPatch was incorrectly using children() rather than contents() inside cleanup() to iterate down through all the child nodes of the element to clean up.
2013-01-09 09:42:05 +00:00
Keyamoon c0995399d4 fix(jqLite): make next() ignore non-element nodes
next() is supposed to return the next sibling *element* so it
should ignore text nodes. To achieve this, nextElementSibling()
should be used instead of nextSibling().
2013-01-08 14:54:56 -08:00
Igor Minar de6cc287e5 fix($injector): remove bogus fn arg
getService fn takes only one argument, removing the second one.

Closes #1711
2013-01-08 14:36:36 -08:00
Igor Minar afd6771163 refactor($browser): remove faulty 20+ cookies warning
the warning is defunct (and the test is incorrect) so obviously nobody is using
it and it just takes up space.

also the browser behavior varies (ff and chrome allow up to 150 cookies, safari
even more), so it's not very useful.

Closes #1712
2013-01-08 14:27:51 -08:00
Igor Minar 4cda028609 revert: fix(a): prevent Opera from incorrectly navigating on link click
This reverts commit c81d8176cc.

This commit causes several issues (#1651, #1674, #1662) and doesn't even
contain a test that proves that anything on Opera got actually fixed.

If the original Opera resurfaces, we'll fix it properly.
2013-01-08 11:51:17 -08:00
kim lokoy 8ecce7642b docs(guide): fix typos in unit test guide 2013-01-07 21:00:13 +01:00
Pawel Kozlowski d1d5761232 docs(forms): fix code example for a custom form control
Closes #1021
2013-01-05 23:04:33 +01:00
naomiblack 759cba1a8d docs(faq): add info on logo reuse and how to get t-shirts and stickers 2013-01-04 19:22:00 +01:00
Jonathan Card 23cd40a8ec docs(form): minor form doc and example fixes
Form documentation fixes:
- Fix broken form example in docs
- A few small other corrections in form docs.
2013-01-04 17:25:24 +01:00
Per Rovegård f3188c1d09 docs($http): clarify documentation on error status codes
Modify the documentation for $http to correspond to what Angular
considers a success status code.

Closes #1693
2013-01-03 20:47:55 +01:00
Matt Hardy 2f4967f100 docs(guide): change example controller to properly call greet method on greeter 2012-12-31 13:21:29 +01:00
Murilo da Silva 4fe4e7457c docs(anchorScroll): correct word "location" 2012-12-19 21:14:09 +01:00
John Fletcher d4e7274d4b docs(guide): minor English corrections to the Directive guide 2012-12-19 20:55:22 +01:00
Miško Hevery cffa015554 docs(directive): old syntax 2012-12-18 20:39:17 -08:00
Pawel Kozlowski 1104c7d75b docs(ngView): fix code example (change template to templateUrl)
Closes #1715
2012-12-18 17:56:04 +01:00
Gonzalo Ruiz de Villa 4c6b4447db fix($route): correctly extract $routeParams from urls
Routes like '/bar/foovalue/barvalue' matching '/bar/:foo/:bar'
now are well mapped in $routeParams to:
{bar:'barvalue', foo:'foovalue'}

Closes: #1501
Signed-off-by: Gonzalo Ruiz de Villa <gonzaloruizdevilla@gmail.com>
2012-12-14 01:16:07 +01:00
ggoodman 741a37b338 feat(docs): Add angularjs tag to plunks and make private
This is a minor edit to allow Plunks created by way of the docs.angularjs.org site to be appropriately tagged as `angularjs`.
Also, make these generated Plunks private by default.
2012-12-12 21:00:41 +00:00
Peter Evjan 1157c5d341 docs(README.md): add missing 'you' and a comma 2012-12-11 19:33:28 +01:00
Romain Neutron e48adebfb7 docs(guide): fix injector service code example
Fix syntax and update code to the latest API
2012-12-10 23:50:12 +01:00
Juha Syrjälä 0a61dcb486 docs($resource): document port number escaping and fix typo 2012-12-09 17:49:42 +01:00
Eric Case 4b51eaadf8 docs(tutorial): typo fix commandx -> command 2012-12-08 11:39:56 +01:00
Eric Case e2457ca16d docs($q): typo fix - programing -> programming 2012-12-07 21:00:25 +01:00
János Rusiczki bd62790080 doc(concepts): Fix typo in $render() function 2012-12-07 10:19:08 +00:00
Jeremy Tymes 53fdcafa44 docs($http): fix link typo in $http doc
Should be $httpBackend instead of $httpBacked

Closes #1516
2012-12-06 21:50:21 +01:00
Fred Sauer af6f2483be docs(mocks): update src/ngMock/angular-mocks.js documentation
Clarify how to use `$exceptionHandlerProvider.mode('log')` in tests
2012-12-06 21:50:21 +01:00
Fred Sauer d8522aa349 docs(mocks): fix documentation bug: angular.mock.debug 2012-12-06 21:50:20 +01:00
Igor Minar bae3121683 chore(bootstrap-prettify): update urls to code.angularjs.org
Closes #1599
2012-12-05 02:55:19 +01:00
_pants 54c0d464b0 fix(select): support optgroup + select[multiple] combo
Closes #1553
2012-12-05 02:21:31 +01:00
Sudhir Jonathan cf89e8653c fix($injector): provider can now be defined in the array format
`injector.instantiate` is now called for arrays too, instead of only for functions.

Closes #1452
2012-12-01 19:09:36 +01:00
Sudhir Jonathan 0c3500f532 fix($resource): HTTP method should be case-insensitive
Perform call `angular.uppercase` on all given action methods.

Closes #1403
2012-11-30 23:23:34 +01:00
Cezar Berea c12f525df4 refactor($resource): fix indentation and move a method definition
Moved Resource.bind out of the actions forEach
2012-11-30 22:47:25 +01:00
Igor Minar e7ba830691 fix(Scope): ensure that a scope is destroyed only once
Due to bd524fc4 calling $destroy() on a scope mupltiple times cases NPE.

Closes #1627
2012-11-30 13:09:50 +01:00
Daniel Luz 4eb0716711 docs(directive): correct expression, fix typo and re-wrap lines 2012-11-29 20:22:41 +01:00
Johannes Hansen ed90f3b7ea fix(docs): add missing </div> tag to sourceEdit directive template 2012-11-29 20:22:40 +01:00
Igor Minar 14b19ecf5e docs(menu): fix the navbar drop down links 2012-11-28 23:56:21 +01:00
Igor Minar 644432a14c chore(release): start 1.0.4 bewildering-hair iteration 2012-11-28 15:51:23 +01:00
Igor Minar a03e370a09 chore(release): cut the 1.0.3 bouncy-thunder release 2012-11-27 01:44:46 +01:00
Igor Minar 23677d3ddb docs(CHANGELOG): release notes for 1.0.3 and 1.1.1 releases 2012-11-27 01:44:46 +01:00
Rado Kirov fc781560a3 fix($location): reset $location.$$replace with every watch call
Closes #1111
2012-11-26 23:24:39 +01:00
Vojta Jina c9199ee663 docs: load angular from CDN only on production
So that when running the docs locally, eg. during e2e testing, we use the latest build version of angular, rather than the stable one from CDN.

This fixes e2e tests running with Testacular.
2012-11-26 21:33:45 +01:00
Igor Minar 6f18adedef fix(ngClassOdd/ngClassEven): support shrinking/reordering in repeaters
We need to watch $index in addition to cssClasses because only then
we can correctly respond to shrinking or reordered repeaters.

Closes #1076
2012-11-26 21:33:45 +01:00
Igor Minar 6ad894cd58 style(jqLite): better variable names
selector => cssClasses
2012-11-26 21:33:45 +01:00
Igor Minar cde2f1a868 fix(ngRepeat): support mostly-stable repeating for primitives
I'm reverting changes that were originally done to ngRepeat to fix #933,
because these are now not necessary after the previous changes to keep
ngModel always synced with the DOM.
2012-11-26 21:33:45 +01:00
Igor Minar 6a831495de fix(ngModel): sync ngModel state with scope state
In cases when we reuse elements in a repeater but associate
them with a new scope (see #933 - repeating over array of
primitives) it's possible for the internal ngModel state and
the scope state to get out of sync. This change ensure that
the two are always sync-ed up even in cases where we
reassociate an element with a different (but similar) scope.

In the case of repeating over array of primitives it's still
possible to run into issue if we iterate over primitives and
use form controls or similar widgets without ngModel - oh well,
we'd likely need a special repeater for primitives to deal
with this properly, even then there might be cornercases.

Closes #933
2012-11-26 21:33:45 +01:00
Igor Minar 6e2c38f54d test(ngRepeat): clean up and improve tests 2012-11-26 20:39:10 +01:00
Igor Minar 00e7e31418 fix(ngRepeat): attempt to simplify and improve existing fix for #933
I'm keeping this in for future reference. The issue with this solution
is that if we shift() the first item in the array, the whole repeater
DOM will be rebuilt from scratch, we need to do better than that.
2012-11-26 20:39:00 +01:00
Igor Minar ff4b3e20c1 test(ngRepeat): add test for issue #1076 2012-11-26 20:38:51 +01:00
Igor Minar 269fb43b36 fix(jqLite): fire $destroy event via triggerHandler
in jQuery 1.8.x the data() data structure is changed and events are
not accessible via data().events. Since all we need is to trigger
all event handlers, we can do so via triggerHandler() api instead of
mocking with the internal jQuery data structures.

This fix was originally proposed by PeteAppleton via PR #1512.

Closes #1512
2012-11-26 16:03:43 +01:00
Igor Minar 7530654328 feat(jqLite): add triggerHandler()
we need triggerHandler() to become jQuery 1.8.x compatible.

this is not fully featured triggerHandler() implementation - it doesn't
bother creating new DOM events and passing them into the event handlers.

this is intentional, we don't need access to the native DOM event for our
own purposes and creating these event objects is really tricky.
2012-11-26 16:03:39 +01:00
Iristyle c7bd464384 docs(CONTRIBUTING.md): add contrib info file for GitHub 2012-11-25 21:00:56 +01:00
Vojta Jina ef1874d1f3 fix(Scope): allow removing a listener during event 2012-11-25 11:41:32 +01:00
Kevin Western c6d8205fdd docs(README.md): fix "API Docs" link
use direct link to api docs
2012-11-25 01:24:03 +01:00
Dean Sofer 55150a669a docs(api): add ngRequired to input/select/textarea directives
Closes #1202
2012-11-25 01:19:47 +01:00
Jeremy Tymes 1eb9e22d45 fix($cacheFactory): return undefined when removing non-existent entry
Instead of throwning an exception, remove should return undefined when
cache entry to be removed doesn't exist.

Closes #1497
2012-11-24 21:58:17 +01:00
Adrian Gheorghe c0de8fb737 fix($resource): prevent default params to be shared between actions
Having a $resource defined as:

var R = $resource('/Path', {}, {
  get: {method: 'GET', params: {objId: '1'}},
  perform: {method: 'GET'}
});

was causing both actions to call the same URI (if called in this order):

R.get({}); // => /Path?objId=1
R.perform({}); // => /Path?objId=1
2012-11-24 21:29:16 +01:00
Kris Jenkins 557e3894d7 docs(): Fix a couple of typos in the documentation 2012-11-22 08:28:49 +01:00
Dave Clayton 38a9695413 docs(guide/concepts): some typo/grammar fixes 2012-11-22 08:28:49 +01:00
John Hume 293e0336b0 docs(guide/directive): fix typo 2012-11-22 08:28:49 +01:00
Uri Goldshtein 1f5bc0a1cd docs($q): fix missing bracket in the example 2012-11-22 08:28:49 +01:00
Igor Minar 1fe666192b fix($rootScope): workaround for Chrome's memleak
Under certain circumstances chrome fails to GC scopes
because of buggy optimizations and caching. Nulling out
references to (not from!) other scopes helps Chrome to
realize that this object should be GC-ed.

This is really just a workaround as the real problem needs
to be fixed in Chrome.

See discusstion at:
https://github.com/angular/angular.js/issues/1313#issuecomment-10378451

And chrome bug at:
https://code.google.com/p/v8/issues/detail?id=2073

Closes #1313
2012-11-14 19:53:29 +01:00
Igor Minar 29541e735d revert($resource): support custom headers per action
This reverts commit b936e52874.

This commit introduces a feature and should haven't been merged
into the stable branch.
2012-11-11 12:07:26 +01:00
Igor Minar f5b567d44b chore(validate-commit-msg): recognize 'revert' as valid commit type 2012-11-11 12:06:05 +01:00
Haralan Dobrev 5ee3bbee90 docs(angular.module): improve angular.Module#run docs 2012-11-11 11:40:52 +01:00
Jamison Dance 80927c5811 docs(guide): fix run-on sentence in modules guide 2012-11-11 11:35:20 +01:00
Jamison Dance ca8b344e20 docs(tutorial): change module name in step-7 2012-11-11 11:35:15 +01:00
Wes Alvaro 3dab93874d docs($timeout): set return type to Promise instead of *.
The cancel function accepts a Promise, but the timeout function
fails to specify returning a Promise.
2012-11-11 11:32:00 +01:00
Josh Adams 7550f90a57 docs(ngList): fix typo 2012-11-11 11:25:40 +01:00
Josh Adams d78fea87d1 docs(encodeUriSegment): fix typo 2012-11-11 11:23:46 +01:00
Tim Macfarlane 27cee7db0a docs(guide/directive): fix names in scope '='; easier to grok 2012-11-11 11:20:57 +01:00
Christian Vuerings 60acba3840 docs(ngHide): Fix typo and make it more in line with ngShow 2012-11-11 10:37:59 +01:00
Igor Minar 51bed36370 chore(docs): fix docs-scenario.html 2012-11-08 22:18:34 +01:00
Igor Minar 6d940213ac chore(docs): remove obsolete gae files 2012-11-08 22:18:34 +01:00
Miško Hevery 494b527fa7 docs(directive): fix typo 2012-11-05 19:35:31 -08:00
Sudhir Jonathan 8ce84cb2ea chore(testacular): use local testacular version
Making testacular a dependency to avoid having to install it globally.
(Causes npm issues on some machines)
2012-10-31 17:00:00 -07:00
Sudhir Jonathan d981c2a3ec fix(select): select option with a label of 0 is not shown
Bug caused by the use of the `||` operator to replace all non-truthy
values with an empty string. Changed to replace only `undefined` values.

Closes #1401
2012-10-31 15:03:48 -07:00
Igor Minar 537e20065a chore(validate-commit-msg): allow '/' in scope 2012-10-31 14:48:24 -07:00
Fred Sauer 97578b4dae docs(guide/location): fix table formatting
Fix table formatting so headings are bold, rows are separated by lines, and rows have :hover style
2012-10-31 14:48:18 -07:00
Tim Macfarlane fa12564607 docs(module): fix typo in example
fixed example app, `simpleAppModule` should have been `myAppModule`.
2012-10-31 14:22:12 -07:00
sqwishy trick 54bcb9ae25 chore(injector): fix typo in injector documentation 2012-10-31 14:19:52 -07:00
Adam Macejak ad7ce0d402 fix(scenario-runner): support data-ng and x-ng based attributes
Prefixed attributes like data-ng-model and x-ng-model were not being
found by the Selector. It was only looking at ng: and ng- prefixed
attributes.
Added a few tests as well to ensure the aforementioned prefixed
attributes are being matched properly.

Closes #1020
2012-10-31 14:10:26 -07:00
Daniel Luz 085e0ea8ef docs(contribute): fix task name for continuous testing 2012-10-31 13:13:33 -07:00
Igor Minar bb52c4e8d3 fix(docs): correctly generate filenames for plunkr/fiddle
previously examples like $http where broken because we would strip part of the
filename (http-hello.html -> http)

we really want to strip only the id suffix that we append to disambiguate
common filenames (like index.html) which appear in many examples.
2012-10-31 13:06:22 -07:00
Shyam Seshadri 295af335c1 feat(docs): add plunkr support
Add option to edit source in Angular Docs in Plunkr in addition to JsFiddle
2012-10-31 13:06:16 -07:00
Daniel Luz 2c2e18c37a fix(doc): typo on FAQ
Closes #1493
2012-10-31 10:26:00 -07:00
Igor Minar adfb75e3c6 fix($compile): don't look for class directives in empty string
if className is undefined or empty string, don't bother looking for directives in there
2012-10-29 19:39:34 -07:00
Igor Minar 9bff5c60df fix($compile): compilation should not recurse into empty nodes
if a node doesn't have children then don't try to compile these non-existent children
2012-10-29 19:39:21 -07:00
Igor Minar 3ba008d4b2 style($compile): better fn names for debugging 2012-10-29 19:38:57 -07:00
Igor Minar 4e45a2f8e2 refactor($compile): simplify nodeLinkFn 2012-10-29 19:38:29 -07:00
Igor Minar 4dbd8452eb fix($compile): prevent double attr interpolation w/ templateUrl
This fixes the issue that caused two attr interpolation observers
to be registered for the same attribute as a result of isolate
scope definition with attr (@) property for this attribute.

Duplicate observers would then fight with each other updating the
model.

The issue occured only when this directive was used in a repeater
because that's when we clone the template node which caused the
two observers to point to two different sets of $attr instances.

Closes #1166, #836
2012-10-29 19:38:03 -07:00
Braden Shepherdson 45a8db9c08 fix(currency): Handle not-quite-zero values
IEEE 754 floating point sometimes results in values that are very small,
rather than zero. One example is 1.0 + 1.07 - 2.07, which returns
4.440892098500626e-16 instead of 0.

This change tweaks the number formatting logic so that an exponential
value with a negative exponent that is larger than the precision+1
returns 0 instead. For example: with precision 2, anything with an
exponent of -4, -5 or more would become 0. 9e-3 = 0.009 = 0.01, but 9e-4
= 0.0009 = 0.001 = 0.00. This detail is unlikely to matter since this
quirk is usually only triggered with values very close to zero.

Closes #1469
2012-10-29 19:37:52 -07:00
Braden Shepherdson d930a410fb doc(faq): Add Common Pitfalls section
Describes several common pitfalls new users of Angular fall into that
I've observed in #angularjs.
2012-10-29 19:37:38 -07:00
Braden Shepherdson 66505ffc40 doc(faq): Fix minor spelling and wording errors 2012-10-29 19:37:29 -07:00
Igor Minar 045de959b9 chore(check-size.sh): fix rake target 2012-10-29 19:37:21 -07:00
Igor Minar 3ca11d5235 docs(contribute): add CLA note to code submission section 2012-10-19 09:15:34 -07:00
Igor Minar d5d8ac01e3 docs(contribute): add visible link to github project 2012-10-19 09:15:34 -07:00
Igor Minar ace81c053c chore(validate-commit-msg): allow * and - in scope string 2012-10-18 03:29:12 -07:00
Igor Minar 1e95c419b8 chore(jasmine): remove Jasmine from our repo
it's bundled with Testacular, so we don't need it here
2012-10-18 03:29:12 -07:00
Igor Minar 49ed63d26a chore(jstd): remove JsTestDriver from our repo
Testacular FTW!
2012-10-18 03:29:12 -07:00
Igor Minar 6ff2685668 docs(tutorial): replace JsTD with Testacular + drop snapshots
JsTD references have been replaced with Testacular stuff.

snapshots are PITA to maintain so I'm dropping them, everyone loves the Git
version anyway.
2012-10-18 02:34:27 -07:00
Igor Minar c4573c04aa chore(Rakefile): remove test_out dir when cleaning 2012-10-17 20:20:54 -07:00
Igor Minar d57abdb3f7 chore(Rakefile): tune JVM for closure compiler
Using the client VM and forcing 32bit mode gives us huge perf boost.

before:

reali   0m8.173s
user    0m39.984s
sys     0m1.408s

after:

real    0m3.000s
user    0m12.687s
sys     0m0.852s
2012-10-17 20:20:53 -07:00
Igor Minar 4050e89446 chore(Rakefile): paralelize closure compilation
this speeds up the build by paralelizing closure compilation (the slowest
piece of the build process)

before:

real  0m14.372s
user  0m31.649s
sys   0m1.006s

after:

real  0m8.191s
user  0m40.473s
sys   0m1.378s
2012-10-17 20:16:36 -07:00
Vojta Jina b6620c737f chore(test): add junit config for testacular 2012-10-17 20:16:36 -07:00
Igor Minar 0c8e908841 chore(Rakefile): misc_options should support + -> , conversion 2012-10-17 20:16:35 -07:00
Igor Minar 5595e196a8 chore(Rakefile): use exec for webserver
exec unlike system replaces the current process. this way when we kill
the webserver process we don't get scary looking 'rake aborted' error
2012-10-17 12:44:38 -07:00
Misko Hevery f92e4146d1 fix(doc): disable directory listing in docs.angularjs.org 2012-10-08 15:09:06 -07:00
Vojta Jina 8b7108e3c9 chore: add travis config 2012-10-05 10:20:02 -07:00
Igor Minar caf702cc88 docs(downloading): update the downloading docs 2012-10-05 03:15:11 -07:00
Vojta Jina cf2c49ed7f fix($compile): reference local in isolate scope
This was really corner case:
Watcher needs to return changed value, to notify that model might have changed and one more $digest cycle needs to be performed.

The watcher, that takes care of reference binding into an isolate scope ("="), did not return changed value, if the change was from the isolate scope to the parent.

If any other watcher returned change, it worked fine, as this change caused re-digest.

Closes #1272
2012-09-22 12:00:16 -07:00
Igor Minar ccd52abf5d docs(README): update README.md with new rake tasks 2012-09-17 14:52:06 -07:00
Igor Minar 74c574015d chore(Rakefile): fix test:jquery task 2012-09-17 14:52:06 -07:00
Igor Minar 1f1a6fb6d2 docs(contribute): update contribute docs 2012-09-17 09:46:34 -07:00
Igor Minar 8632e893b0 chore(): remove unused files 2012-09-17 09:46:34 -07:00
Igor Minar c2b6e127fa docs(contribute): update misc/contribute docs with Testacular info 2012-09-17 09:46:34 -07:00
Igor Minar 06eceeb09f chore(testing): Testacular config files + rake tasks
- adds testacular config files for jqlite, jquery, modules and e2e tests
- replaces obsolete JsTD Rake tasks with Testacular onces
- rake tasks are parameterazied so that they can be used locally as well as on CI server

usage:

rake test  # run all tests on Chrome
rake test[Safari+Chrome+Opera]  # run all tests on Safari, Chrome and Opera
rake test[Safari]  # run all tests on Safari
rake test:jqlite # run unit tests using jqlite on Chrome
rake test:jqlite[Safari,"--reporter=dots"]  # run jqlite-based unit tests on Safari with dots reporter
rake autotest:jquery  # start testacular with jquery-based config and watch fs for changes
rake test:e2e # run end to end tests
2012-09-17 09:46:13 -07:00
Miško Hevery 8133d468b9 docs(directive): remove reference to old isolation syntax 2012-09-13 11:32:13 -07:00
Misko Hevery 074a354fa9 fix($route): support inline annotation on .resolve 2012-09-11 23:16:41 -07:00
Vojta Jina e191582a02 chore(scripts): add init-repo script 2012-09-11 23:16:38 -07:00
Jay Zeng 6fbe926cda docs(ngResource): Spelling typo (agressive => aggressive) 2012-09-11 16:39:46 -07:00
Igor Minar ebbc224e09 fix($resource): fix isDefined -> angular.isDefined 2012-09-11 16:39:46 -07:00
Shyam Seshadri 2c6aa4c300 fix(*): name all anonymous watch functions in Angular
This will allow us to see function names in Batarang and debugger.

Closes #1119
2012-09-11 16:39:46 -07:00
Zhenbo Zhang f7a8f17fc7 fix(ng-repeat) to work with primitive types 2012-09-11 16:38:42 -07:00
Brian Ford 191efbb558 docs(guide): fix directive interpolation example code
Closes #1339
2012-09-11 16:19:45 -07:00
Shyam Seshadri bf873d6f02 fix(scenario): emit RunnerBegin event 2012-09-11 16:19:44 -07:00
Vojta Jina e741107c55 chore(scripts): add commit-msg hook (validation) 2012-09-11 16:19:44 -07:00
Jimmy Zhuo 82f4b99d99 fix(scenario): NPE when no angular loaded in test page 2012-09-11 16:19:44 -07:00
Daniel Luz 7210b7ae1d docs($rootScope): fix iteration limit described by $watch, it's actually 10 as of now 2012-09-11 16:19:44 -07:00
Daniel Luz afed23c001 docs($rootScope): fix typos and minor wording tweaks on $watch 2012-09-11 16:19:44 -07:00
Daniel Luz 1f69cc2989 docs($rootScope): fix quoting on expression 2012-09-11 16:19:43 -07:00
Daniel Luz 3401833c83 docs($rootScope): standardize on present, third-person actions for descriptions 2012-09-11 16:19:43 -07:00
Daniel Luz 06606e2816 docs($rootScope): backquote attribute types too on $on 2012-09-11 16:19:43 -07:00
Daniel Luz eba64e1f31 docs($cacheFactory): fix backquotes on method descriptions 2012-09-11 16:19:43 -07:00
Daniel Luz 81dd1df1b1 docs($rootScope): fix typos on $new 2012-09-11 16:19:43 -07:00
Daniel Luz dbafbb0de5 docs($rootScope): fix typo on $eval 2012-09-11 16:19:42 -07:00
Daniel Luz 1d0aa7b7c6 docs($rootScope): fix typos on $watch 2012-09-11 16:19:42 -07:00
Igor Minar afd02ca48c fix(docs): update docs top menu links 2012-09-06 15:56:11 -07:00
sgtpep 67db7616ad fix(a): prevent Opera from incorrectly navigating on link click
we handle the navigation by ourselves, so we need to prevent the default action.

Opera ignores event.preventDefault() call so we must return false.
2012-09-06 15:54:20 -07:00
Kai Groner 3d7c752e27 fix(FormController): propagate dirty state to parent forms 2012-09-06 15:54:19 -07:00
Jonathan Zacsh f02833d634 chore(docs): get correct location for jasmine-node 2012-09-06 15:54:19 -07:00
Misko Hevery 0eb373e0e6 fix($injector): more conservative annotation parsing 2012-09-06 15:49:50 -07:00
Xiangru Chen fd3071843c fix(ngSrc): don't set src if value is empty string
Current implementation of ngSrc may lead to empty src attribute when page is loading.

For example:

<img ng-src="{{image.url}}">
can be temporarily rendered as

<img src="">
before the image resource is loaded.

Some browser emits a request to the current page when seeing <img src=""> (Firefox13 and IE8 will, Chromium20 won't), which leads to performance problems.
2012-09-06 15:49:49 -07:00
Iwein Fuld a631ceb223 fix(dateFilter): make timezone optional
Makes the time zone optional in the date filter

Problem with the current R_ISO8601_STR regex was that the time was optional, but the zone was not.
This results in the filter not formatting local date times, which it could easily do.

For example:
2012-08-30 -> formatted
2012-08-30T06:06:06.123Z -> formatted
2012-08-30T06:06:06.123 -> NOT formatted

A simple change in the regex fixes this. Arguably this is closer to the ISO8601 spec which specifies
local dates being in the "current time zone" and not requiring a Z. In any case it behaves more like
a user would expect.
2012-09-06 15:49:49 -07:00
Misko Hevery a713928210 docs(concept): correct example for creating injector 2012-09-06 15:49:49 -07:00
Godmar Back 05fa20df81 docs(module): fixed module example and corrected typos 2012-09-06 15:49:49 -07:00
Benjamín Eidelman 125573602f fix($resource): allow falsy values in URL parameters
Close #1212

when a param value was 0 (or false) it was ignored and removed from url.
after this fix that only happens if the value is undefined or null.
2012-09-06 15:49:49 -07:00
Jay Zeng ed5dfbcd66 docs(module): myAppModule -> simpleAppModule 2012-09-06 15:49:49 -07:00
petrovalex d2e52b2376 fix($resource): ignore undefined parameters
- $resource should handle multiple params with same name
- ignore slashes of undefined parameters
- fix default parameters issue, mentioned in #875

Closes #875
Closes #782
2012-09-06 15:49:49 -07:00
petrovalex a56aaa9877 fix(ngClassEven/Odd): filtering/ordering and repeater
Closes #1076
2012-09-06 15:49:48 -07:00
Max Martinsson 79bb7b1f0b fix(ngClass): works with class interpolation
Closes #1016
2012-09-06 15:49:48 -07:00
Max Martinsson b936e52874 feat($resource): support custom headers per action
Closes #736
2012-09-06 15:49:48 -07:00
petrovalex 0d52ff0f10 fix($parser): string concatination with undefined model
Closes #988
2012-09-06 15:49:48 -07:00
Stein Jakob Nordbø baf52e902d fix(dateFilter): support sub-second precision on dateFilter 2012-09-06 15:49:48 -07:00
Igor Minar dffea9e2b7 docs($route): rename leftover $afterRouteChange to $routeChangeSuccess 2012-09-06 15:03:58 -07:00
Igor Minar 4a411b8f82 chore(release): prepare 1.0.3 bouncy-thunder iteration 2012-09-06 08:42:51 -07:00
Misko Hevery 278bfc4bb2 fix(docs): broken url to angular-bootstrap 2012-09-04 18:16:52 -07:00
Igor Minar 18731173f9 chore(Rakefile): add 'version' rake task to generate version.txt 2012-09-04 16:38:29 -07:00
Igor Minar d43fb404d7 chore(docs): bump up the stable version 2012-09-04 16:30:33 -07:00
Igor Minar da984ad187 chore(release): cut the 1.0.2 debilitating-awesomeness release 2012-09-04 11:08:40 -07:00
Igor Minar 4015357ce5 chore(docs): don't rewrite colons in doc filenames 2012-09-04 11:08:40 -07:00
Igor Minar dc3d11ad19 chore(Rakefile): zip only the build dir 2012-09-04 11:08:40 -07:00
Igor Minar 0e1545eb04 revert: fix(ng-repeat) to work with primitive types
this commit was accidentaly merged. it needs more work and we don't
have CLA signature

This reverts commit 98d489712e.
2012-08-31 13:44:36 -07:00
Igor Minar ec7cabf5c9 docs(changelog): release notes for 1.0.2 and 1.1.0 releases 2012-08-31 13:23:23 -07:00
Jonathan Zacsh 3051beba2f fix(docs): Making sure gen_docs.sh looks for a globally installed copy of jasmine-node as well as local. 2012-08-30 22:38:54 -07:00
Fernando Correia 92304323b1 docs(tutorial): correct typos and clarify a few sections 2012-08-30 22:38:54 -07:00
Brice Burgess c28123a872 fix(docs): indicate support for passing a string as the controller property on $routeProvider's route object 2012-08-30 22:38:53 -07:00
brettcannon d798423813 doc(misc) Mention how attribute names map to directive names. 2012-08-30 22:38:52 -07:00
Sahat Yalkabov 2583e77cc7 doc(module) changed simpleApp to myApp in the Module page guide for consistency 2012-08-30 21:34:43 -07:00
Steve Nicolai f66836fee4 doc(devguide) - Fix typos and small grammatical errors in the developer guide. 2012-08-30 21:34:42 -07:00
Uri Goldshtein 0ccc445d53 Loading from Google CDN
As you guys had mansion, we can and need to do it through Google CDN for better performance,
so i've updated it accordingly
2012-08-30 21:34:42 -07:00
Tyson Benson b7d5fa1cbe docs(typos): fix typos in dev guide 2012-08-30 21:34:42 -07:00
German Galvis 8bb3942453 fix(scenario): Adding meta tag to avoid cache issues 2012-08-30 21:34:42 -07:00
phil 51a79cebcb docs(api): fix typo on home page
Refference -> Reference
2012-08-30 21:34:41 -07:00
csugden 36bcf64008 Update docs/content/guide/overview.ngdoc
Corrects video information
2012-08-30 21:34:41 -07:00
Jamie Krug 5c6630605b fix(docs): Fix typos and improve grammar. 2012-08-30 21:34:41 -07:00
Jamie Krug 125827406c fix(docs): Fix bad links. 2012-08-30 21:34:41 -07:00
Colin Frei 62c21422a6 docs(module) fix typo 2012-08-30 21:34:41 -07:00
Zhenbo Zhang 98d489712e fix(ng-repeat) to work with primitive types 2012-08-30 21:34:41 -07:00
Igor Minar 2cab2d8ef1 test(locationSpec): fix broken tests after vojta's commit 2012-08-30 16:54:07 -07:00
Vojta Jina 8fa2bb72bc fix(mocks): free up memory after every spec 2012-08-30 16:53:52 -07:00
Igor Minar d151f94937 chore(docs): ask GAE to serve docs-keywords.js 2012-08-30 15:59:29 -07:00
Igor Minar 5b74b7185b test(bootstrap): test exception siling during bootstrap
Closes #1018
2012-08-30 15:18:11 -07:00
Igor Minar 4f0be2ae4e test(ngApp): add missing test for [ng-app] bootstrap 2012-08-30 15:18:02 -07:00
Igor Minar bb9badeb2a fix(jqLite): better support for xhtml
it turns out that some stuff doesn't work in xhtml as it does in html.

for example &nbsp; can't be innerHTML-ed and auto-closing of elements
doesn't work.

the reporter of the referenced issue claimed that innerHTML vs text on
script made a difference but that doesn't appear to be true in my testing.

I'm not including test for this because testacular doesn't currently
run tests in xhtml yet.

Closes #1301
2012-08-30 10:52:36 -07:00
Igor Minar c287c8361d chore(docs): correctly link docs images 2012-08-30 08:59:17 -07:00
Igor Minar ade7127c79 chore(Rakefile): fix the default task 2012-08-30 08:58:51 -07:00
Igor Minar d341483f1f chore(Rakefile): remove bogus symlink from build 2012-08-30 08:58:39 -07:00
Igor Minar b36acbc857 chore(docs): use symlinks to build docs
so that we can just edit source files without rebuilding docs.

this works for all docs files, except for those that are generated
or rewritten during build.
2012-08-28 16:08:03 -07:00
Igor Minar a4fea38b94 chore(Rakefile): various build script changes
- restructure rake tasks

  this splits up the concatination and minification into two
  tasks so that we can just build angular.js quickly without wasting
  time with minification which is often not needed when just debugging
  some issue on 3rd party site.

- use symlinks when creating final zip file

- switch from btar to zip

- get rid of version numbers from filenames

- rewrite version numbers in all index files

Closes #1226
2012-08-28 16:07:47 -07:00
Misko Hevery 300c5c0c99 doc($log): correct non-working example 2012-08-27 21:20:51 -07:00
Misko Hevery 152537c4e9 doc(guide): add concepts 2012-08-27 21:20:51 -07:00
Misko Hevery 8b46bf6bc9 fix(ngdoc): failing test 2012-08-27 21:20:50 -07:00
Colin Frei aef861eb41 doc(directive) correct typos 2012-08-27 21:20:50 -07:00
Misko Hevery f61d36861d fix(docs) typo 2012-08-27 21:20:50 -07:00
Misko Hevery 2af0348cea fix(ng-list): remove data bound flicker 2012-08-27 21:20:50 -07:00
Misko Hevery 78c5743494 doc(misc) updated getting started to reflect the new homepage 2012-08-27 21:20:49 -07:00
Misko Hevery 2cb9fbd043 doc(guide) simplify the guide home page 2012-08-27 21:20:49 -07:00
Igor Minar e9dad5dbf4 chore(Rakefile): rewrite version numbers in all index files 2012-08-27 12:25:40 -07:00
Igor Minar 54895fc2a1 chore(docs): support _escaped_fragment_ hack for crawler 2012-08-25 02:31:20 -07:00
Igor Minar 60a12b4161 chore(docs): use GAE and Google CDN for docs
Short summary: if you use local node server everything should work as before,
if you use GAE, everything should work now as well, but we pull assets from CDN.

- GAE doesn't support ':' in filenames, so I had to replace it with '_'
  but only in the filename, all servers were reconfigured to rewrite the
  urls from : to _ when doing file lookup
- We now pull angular assets from google CDN when deployed on GAE (locally
  or in production). When running on a non GAE server we pull assets from
  ../ directory as before
- Since only certain versions of Angular are available on CDN and we want
  to be able to autodeploy docs, I had to pin down the Angular files
  to a "stable" version when running on GAE
2012-08-24 15:00:36 -07:00
Igor Minar cd7e58ba41 docs(a): expose hidden docs
It seems that docs for these directive were previously hidden by accident
2012-08-24 14:59:52 -07:00
johnlindquist 9391475dc3 docs(ngRoute): fix typo
aftre -> after
2012-08-24 14:59:43 -07:00
phil 7840803add docs(tutorial): fix typo in step_00
Just removed an extra comma. No big deal.
2012-08-24 14:59:21 -07:00
Igor Minar 7d77de2834 fix($compile): denormalize directive templates
Since developers are allowed to customize start/end interpolation
strings, but third-party directive creators don't know about these
customizations, we should standardize on {{ }} in templates of
reusable (third-party) directives. During the compilation, these
templates are then denormalized to use whatever the custom
start/end symbol is, effectively translating the template into the
syntax of the runtime environment.

This addresses an issue raised at http://goo.gl/e8VPV

Existing code should not be affected by this change since project
that do use custom interpolation markers are not expected to use
{{ }} in existing directive templates.
2012-08-13 14:35:32 -07:00
Igor Minar ab044cada6 refactor($compile): code cleanup 2012-08-13 12:36:42 -07:00
Brian Ford d010e0cc7d fix(ngPluralize): fixes ng-pluralize when using non-standard start/end symbols
Closes #1134
2012-08-13 12:36:33 -07:00
Igor Minar 40f728b1aa style(ngPluralizeSpec): fix indentation 2012-08-13 12:36:22 -07:00
Igor Minar 23abb26405 feat($interpolate): expose start/end symbols in run phase
previously the startSymbol() and endSymbol() getters were exposed only via provider
in the config phase
2012-08-13 12:36:14 -07:00
Igor Minar fd55bc8e1d docs($interpolateProvider): fixing docs 2012-08-13 09:51:57 -07:00
Igor Minar 541aaa4e08 fix($interpolate): $interpolateProvider.endSymbol() returns startSymbol
I also added missing tests.
2012-08-13 09:51:45 -07:00
Igor Minar f22c422547 docs($interpolate): fix typo in description 2012-08-13 09:51:35 -07:00
Vojta Jina 0e461f0c07 docs($compileProvider): remove duplicate of .directive() 2012-08-12 11:04:32 -07:00
Vojta Jina 5074448443 docs: fix broken links to $compileProvider.directive() 2012-08-12 11:04:20 -07:00
Brian Ford 8d66af11e6 fix(docs): fixed documentation for using linky 2012-08-10 16:38:01 -07:00
Brian Ford 169948bb47 chore(ngDoc): add support for custom @usage metadata 2012-08-10 16:37:54 -07:00
Brian Ford 58d9469574 fix(docs): added note about using JSON3 as a polyfill for IE7 2012-08-10 16:37:42 -07:00
Brian Ford 8d858a2360 fix(docs): added note about needing JSON shim for IE7 and earlier 2012-08-10 16:36:56 -07:00
Igor Minar 5540748890 fix(option): support option elements in datalist
previously we expected to find option elements only within select element and if
that was not the case we throw an error. This made it impossible to include datalist
element with nested option elements in the template.

Closes #1165
2012-08-10 16:14:49 -07:00
unirgy f8a52be817 docs($rootScope): fix $on listener signature doc
Added args in $on() listener syntax declaration
2012-08-10 14:52:57 -07:00
Igor Minar 3b5f1105f6 test(jqLite): add missing test for $destroy event 2012-08-10 14:21:11 -07:00
Igor Minar 663ccc5449 fix(form): prevent page reload when form destroyed
this fix ensures that we prevent the default action on form submission
(full page reload) even in cases when the form is being destroyed as
a result of the submit event handler (e.g. when route change is
triggered).

The fix is more complicated than I'd like it to be mainly because
we need to ensure that we don't create circular references between
js closures and dom elements via DOM event handlers that would then
result in a memory leak.

Also the differences between IE8, IE9 and normal browsers make testing
this ugly.

Closes #1238
2012-08-10 14:21:02 -07:00
Igor Minar 263f47819f test(form): fix broken preventDefault test
the original test relied on incorrect assumptions about how jasmine async
tests work (when setTimeout is triggered) and how browser reloads a page
(the sequence of events) and thus the test passes even when the default
is not prevented.

this change fixes the test by registering an extra submit event handler
that checks if the default was prevented.

if the default was not prevented, the test will fail and the page will
be reloaded causing the test runner to panic.
2012-08-10 14:20:52 -07:00
Igor Minar 6b75475ce3 refactor(formSpec): group preventDefault specs into a describe 2012-08-10 14:20:28 -07:00
Igor Minar 07c354a8c0 docs(faq): update faq docs 2012-08-10 14:20:13 -07:00
Igor Minar 1391579599 docs(styles): fix the cog icon alignment 2012-08-10 14:19:57 -07:00
Vojta Jina 5d2bd1d84c chore(nodeserver): add font mime type 2012-08-10 14:19:47 -07:00
Vojta Jina bf77e212af docs(guide): hide scenario for directive example
scenario test for this example would be tricky, we need to teach
the runner how to inject mocks first.
2012-08-10 14:19:37 -07:00
Vojta Jina eef2f9c31e docs(design): fix icons
Copy fontawesome during build
2012-08-10 14:18:45 -07:00
brettcannon 438627c2c3 fix(docs): "in depth" -> "in-depth" 2012-08-10 14:18:06 -07:00
Igor Minar d3952b79c7 docs(readme): improve blurb about AngularJS in README.md 2012-07-19 21:48:45 -07:00
brettcannon 5ef9ed87d8 fix(docs): Capitalize Angular. 2012-07-19 15:23:21 -07:00
brettcannon 8c81a0f372 fix(docs): Fix a spelling mistake by replacing the noun with "it" 2012-07-19 15:04:29 -07:00
brettcannon bde931afd5 fix(docs): "were" -> "where" 2012-07-19 11:28:19 -07:00
brettcannon 6553fe68d1 fix(docs): Capitalize "URL". 2012-07-19 11:05:38 -07:00
Chris Dawson 13b5fd1b9d fix(docs): Fixed defer to timeout change in timer directive example 2012-07-19 10:04:22 -07:00
Chris Dawson 17209d5b4a fix(docs): Spelling errors 2012-07-19 10:01:50 -07:00
brettcannon 6f9a5721bc fic(docs): Consistently use __bold__ for things that must be done when moving the ng-controller declaration. 2012-07-19 09:57:58 -07:00
brettcannon 31c825607d fix(docs): Tweak some grammar and add some links relating to DI. 2012-07-19 09:54:53 -07:00
brettcannon ab6937e251 fix(docs): Capitalize "APIs" 2012-07-19 09:49:44 -07:00
brettcannon fbfda241f6 fix(docs): Capitalize "Angular". 2012-07-19 09:35:43 -07:00
brettcannon 206371b737 fix(docs): Capitalize Angular. 2012-07-19 09:26:34 -07:00
brettcannon b6b92bd866 fix(docs): Add a missing "the". 2012-07-19 09:09:52 -07:00
brettcannon 79f2d843a8 fix(docs): ngRepeater isn't a thing, ngRepeat is 2012-07-19 09:04:59 -07:00
brettcannon 64a9cd8f4f fix(docs): Remove a redundant "in". 2012-07-19 09:02:04 -07:00
brettcannon 7f6e1326f3 fix(docs): Grammatical fix 2012-07-18 15:48:08 -07:00
brettcannon 1fd2b3d402 fix(docs): Fixed some awkward wording 2012-07-18 15:42:29 -07:00
brettcannon d56d69cc83 fix(docs): Tweak formatting and wording of a list 2012-07-18 15:20:38 -07:00
brettcannon 01e726b2fa fix(docs): Don't want the present participle of "is" 2012-07-18 15:15:09 -07:00
brettcannon 1613621645 fix(docs): Adjectve accidentally made into an adverb 2012-07-18 12:16:14 -07:00
brettcannon 92a3d28218 fix(docs): Minor grammatical fix 2012-07-18 11:52:57 -07:00
Rishabh Rao 4c58501956 fix(docs): Fixed typo: changed ngRepeate to ngRepeat. 2012-07-16 12:33:19 -07:00
Jamie Krug c076fe08cf fix(docs): Fix spelling, punctuation and grammatical errors on dev guide bootstrap page. 2012-07-16 12:10:43 -07:00
Jamie Krug 2473412ba5 fix(docs): Fix spelling, punctuation and grammatical errors on dev guide compiler page. 2012-07-16 12:10:42 -07:00
Jamie Krug 1f2d50000e fix(docs): Fix spelling, punctuation and grammatical errors on dev guide overview page. 2012-07-16 12:10:33 -07:00
Kevin Old 5026315d6f fix(docs): correct typo 2012-07-16 11:40:21 -07:00
Igor Minar a8b04004e3 docs(readme): add blurb about AngularJS to README.md 2012-07-02 08:21:19 -07:00
Igor Minar f0a090ddf2 fix(docs): correctly generate sitemap 2012-07-02 08:21:19 -07:00
Igor Minar 6d9313a68d fix(docs): fix broken ng-docs specs 2012-07-02 08:21:19 -07:00
Vojta Jina 212f685e06 chore(changelog): fix typos in rc11 changelog 2012-06-25 20:36:41 -07:00
Igor Minar 35706ba482 chore(release): starting the 1.0.2 debilitating-awesomeness iteration 2012-06-25 12:52:32 -07:00
Igor Minar 9bef436b22 chore(release): cutting the 1.0.1 thorium-shielding release 2012-06-25 09:30:57 -07:00
Igor Minar 3f14a45aa5 docs(changelog): release notes for 1.0.1 thorium-shielding 2012-06-25 09:30:57 -07:00
Misko Hevery ffb270130a fix(browser): prevent ie from getting into redirect loop
Closes #1075
Closes #1079
Closes #1085
2012-06-22 10:21:31 -07:00
Igor Minar 0d57f1373f chore(release): starting the 1.0.1 iteration 2012-06-21 13:59:53 -07:00
Igor Minar 869143ec7d chore(logos): fix shield logo exports
the previous version is clipped at the top
2012-06-21 13:58:24 -07:00
Igor Minar 1e6d4d5f54 fix(logo): center A in the shield 2012-06-21 13:58:24 -07:00
Vojta Jina 3da4194f98 fix($location): url rewriting if element was removed
When user clicks a link, $location needs to intercept this event.  The <a> doesn't have to be target element of the DOM event, so it needs to traverse the DOM, to find first <a> parent.

If the target element was removed from DOM, during the same event, it would throw an exception. This fixes the issue.

Closes #1058
2012-06-20 12:18:48 -07:00
Misko Hevery ad5d2f2991 fix(doc) firefox icon rendering 2012-06-15 10:40:25 -07:00
Igor Minar 519bef4f3d chore(release): cutting the 1.0 temporal-domination release 2012-06-14 10:50:22 -07:00
Igor Minar 6dfe5be155 docs(changelog): release notes for 1.0 temporal-domination release 2012-06-14 10:50:22 -07:00
Misko Hevery 6593a3e082 fix($location): fix URL interception in hash-bang mode
Closes #1051
2012-06-14 10:48:56 -07:00
Misko Hevery 0f44964e5e fix($location): correctly parse link urls in hashbang mode with prefix
This is a second fix for a regression that was introduced by 92a2e180.
The fix addresses scenarios when the $location service is configured with
a hash prefix.

Closes #1037
2012-06-13 10:49:05 -07:00
Igor Minar f6b09b9139 chore(release): starting the 1.0 temporal-domination iteration 2012-06-13 10:46:22 -07:00
Igor Minar 7fa1995e08 chore(release): cutting the 1.0.0rc12 regression-extermination release 2012-06-12 01:46:02 -07:00
Igor Minar da94b03af7 docs(changelog): release notes for 1.0.0rc12 regression-extermination 2012-06-12 01:45:26 -07:00
Igor Minar f158d81d21 docs($browser): hide $browser docs - it's a private service 2012-06-12 01:14:45 -07:00
Igor Minar 9af7a9198e fix($defer): remove deprecated $defer service 2012-06-12 01:09:07 -07:00
Misko Hevery 74fa65ecb7 fix($location): correctly parse link urls in hashbang mode
This is a fix for a regression that was introduced by 92a2e180

Closes #1037
2012-06-12 00:27:25 -07:00
Igor Minar ee6014a3aa fix($location): throw Errors not Strings 2012-06-12 00:27:24 -07:00
Igor Minar d9ff5fd432 fix(docs): migrate from $defer to $timeout 2012-06-12 00:11:04 -07:00
Igor Minar f16150d5f1 docs(*): simplify doc urls
we now have two types of namespaces:

- true namespace: angular.* - used for all global apis
- virtual namespace: ng.*, ngMock.*, ... - used for all DI modules

the virual namespaces have services under the second namespace level (e.g. ng.)
and filters and directives prefixed with filter: and directive: respectively
(e.g. ng.filter:orderBy, ng.directive:ngRepeat)

this simplifies urls and makes them a lot shorter while still avoiding name collisions
2012-06-12 00:10:18 -07:00
Igor Minar fc0b2b5715 chore(logos): adding AngularJS and shield logos 2012-06-11 14:13:18 -07:00
Igor Minar f3f090da8a chore(release): start 1.0.0rc12 regression-exterminator release
quick release to fix $location regression
2012-06-11 14:10:02 -07:00
Igor Minar 068f2f9d43 chore(release): cutting the 1.0.0rc promise-resolution release 2012-06-11 00:03:01 -07:00
Igor Minar 2d48733723 docs(changelog): release notes for 1.0.0rc11 promise-resolution 2012-06-11 00:03:01 -07:00
Igor Minar d37d595b67 test($location): fix tests borked during event renaming 2012-06-10 17:42:44 -07:00
Igor Minar 5d70e4a89c docs(*): fix various outdated docs and examples
Closes #1030
2012-06-10 09:01:42 -07:00
Igor Minar b5bba65a93 docs($location): clarify the two-way data-binding note
Closes #1030
2012-06-09 06:57:55 -07:00
Max Martinsson fb99b539b4 fix($compile): correctly merge class attr for replace directives
Merging of interpolated class attribute from directive template with replace:true works

Closes #1006
2012-06-08 16:07:15 -07:00
Vojta Jina 10f80d7d29 fix($http): add utf-8 to default Content-Type header (post/put)
This fixes special characters issue with MongoLab.

https://groups.google.com/d/topic/angular/1T6h7bfZ7Rs/discussion
2012-06-08 16:07:15 -07:00
Misko Hevery c3a41ff9fe feat($compile): simplify isolate scope bindings
Changed the isolate scope binding options to:
  - @attr - attribute binding (including interpolation)
  - =model - by-directional model binding
  - &expr - expression execution binding

This change simplifies the terminology as well as
number of choices available to the developer. It
also supports local name aliasing from the parent.

BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.

To migrate the code follow the example below:

Before:

scope: {
  myAttr: 'attribute',
  myBind: 'bind',
  myExpression: 'expression',
  myEval: 'evaluate',
  myAccessor: 'accessor'
}

After:

scope: {
  myAttr: '@',
  myBind: '@',
  myExpression: '&',
  // myEval - usually not useful, but in cases where the expression is assignable, you can use '='
  myAccessor: '=' // in directive's template change myAccessor() to myAccessor
}

The removed `inject` wasn't generaly useful for directives so there should be no code using it.
2012-06-08 15:50:13 -07:00
Igor Minar 5c95b8cccc fix(startingTag): make tag name always lowercase
some browsers (IE) always provide the nodeName as upper-case
2012-06-08 15:27:04 -07:00
Misko Hevery 9be82d942f refactor($compile): always call attr.$observe
attr.$observe used to call function only if there was interpolation
on that attribute. We now call the observation function all the time
but we only save the reference to it if interpolation is present.
2012-06-08 15:27:03 -07:00
Misko Hevery 2491319575 chore($compile): clean up compiler tests 2012-06-08 15:27:02 -07:00
Misko Hevery bcc3a021eb chore(jqLite): performance reordering 2012-06-08 15:27:02 -07:00
unknown a57141fd1d docs(guide): correct couple of typos 2012-06-04 18:46:09 -07:00
Ali Mills 1904596e0c fix($timeout): allow calling $timeout.cancel() with undefined
This is how it worked in rc9, before refactoring $defer into $timeout.
2012-06-04 17:43:14 -07:00
Igor Minar 22143381d8 chore(release): starting 1.0.0rc11 promise-resolution iteration 2012-06-04 10:03:59 -07:00
Misko Hevery ddefb42445 doc(app): switch to use $last on ng-repeat 2012-06-02 16:02:09 -07:00
Misko Hevery 676d6e0040 doc(app): remove un-needed file 2012-06-02 16:02:09 -07:00
Misko Hevery 8024a5742c doc(NgModelController) add example and $render documentation
Closes#930
2012-06-02 16:02:09 -07:00
Misko Hevery 073e76f835 doc(guide): corrected examples 2012-06-02 16:02:09 -07:00
Misko Hevery 7019f142ab merge cleanup 2012-06-02 16:02:09 -07:00
Misko Hevery 0532aabcf9 doc(guide): clean up broken links 2012-06-02 16:02:08 -07:00
Misko Hevery f0be543614 doc(ngdoc): clean up doc generation and add missing documentation links 2012-06-02 16:02:08 -07:00
Misko Hevery a3a37c2063 doc(compiler): rewrite 2012-06-02 16:02:08 -07:00
Misko Hevery 0f5259c5a2 docs(introduction): rename 2012-06-02 16:02:08 -07:00
Misko Hevery 321a4a6b1f doc(i18n): rename 2012-06-02 16:02:08 -07:00
Misko Hevery 41d26db32c docs(expression): rewrite 2012-06-02 16:02:08 -07:00
Misko Hevery dd38ce6585 docs(scope): rewrite 2012-06-02 16:02:07 -07:00
Misko Hevery 2e90cdc3d4 docs(dependency injecton): rewrite 2012-06-02 16:02:05 -07:00
Misko Hevery 581f93ae56 docs(ngdocs): cleaned up directive titles 2012-06-02 16:02:05 -07:00
Misko Hevery 6933fb7924 docs(bootstrap): rewritten bootstrap guide 2012-06-02 16:02:05 -07:00
Misko Hevery f5afcca99d docs(overview): updated overview guide 2012-06-02 16:02:04 -07:00
Misko Hevery 2356c21650 doc(ngdoc): proper label for source and demo section 2012-06-02 16:02:04 -07:00
Misko Hevery 275e5335dc fix(docs): include short words in keywords
Short words like $q are now searchable.

Closes #967
2012-06-02 15:44:58 -07:00
Misko Hevery 92a2e18076 feat($location): add $locatonChange[begin|completed] event
This allows location change cancelation
2012-06-02 15:44:58 -07:00
Misko Hevery 8aa18f0ad0 chore($location) switch to use $rootElement 2012-06-02 14:51:03 -07:00
Misko Hevery 85632cb44c feat($rootElement): added application root element
Publish the application root element as $rootElement
so that it can be injected to other services.
2012-06-02 14:50:58 -07:00
Misko Hevery 0a6e464a93 feat($route): rename template -> tempalteUrl and add support for inline templates
BREAKING CHANGE: template in $route definition is now templateUrl
To migrate just rename `template` to `templateUrl`.
2012-06-01 17:01:10 -07:00
Misko Hevery 7c24282188 chore($route): rename events
BREAKING CHANGE

rename $beforeRouteChange to $routeChangeStart
rename $afterRouteChange to $routeChangeSuccess
2012-06-01 16:57:49 -07:00
Misko Hevery 885fb0dd07 feat($route): resolve local route promises
Resolve all promises on route before we fire $afterRouteChange which then renders the ngView.
2012-06-01 16:56:31 -07:00
Misko Hevery 4361efb03b feat($injector): provide API for retrieving function annotations 2012-06-01 10:57:51 -07:00
Misko Hevery 416a783040 fix(jqLite): don't eat event exceptions
JQuery does not catch exceptions either, and just
lets them pass. This allows the exception to be
shown in console.
2012-05-24 13:48:44 -07:00
Misko Hevery bbaf9a2870 fix(docs): accept return in addition to returns
documentation used @return but parser expected
@returns, which made the generated documentation
incomplete.
2012-05-24 13:48:42 -07:00
Misko Hevery 7e70463da1 chore(docs): remove generated file 2012-05-24 13:48:42 -07:00
Misko Hevery 4235ee9ad6 chore(docs): remove unused doc_widget.js file 2012-05-24 13:48:40 -07:00
Misko Hevery 3fdb29242b chore(docs): correct spacings 2012-05-24 13:48:38 -07:00
Misko Hevery b5fb18ae35 fix(favicon): update to aliased icon 2012-05-24 13:48:31 -07:00
Igor Minar 5fdf42ce39 chore(release): cut the 1.0.0rc10 tesseract-giftwrapping release 2012-05-23 21:05:21 -07:00
Igor Minar bf6a0b7289 docs(changelog): release notes for 1.0.0rc10 tesseract-giftwrapping 2012-05-23 16:37:37 -07:00
Misko Hevery 989446ecee fix($rootScope): TTL exception does not clear $$phase
When $digest() throws infinite digest exception it
does not properly clear the $phase leaving the scope
in an inconsistent state.

Closes #979
2012-05-23 16:01:20 -07:00
Igor Minar 5214c1d0cb chore(package.json): add simple package.json with npm dependencies 2012-05-23 15:00:56 -07:00
Igor Minar 4511d39cc7 feat($timeout): add $timeout service that supersedes $defer
$timeout has a better name ($defer got often confused with something related to $q) and
is actually promise based with cancelation support.

With this commit the $defer service is deprecated and will be removed before 1.0.

Closes #704, #532
2012-05-23 15:00:56 -07:00
Daniel Gomes 15b8f205bb docs($filter): minor corrections 2012-05-22 14:27:26 -07:00
Max 1d388676e3 fix(ngRepeat): expose $first, $middle and $last instead of $position
$position marker doesn't work well in cases when we have just one item
in the list because then the item is both the first and last. To solve
this properly we need to expose individual $first and $middle and $last
flags.

BREAKING CHANGE: $position is not exposed in repeater scopes any more

To update, search for $position and replace it with one of $first,
$middle or $last.

Closes #912
2012-05-22 14:18:15 -07:00
Vojta Jina 84542d2431 feat(scope): add event.preventDefault() and event.defaultPrevented 2012-05-17 15:47:53 -07:00
Vojta Jina 91db99208e refactor(scope.$emit): rename event.cancel() to event.stopPropagation()
Breaks event.cancel() is event.stopPropagation()
2012-05-17 15:47:52 -07:00
Misko Hevery acf095d178 fix(jqLite): have same expando format as jQuery 2012-05-17 10:36:45 -07:00
Igor Minar 301d8f233b chore(release): start 1.0.0rc10 tesseract-giftwrapping iteration 2012-05-15 00:09:08 -07:00
Igor Minar d70223e53e chore(release): cutting 1.0.0rc9 eggplant-teleportation 2012-05-14 22:13:15 -07:00
Igor Minar 8ad02bb5a8 docs(changelog): release notes for 1.0.0rc9 eggplant-teleportation 2012-05-14 22:00:18 -07:00
Misko Hevery ec1c5dfaee fix(jqLite): .data()/.bind() memory leak
Since angular attaches scope/injector/controller
into DOM it should clean up after itself. No need
to complain about memory leaks, since they can
only happened on detached DOM. Detached DOM would
only be in tests, since in production the DOM
would be attached to render tree and removal
would automatically clear memory.
2012-05-14 21:56:22 -07:00
Misko Hevery 24e7da4f19 fix(angular-mocks): memory leak in jasmine's DI utils
When using inject/module helper methods in tests, these methods would
leave the injector laying around after the test. Since injector is
the application it can grow very large.
2012-05-14 21:56:22 -07:00
Vojta Jina 7b739c9702 fix($sniffer): report history false on Android < 4
Android has history.pushState, but it does not update the location correctly:
http://code.google.com/p/android/issues/detail?id=17471

Closes #904
2012-05-14 15:12:51 -07:00
Igor Minar c1533ef576 fix($location): support urls with any protocol
The url used for location parsing was quite strict and did not support
custom url schemes like "chrome-extension://". With this change the only
requirement for scheme is that it doesn't contain ":" character.
2012-05-14 14:45:56 -07:00
Igor Minar 679cb8a74a fix($browser/$location): single quote in url causes infinite digest in FF
The real issue is in FF, see https://bugzilla.mozilla.org/show_bug.cgi?id=407172.

FF overly encodes stuff which breaks our expectations and then we fail .url() != currentUrl.absUrl()
comparison unexpectidly, which leads to infinite digest.

The workaround is to correct for this inconsistency in $browser and decode any single quotes in urls.

Closes #920
2012-05-13 21:53:19 -07:00
Igor Minar 4e65635f85 doc($rootScope): fix $digest example 2012-05-08 17:00:25 -07:00
Misko Hevery aa02534865 bug(ie8 docs): docs now work on ie8 2012-05-07 15:43:09 -07:00
Misko Hevery b99f65f64d bug(html5 navigation): broken in Opera
http://my.opera.com/community/forums/topic.dml?id=1185462

Closes# 938
2012-05-07 15:43:09 -07:00
Igor Minar f76474823a chore(release): starting 1.0.0rc9 eggplant-teleportation interation 2012-05-07 00:11:50 -07:00
Igor Minar 8ba1fd87e1 chore(release): cutting the 1.0.0rc8 blooming-touch release 2012-05-07 00:09:20 -07:00
Igor Minar 4d2dd46483 docs(changelog): release notes for 1.0.0rc8 blooming-touch 2012-05-07 00:08:43 -07:00
Igor Minar b24cc63bcb fix(ngSrc,ngHref): binding should set element prop as well as attr
IE9 ignores setAttribute('src', val) calls on img if "ng:src" attribute
is present. It only fetches the image if element property is updated as well.

Closes #935
2012-05-06 23:01:33 -07:00
Igor Minar 49dfdf8f02 fix(ngModel): use keydown/change events on IE9 instead of input
On IE9 the input event is not fired when backspace or delete key are pressed or when
cut is performed. This makes listening on the input event unreliable and therefore
it's better for us to just use keydown/change events instead.

Closes #879
2012-05-06 23:01:33 -07:00
Vojta Jina 5bcb749abb fix(scenario): make browser().location() working if ng-app on other than <html> 2012-05-05 03:30:28 +02:00
Vojta Jina 499a76a08c fix($parse): support methods on falsy primitive types
e.g. zero, false, empty string

- fix tests to be executed with csp true
- fix cps (when more than 5 parts)
2012-05-05 03:30:19 +02:00
Misko Hevery 8e2675029f chore(docs): re-skin main documentation 2012-05-04 16:12:17 -07:00
Misko Hevery d0159454df bug($cookie): set on app base path rather the current path. 2012-05-04 15:50:39 -07:00
Misko Hevery 7f0eb15161 fix($compile): have $observe return registration function 2012-05-04 15:50:39 -07:00
Misko Hevery c4fa487250 feat(bootstrap): support code prettify and dropdown from bootstrap 2012-05-04 15:50:37 -07:00
Misko Hevery cef3535c16 chore(controller): allow setting map of controllers 2012-05-04 15:50:37 -07:00
Misko Hevery fbb499e0a8 chore(module): improved module prefix/suffix code 2012-05-04 15:50:37 -07:00
Misko Hevery e40f8d829f chore(debug): rewrite angular-bootstrap.js to use $script 2012-05-04 15:50:37 -07:00
Igor Minar 9c0418cf1a fix($compile): ignore ws when checking if template has single root
Also add the same error checking for sync templates.

Closes #910
2012-05-04 13:01:55 -07:00
Igor Minar 1564b82b49 style($compile): rename orig*Node to beforeTemplate*Node 2012-05-03 23:40:43 -07:00
Igor Minar b431ee3850 fix($compile): fix replaceWith
the old implementation didn't reattach jquery/jqlite data which caused
things like  to be lost

I tried various implementations but it appears that by reattaching the data
to the new node by copying the expando property is the most reliable of all.
2012-05-03 23:40:43 -07:00
Igor Minar a44d3dcd6a chore(testabilityPatch): print number of leaked references if any 2012-05-03 23:31:28 -07:00
Igor Minar ee579a071a feat(jqLite): support data() getter and data(obj) setter
... just like jquery does
2012-05-03 23:31:28 -07:00
Igor Minar 5df7e6fae5 style(jqLite): clean up the code 2012-05-03 23:31:28 -07:00
Igor Minar fff31d8d61 style($compile): clean up the code and normalize fn names 2012-05-03 23:31:28 -07:00
Igor Minar 9cba23a588 chore(trace): add helper method trace
use it as trace('label') to dump the stack during debugging
2012-05-03 10:07:30 -07:00
Igor Minar 705f4bbf11 fix($compile): attach scope to the directive element when templateUrl and replace=true
We forgot to reattach the scope to the replacement element. This affected only
directives that had templateUrl and replace:true properties.

Reported on the mailing list:
https://groups.google.com/forum/?fromgroups#!topic/angular/zwjLr1msS2Y
http://jsfiddle.net/lukebayes/g9Sh9/
2012-05-03 00:15:26 -07:00
Igor Minar bd530e2257 chore($compile): remove obsolete <<CONTENT>> transclusion
This stuff was never documented and is an accidental leftover from the time
when the compiler was rewritten.

If any code depends on this, it should be rewritten to use ngTransclude directive
intead.
2012-05-03 00:15:26 -07:00
Igor Minar 843f762c57 fix($compile): prevent duplicate directive controller instantiation
Closes #876
2012-05-03 00:15:26 -07:00
Igor Minar beea3a4bed style($compile): rename compiler.js to compile.js 2012-05-02 16:37:48 -07:00
Igor Minar 3bd3cc571d fix(select): don't interfere with selection if not databound
Closes #926
2012-05-02 14:24:43 -07:00
Igor Minar c7f1101520 chore(release): starting the 1.0.0rc8 blooming-touch iteration 2012-05-02 14:21:30 -07:00
Igor Minar 76afa406b1 chore(release): cut 1.0.0rc7 rc-generation release 2012-04-30 16:32:45 -07:00
Igor Minar f3c77858be docs(changelog): release notes for 1.0.0rc7 rc-generation 2012-04-30 15:53:05 -07:00
Igor Minar 96758c1c52 docs(ngCsp): make the CSP docs publicly visible 2012-04-30 15:37:12 -07:00
Igor Minar 006fb4fbeb docs(ngSanitize): fix directive links 2012-04-30 01:09:55 -07:00
Igor Minar 075c089b5c docs(tutorial): update all the remaining steps
I made some diagrams and portions of the text that are stil stale
invisible. We'll fix these in the next relese.
2012-04-30 01:08:15 -07:00
Igor Minar 2b87c814ab feat($parse): CSP compatibility
CSP (content security policy) forbids apps to use eval or
Function(string) generated functions (among other things). For us to be
compatible, we just need to implement the "getterFn" in $parse without
violating any of these restrictions.

We currently use Function(string) generated functions as a speed
optimization. With this change, it will be possible to opt into the CSP
compatible mode using the ngCsp directive. When this mode is on Angular
will evaluate all expressions up to 30% slower than in non-CSP mode, but
no security violations will be raised.

In order to use this feature put ngCsp directive on the root element of
the application. For example:

<!doctype html>
<html ng-app ng-csp>
  ...
  ...
</html>

Closes #893
2012-04-27 23:04:24 -07:00
Igor Minar 2b1b257034 chore(server.js): Add CSP support
The support is disabled by default, uncomment relevant lines to enable
it.
2012-04-27 22:04:16 -07:00
Igor Minar 73caf76225 chore(check-size): add a script to check gziped size
this is useful to quickly check the resulting size during development
2012-04-23 11:42:27 -07:00
Igor Minar dbb92efd13 chore(release): start 1.0.0rc7 rc-generation iteration 2012-04-23 11:42:26 -07:00
Vojta Jina 1214084e9d docs(directive): fix transclusion examples 2012-04-21 21:08:30 +02:00
Misko Hevery a18926f986 fix(events): include ie8 in extra event property reset 2012-04-20 17:04:21 -07:00
Misko Hevery b806b30861 fix(bootstrap): rewritten to $script 2012-04-20 17:04:21 -07:00
Misko Hevery 43d15f830f fix(mouseenter): FF no longer throws exceptions 2012-04-20 17:04:21 -07:00
Igor Minar 1d26acb874 chore(release): cutting the 1.0.0rc6 runny-nose release 2012-04-20 15:06:39 -07:00
Igor Minar 983c309542 docs(changelog): release notes for 1.0.0rc6 runny-nose 2012-04-20 15:06:05 -07:00
Igor Minar 904b69c745 fix(select): properly handle empty & unknown options without ngOptions
Previously only when ngOptions was used, we correctly handled situations
when model was set to an unknown value. With this change, we'll add/remove
extra unknown option or reuse an existing empty option (option with value
set to "") when model is undefined.
2012-04-20 14:29:37 -07:00
Igor Minar c65c34ebfe test(selectSpec): clean up and simplify specs 2012-04-20 14:29:36 -07:00
Igor Minar 8ebe5ccd9a feat(jquery): jquery 1.7.2 support 2012-04-20 14:29:36 -07:00
simpulton e61fd1b43a feat($resource): support HTTP PATCH method
Properly serialize data into request body instead of url.

Closes #887
2012-04-20 12:32:33 -07:00
Misko Hevery ce15a3e049 chore(license): update to google 2012-04-20 11:29:34 -07:00
Misko Hevery 46bb08a9d0 fix(compiler): reading comment throws error in ie
Unders some circumstances reading the comment's text throws error.
2012-04-20 11:29:34 -07:00
Misko Hevery 94dd685709 fix(script): Incorrectly reading script text on ie
IE deals with script tags in special way and .text() does not work. Reading the .text property directly fixes the issue.
2012-04-20 11:29:34 -07:00
Misko Hevery dc32ea627e chore(logo): added angular shield logo 2012-04-20 11:29:33 -07:00
Misko Hevery eafe15f54c fix(document): accidental clobbering of document.getAttribute
Closes #877
2012-04-20 11:29:33 -07:00
Chris Dawson 666f326c5d docs(guide/controllers): update w/ controller scope separation 2012-04-20 10:57:26 -07:00
pkozlowski-opensource 908785960d docs(guide/e2e): fix a link to e2e dsl 2012-04-20 10:49:44 -07:00
johnlindquist 5cc245dd80 docs(ngBind): "angular.module.ng.$sanitize" -> "angular.module.ngSanitize.$sanitize" 2012-04-20 10:44:18 -07:00
johnlindquist 0bd0ef7813 docs($compile) "updateh"->"updated" 2012-04-20 10:43:58 -07:00
johnlindquist 0c7252f929 docs(ngBind): "makes make" -> "makes" 2012-04-20 10:43:41 -07:00
Vojta Jina b94fb5c8c1 docs($resource): fix the example 2012-04-15 09:42:54 -07:00
Igor Minar c322735f83 chore(release): starting the 1.0.0rc6 runny-nose iteration 2012-04-12 03:57:14 -07:00
Igor Minar 9260b4937d chore(release): cutting the 1.0.0rc5 reality-distortion release 2012-04-12 03:56:28 -07:00
Igor Minar e9ccec76a6 docs(changelog): release notes for 1.0.0rc5 reality-distortion 2012-04-12 03:26:10 -07:00
Igor Minar 2037facc99 docs(tutorial): update step-04 to v1.0 2012-04-12 02:45:12 -07:00
Igor Minar b2d0a386f6 style(docs-scenario.html): rename <angular/> to AngularJS in the title 2012-04-12 02:36:03 -07:00
Igor Minar 6d7e7fdea6 fix($location): properly rewrite urls in html5 mode with base url set
previously we were doing all kinds of checks to see if we should rewrite the url or not and we
were missing many scenarios. not any more.

with this change, we rewrite the url unless:
- the href is not set
- link has target attribute
- the absolute url of the link doesn't match the absolute prefix for all urls in our app

This also means that ng-ext-link attribute which we previously used to distinguish external
links from app links is not necessary any more. apps can just set target=_self to prevent
rewriting.

BREAKING CHANGE: ng-ext-link directive was removed because it's unnecessary

apps that relied on ng-ext-link should simply replace it with target=_self
2012-04-12 02:36:03 -07:00
Igor Minar df72852f34 fix(e2eRunner): $browser.location should delegate to apps $location
previously it would create a new instance which wasn't configured as the one in the app,
which resulted in incorrect values being returned in html5 mode with base url set
2012-04-12 02:36:03 -07:00
simpulton c4f6ccb065 docs($compile): fixed typo 2012-04-11 23:48:53 -07:00
Igor Minar 0c49bbdc38 test(ngView): fix failing e2e tests 2012-04-11 21:27:55 -07:00
Igor Minar 7d074a3775 docs($http): fix return types 2012-04-11 17:29:16 -07:00
Igor Minar dceafd32ee feat($http): expose the defaults config as $http.defaults
Often it is impossible to set the http defaults during the config phase,
because the config info is not available at this time.

A good example is authentication - often the app needs to bootstrap,
allow user to enter credentials and only then it gains access to
session token which then should be sent to the server with every request.
Without having the ability to set the defaults at runtime, the developer
either has to resort to hacks, or has to set the session token header
with every request made by the app.
2012-04-11 17:29:16 -07:00
Thibault Leruitte 0a5050eb3c fix($location): don't rewrite links to different base paths
links to different base paths should not be left untouched
2012-04-11 17:27:32 -07:00
Vojta Jina 7c430c5ed0 chore(release scripts): group changelog only if more than 1 entry 2012-04-11 16:12:58 -07:00
Vojta Jina 93d62860e9 fix(input.radio): support 2-way binding in a repeater
Closes #869
2012-04-11 15:50:52 -07:00
Vojta Jina 5bcd719866 chore(ngSanitize): extract $sanitize, ngBindHtml, linkyFilter into a module
Create build for other modules as well (ngResource, ngCookies):
- wrap into a function
- add license
- add version

Breaks `$sanitize` service, `ngBindHtml` directive and `linky` filter were moved to the `ngSanitize` module. Apps that depend on any of these will need to load `angular-sanitize.js` and include `ngSanitize` in their dependency list: `var myApp = angular.module('myApp', ['ngSanitize']);`
2012-04-11 15:50:47 -07:00
Igor Minar e1743cc837 docs($compile): fix typo in the docs templateURL -> templateUrl 2012-04-11 11:23:48 -07:00
Igor Minar 52ee1ab5eb chore(*): remove dead code and fix code style issues 2012-04-10 16:52:12 -07:00
Vojta Jina fcc556df37 docs(guide.forms): fix the forms dev guide to use ng-disabled 2012-04-10 13:42:17 -07:00
Igor Minar 5c0ec9d06d docs(angular.bootstrap): fix typos and errors 2012-04-10 13:21:29 -07:00
Igor Minar ac2f0cece6 docs(tutorial): fix typos in steps 2 and 3 2012-04-10 06:04:13 -07:00
Igor Minar fbaa1968b7 chore($browser): remove the addJs method
this was never meant to be a public api used by apps. I refactored
the code to hide the functionality.

BREAKING CHANGE: $browser.addJs method was removed

apps that depended on this functionality should either use many of the
existing script loaders or create a simple helper method specific to the
app.
2012-04-09 17:59:47 -07:00
Igor Minar 13d5528a5f chore($browser): remove the addCss method
this api was never supposed to be public. nobody should be relying
on it.

I'm removing it since angular doesn't need it.

BREAKING CHANGE: $browser.addCss was removed

apps the depend on this functionality should write a simple utility
function specific to the app (see this diff for hints).
2012-04-09 15:21:46 -07:00
Igor Minar b5406d276d chore(ngBind): remove obsolete test
this test is not testing what it claims it is.

we don't need it any more
2012-04-09 11:49:51 -07:00
Igor Minar 0f89383d98 chore(tests): rename all directive names to the normalized form 2012-04-09 11:48:54 -07:00
Igor Minar 10daefc6f4 fix(ngBindHtml): clear contents when model is falsy
Closes #864
2012-04-09 09:52:28 -07:00
Igor Minar dc7b764d4d test(ngBindSpec): correct tests + split them up 2012-04-09 09:52:28 -07:00
Igor Minar 82d90a4096 fix(docs): change all directive references to use the normalized names 2012-04-09 09:52:27 -07:00
Igor Minar 7468bcb80b chore(release): starting 1.0.0rc5 reality-distortion iteration 2012-04-09 08:59:31 -07:00
Igor Minar bd4a4d390c chore(release): cutting the 1.0.0rc4 insomnia-induction release 2012-04-05 11:46:36 -07:00
Igor Minar 94fca76a08 docs(changelog): release notes for 1.0.0rc4 insomnia-induction 2012-04-05 11:45:34 -07:00
Igor Minar 1c8c083404 fix(docs): move $cookies and $cookieStore docs to module 2012-04-05 11:33:42 -07:00
Igor Minar 0f2de12273 chore(docs): add nonminified jquery debug version of docs 2012-04-05 11:33:42 -07:00
Igor Minar 1bbc67ef6c chore(Rakefile): fix and improve file rewriting code 2012-04-05 10:22:27 -07:00
Igor Minar 637817e3ba fix(Rakefile): move 'use strict'; flag into the angular closure
closure compiler is stubborn and puts the flag to the top of the file, so
we have to post-process the minified file to move the flag into the angular
closure.
2012-04-05 10:22:27 -07:00
Vojta Jina 86182a9415 feat($http): add withCredentials config option 2012-04-04 16:13:02 -07:00
Igor Minar 15ecc6f366 feat($route): allow chaining of whens and otherwise
Previously one had to write:

$routeProvider.when('/foo', {...});
$routeProvider.when('/bar', {...});
$routeProvider.otherwise({...});

After this change it's just:

$routeProvider.
    when('/foo', {...}).
    when('/bar', {...}).
    otherwise({...});

Breaks #when which used to return the route definition object but now
returns self. Returning the route definition object is not very useful
so its likely that nobody ever used it.
2012-04-04 16:10:44 -07:00
Igor Minar 53b2254ea7 docs(tutorial): update tutorial intro + steps 0-3
also contains all kinds of fixes that I had to make in the docs app to
get the tutorial to render correctly
2012-04-04 15:59:18 -07:00
Igor Minar 6336b6e89e chore(docs): restore old tutorial ngdoc files 2012-04-04 15:59:18 -07:00
Igor Minar fdf17d729f fix(docs): remove ngModelInstant from all examples
just fixing leftover code after the removal of ngModelInstant
2012-04-04 15:56:15 -07:00
Vojta Jina 85776c0d37 refactor(ngHref, ngSrc): remove duplicate tests 2012-04-04 15:01:27 -07:00
Vojta Jina 02cf958a07 chore(directive): correct file names for booleanAttrs 2012-04-04 14:58:27 -07:00
Vojta Jina 8fe4295a06 refactor(ngInclude): correct the tests 2012-04-04 14:58:07 -07:00
Vojta Jina dcb8e0767f fix(booleanAttrs): convert to boolean
jQuery's attr() does not handle 0 as false, when it comes to boolean attrs.
2012-04-04 08:26:28 -07:00
Misko Hevery 21b77ad5c2 fix(form): preperly clean up when invalid widget is removed
Removing invalid widget sometimes resulted in improper cleanup of the form state.
2012-04-03 23:28:05 -07:00
Misko Hevery 2f5dba488e fix(ng-href): copy even if no binding
Closes# 850

fixed an issue where ng-href would not copy its content into href if it did not contain binding.
2012-04-03 16:02:20 -07:00
Misko Hevery 7e86eacf30 fix($compile): relax the restriction that directives can not add siblings
Relax the restriction that directives can not add siblings
2012-04-03 16:02:20 -07:00
Vojta Jina 15c1fe3929 refactor(ngView): remove extra $watch, refactor one ugly test 2012-04-03 10:10:44 -07:00
Vojta Jina 428f2b5636 feat(ngInclude): allow ngInclude on css class
And make it terminal so that it does not compile its content, which would cause leaks.
2012-04-03 10:10:44 -07:00
Vojta Jina 199ac26986 fix(ngInclude): fire $includeContentLoaded on proper (child) scope 2012-04-03 10:10:44 -07:00
Vojta Jina 5f70d615a5 refactor(ngInclude): remove scope attribute
The purpose of allowing the scope to be specified was to enable the $route service to work
together with ngInclude. However the functionality of creating scopes was in the recent past
moved from the $route service to the ngView directive, so currently there is no valid use case
for specifying the scope for ngInclude. In fact, allowing the scope to be defined can under
certain circumstances lead to memory leaks.

Breaks ngInclude does not have scope attribute anymore.
2012-04-03 10:10:44 -07:00
Vojta Jina 06d0955074 feat(ngModel): update model on each key stroke (revert ngModelInstant)
It turns out that listening only on "blur" event is not sufficient in many scenarios,
especially when you use form validation you always had to use ngModelnstant
e.g. if you want to disable a button based on valid/invalid form.

The feedback we got from our apps as well as external apps is that the
ngModelInstant should be the default.

In the future we might provide alternative ways of suppressing updates
on each key stroke, but it's not going to be the default behavior.

Apps already using the ngModelInstant can safely remove it from their
templates. Input fields without ngModelInstant directive will start propagating
the input changes into the model on each key stroke.
2012-04-03 10:10:44 -07:00
Vojta Jina a22e0699be feat($sniffer): add hasEvent method for sniffing events
Skip changelog
2012-04-03 10:10:44 -07:00
Brad Green 28ff7c3a66 Doc fixes in bootstrap
Now makes sense.
2012-04-03 07:07:49 -07:00
Mykhailo Kotsur 59ae8adb3c fix(scenario): dev secenario tests
closes #843

Fixed failed e2e test
2012-04-02 16:10:15 -07:00
Igor Minar c0b78478a0 fix($q): $q.reject should forward callbacks if missing
$q.reject('some reason').then() should not blow up, but correctly
forward the callbacks instead.

Closes #845
2012-04-02 10:14:04 -07:00
Mykhailo Kotsur 59fa40ec0e fix($location): search setter should not double-encode the value
By mistake both the setter and helper function that composes the whole
url were encoding the search values.

Closes #751
2012-04-02 08:35:30 -07:00
Igor Minar a1f7f5d4d0 chore(release): start 1.0.0rc4 insomnia-induction iteration 2012-03-30 13:23:36 -07:00
Igor Minar 20687aa5f6 chore(release): cutting 1.0.0rc3 barefoot-telepathy 2012-03-29 16:10:40 -07:00
Igor Minar fc52b81d52 fix(docs): update the example widget regexp for detecting angular.js url
so that we don't show angular-cookies instead of angular.js
2012-03-29 16:10:40 -07:00
Igor Minar ae1aee2b6c fix(FormController): ask for dependency to fool the BC module 2012-03-29 16:10:40 -07:00
Igor Minar 423242017e fix(docs): properly rewrite urls in doc examples at docs-next 2012-03-29 16:10:40 -07:00
Vojta Jina 95c5df5958 fix(ngValue): bind properly inside ng-repeat 2012-03-29 14:05:19 -07:00
Igor Minar 2cb907a836 fix($injector): properly infer dependencies from fn with no args
Previously if there was a white-space in fn: fn( ) {} we failed to infer no args.

This was originally reported by recht, but I decided to use a different fix.

Closes #829
2012-03-29 11:21:04 -07:00
Igor Minar 2f2fd465a4 docs(changelog): release notes for 1.0.0rc3 barefoot-telepathy 2012-03-29 08:10:28 -07:00
Vojta Jina 6da355c3e1 refactor($compile): move methods of attr object into prototype
We have many instances of this object and we clone them as well (e.g. ng-repeat).
This should save some memory and performance as well.

Double prefixed private properties of attr object:
attr.$element -> attr.$$element
attr.$observers -> attr.$$observers

Update shallowCopy to not copy $$ properties and allow passing optional destination object.
2012-03-29 07:30:32 -07:00
Vojta Jina f2106692b1 fix($compile): properly clone attr.$observers in ng-repeat
The `attr` object was only shallow copied which caused all observers to be shared.
Fixing similar issue in ng-* boolean attributes as well as ng-src and ng-href.
2012-03-29 07:30:32 -07:00
Vojta Jina 4557881cf8 chore(release scripts): auto release scripts 2012-03-29 07:22:13 -07:00
Igor Minar af0ad6561c refactor(fromJson/toJson): move the contents of these files into Angular.js
these files are now mostly empty so it doesn't make sense to keep them
separated from other helper functions
2012-03-28 16:57:34 -07:00
Igor Minar 35125d2513 refactor(toJson): use native JSON.stringify
Instead of using our custom serializer we now use the native one and
use the replacer function to customize the serialization to preserve
most of the previous behavior (ignore $ and $$ properties as well
as window, document and scope instances).
2012-03-28 16:57:22 -07:00
Igor Minar 87f5c6e5b7 refactor(fromJson): always use native JSON.parse
This breaks IE7 for which you can use polyfill:

https://github.com/douglascrockford/JSON-js

<!--[if lt IE 8]>
<script src="json2.min.js"></script>
<![endif]-->

or

http://bestiejs.github.com/json3/

<!--[if lt IE 8]>
<script src="json3.min.js"></script>
<![endif]-->
2012-03-28 16:30:38 -07:00
Igor Minar a8a750ab05 feat($http): make the transform defaults to an array
$httpProvider.defaults.transformRequest and $httpProvider.defaults.transformResponse
are now arrays containing single function. This makes it easy to add an
extra transform fn.

adding an extra fn before had to be done in this cluncky way:

$httpProvider.defaults.transformResponse =
[$httpProvider.defaults.transformResponse, myTransformFn];

after this change, it's simply:

$httpProvider.defaults.transformResponse.push(myTransformFn);
2012-03-28 16:30:38 -07:00
Igor Minar 13a95ae499 style($http): remove redundant 'use strict' header 2012-03-28 16:30:31 -07:00
Igor Minar da9f4dfcf4 feat(TzDate): add support for toISOString method 2012-03-28 16:30:31 -07:00
Igor Minar ac4318a2fa refactor(fromJson/date filter): move date string logic to date filter
Breaks angular.fromJson which doesn't deserialize date strings into date objects.

This was done to make fromJson compatible with JSON.parse.

If you do require the old behavior - if at all neeeded then because of
json deserialization of XHR responses - then please create a custom
$http transform:

$httpProvider.defaults.transformResponse.push(function(data) {
  // recursively parse dates from data object here
  // see code removed in this diff for hints
});

Closes #202
2012-03-28 16:30:30 -07:00
Misko Hevery bb2fa6f63f fix(i18n e2e tests): 2012-03-28 11:24:47 -07:00
Igor Minar ba59ef4950 docs(examples): update example apps 2012-03-28 11:24:47 -07:00
Igor Minar 8b93541522 style(Rakefile): use snake_case in ruby code 2012-03-28 11:16:36 -07:00
Misko Hevery 7b22d59b4a chore(ngCookies): moved to module 2012-03-28 11:16:36 -07:00
Misko Hevery 798bca62c6 chore(resource): moved to module 2012-03-28 11:16:36 -07:00
Misko Hevery 8218c4b60b chore(Rakefile): get ready for modules 2012-03-28 11:16:36 -07:00
Misko Hevery 2430f52bb9 chore(module): move files around in preparation for more modules 2012-03-28 11:16:35 -07:00
Brad Green 944098a4e0 Updated manual bootstrap document
Explained why you'd want to manually bootstrap, added contrasting
example for automatic vs manual methods.
2012-03-27 18:06:00 -07:00
Brad Green 2ce0485e6f Rewrite of Automatic Initialization doc
Added examples, explained the reasons why you initialize the whole app
or parts of the page.
2012-03-27 08:28:34 -07:00
Vojta Jina a08cbc02e7 feat($compile): do not interpolate boolean attributes, rather evaluate them
So that we can have non string values, e.g. ng-value="true" for radio inputs

Breaks boolean attrs are evaluated rather than interpolated

To migrate your code, change: <input ng-disabled="{{someBooleanVariable}}">
to: <input ng-disabled="someBooleanVariabla">


Affected directives:

* ng-multiple
* ng-selected
* ng-checked
* ng-disabled
* ng-readonly
* ng-required
2012-03-26 21:14:09 -07:00
Vojta Jina 55027132f3 refactor(ngBindAttr): remove
Breaks ng-bind-attr directive removed
2012-03-26 21:14:09 -07:00
Vojta Jina 09e175f02c feat(ngValue): allow radio inputs to have non string values
Closes #816
2012-03-26 21:14:09 -07:00
Mykhailo Kotsur 5c5b1183c8 docs(guide/module): fix syntax error and expectation in test example 2012-03-26 16:06:46 -07:00
Mykhailo Kotsur f04142ea28 docs(guide/unit-testing): fixed typo in code example 2012-03-26 16:06:16 -07:00
Igor Minar aaedefb92e refactor($sniffer): make $sniffer service private
This service has been accidentaly documented in the past, it should not be considered
to be public api.

I'm also removing fallback to Modernizr since we don't need it.

Breaks any app that depends on this service and its fallback to Modernizr, please
migrate to custom "Modernizr" service:

    module.value('Modernizr', function() { return Modernizr; });
2012-03-26 15:43:59 -07:00
Igor Minar d54dfecb00 feat($controller): support controller registration via $controllerProvider
It's now possible to register controllers as:

.register('MyCtrl', function($scope) { ... });
// or
.register('MyCtrl', ['$scope', function($scope) { ... });

Additionally a module loader shortcut api was added as well:

myModule.controller('MyCtr', function($scope) { ... });
2012-03-26 15:23:29 -07:00
Igor Minar 4b8d926062 feat(assertArgFn): should support array annotated fns 2012-03-26 12:21:42 -07:00
Igor Minar 74c84501ed doc(guide/module): fix typo 2012-03-23 16:57:24 -07:00
Igor Minar 4581b79bbd doc(guide/controller): fix examples 2012-03-23 16:54:48 -07:00
Manuel Woelker 2be8847ef6 doc(guide): order topic list in guide sidebar in accordance with overview
Closes #405
2012-03-23 16:31:33 -07:00
Igor Minar cb2ad9abf2 fix(init): use jQuery#ready for init if available
Closes #818
2012-03-23 15:41:37 -07:00
Misko Hevery 73c8593077 feat(http): added params parameter
The params parameter can now be used to serialize parameters in the URLs. The serialization does proper escaping and JSON encoding if it is an object.
2012-03-23 14:21:43 -07:00
Misko Hevery ac75079e21 fix(q): resolve all of nothing to nothing
$q.all([]) no longer throws exception and resolves to empty array []
2012-03-23 14:21:43 -07:00
Igor Minar 5390fb37d2 fix($compile): create new (isolate) scopes for directives on root elements
previously we would not create them and it's causing all kinds of issues and accidental leaks

Closes #817
2012-03-23 11:46:54 -07:00
Igor Minar 8d7e694849 fix(forEach): should ignore prototypically inherited properties
Closes #813
2012-03-22 16:39:36 -07:00
Igor Minar 5fdab52dd7 feat(jqLite): make injector() and scope() work with the document object
For typical app that has ng-app directive on the html element, we now can do:

angular.element(document).injector() or .injector()
angular.element(document).scope() or .scope()

instead of:

angular.element(document.getElementsByTagName('html')[0]).injector()
...
2012-03-22 16:39:36 -07:00
Vojta Jina 541bedd1a9 refactor(ngController): remove unused deps 2012-03-22 16:29:31 -07:00
Igor Minar 98e18a64aa docs(cookbook/form): fix the example
Closes #712
2012-03-21 13:52:11 -07:00
Igor Minar 0a45bff472 chore(docs): switch disqus id from angularjs to angularjs-next 2012-03-21 13:46:35 -07:00
Igor Minar 263524d381 docs(changelog): fix rc2 release date 2012-03-20 17:21:41 -07:00
Igor Minar 52c59cf0ce chore(release): start 1.0.0rc barefoot-telepathy iteration 2012-03-20 16:02:49 -07:00
Igor Minar c5f8edfe03 chore(release): cutting the 1.0.0rc2 silence-absorption release 2012-03-20 15:38:57 -07:00
Igor Minar 69f0aa899d docs(changelog): release notes for 1.0.0rc2 silence-absorption 2012-03-20 15:25:31 -07:00
Daniel Zen e7cd0bcc5a docs(guide/controllers): add a section on testing controllers 2012-03-20 15:23:58 -07:00
Vojta Jina ade6c45275 feat(input.radio): Allow value attribute to be interpolated 2012-03-20 14:39:23 -07:00
Igor Minar 9eafd10fcd docs(guide/location): fix example 2012-03-20 12:05:57 -07:00
Igor Minar 3436c027f2 docs(guide/started): fix examples 2012-03-20 11:30:21 -07:00
Igor Minar 6a8749e65a refactor($resource): unify and simplify the code 2012-03-20 11:07:38 -07:00
Igor Minar 1a5bebd927 fix($http): don't send Content-Type header when no data
When a http request has no data (body), we should not send the
Content-Type header as it causes problems for some server-side
frameworks.

Closes #749
2012-03-20 11:07:38 -07:00
Igor Minar 83155e8fbe style(ResourceSpec): style clean up 2012-03-20 11:07:37 -07:00
Igor Minar 6d6f875345 fix($resource): support escaping of ':' in resource url
So one can how define cors/jsonp resources with port number as:

resource.route('http://localhost\\:8080/Path')
2012-03-20 11:07:37 -07:00
Igor Minar a4fe51da3b feat($route): when matching consider trailing slash as optional
This makes for a much more flexible route matching:

- route /foo matches /foo and redirects /foo/ to /foo
- route /bar/ matches /bar/ and redirects /bar to /bar/

Closes #784
2012-03-20 11:07:37 -07:00
Igor Minar ee5a5352fd fix(e2e runner): fix typo that caused errors on IE8
Closes #806
2012-03-20 11:07:37 -07:00
Igor Minar 9cb2195e61 fix($compile): don't touch static element attributes
Compiler should not reassign values to element attributes if its not neccessary due
to interpolation or special attribute magic (ng-src -> src)

This resolves several issues on IE caused by reassigning script.src attribute which
caused all of the scripts to be reloaded.
2012-03-20 11:07:36 -07:00
Igor Minar 15213ec212 fix($log): avoid console.log.apply calls in IE
In IE window.console.log and friends are functions that don't have apply or call fns.

For this reason we have to treat them specially and do our best to log at least
something when running in this browser.

Closes #805
2012-03-20 11:07:36 -07:00
Igor Minar 9171c76bb4 style($log): reformat code for readability 2012-03-20 11:07:35 -07:00
Igor Minar 64fb1f2620 docs(filters): use ng-model-instant in live examples
Closes #807
2012-03-20 11:07:35 -07:00
Vojta Jina f49eaf8bf2 fix($compile): Merge interpolated css class when replacing an element 2012-03-20 10:39:43 -07:00
Vojta Jina f701ce08f9 fix(matchers.toHaveClass): Correct reference to angular.mock.dump 2012-03-19 17:26:29 -07:00
Misko Hevery 1cc0e4173d bug(ie7): incorrectly set all inputs to disabled
In ie7 all of the input fields are set to readonly and disabled, because ie7 enumerates over all attributes even if the are not declared on the element.
2012-03-19 15:49:42 -07:00
Misko Hevery d4ae7988da chore(parseInt): cleanup parseInt() for our int() 2012-03-19 11:41:23 -07:00
Misko Hevery 5ac14f633a fix(json): added support for iso8061 timezone
Added support of timezone in dates not just zulu timezone.

This fixes issues for date filter which uses json deserialization under the hood. (for now)

Closes #/800
2012-03-19 11:41:10 -07:00
Misko Hevery 9918b748be fix(compiler): allow transclusion of root elements
Fixed an issue where a directive that uses transclusion (such as ngRepeat) failed to link if it was declared on the root element of the compilation tree. (For example ngView or ngInclude including template where ngRepeat was the top most element).
2012-03-19 11:35:10 -07:00
Misko Hevery 6ecac8e71a fix(select): multiselect failes to update view on selection insert
In multiselect when the underlying selection array push/pops an element the view did not re-render since the array reference stayed the same.
2012-03-19 11:35:10 -07:00
Misko Hevery 823adb2319 fix(ngForm): alias name||ngForm
form directive was requiring name attribute even when invoked as attribute, resulting in unnecessary duplication
2012-03-19 11:35:09 -07:00
Misko Hevery 21e74c2d2e fix(ngView): controller not published
corrected omitted assignment of controller to the element data object. Without this fix the controller created by ngView is not accessible from the browser debugger.
2012-03-19 11:35:09 -07:00
Misko Hevery 6c5a05ad49 feat(jqLite): add .controller() method
extend JQuery with .controller() method which retrieves the closest controller for a given element
2012-03-19 11:35:09 -07:00
Vojta Jina 192ff61f5d feat(scope.$eval): Allow passing locals to the expression 2012-03-18 23:46:30 -07:00
Igor Minar 935c1018da fix(ngRepeat): correct variable reference in error message
Closese #803
2012-03-17 15:57:55 -07:00
Igor Minar 78a6291666 docs(scope): add $destroy event docs 2012-03-16 15:32:14 -07:00
Igor Minar 53b6f522a5 fix(ngDocSpec): fix broken tests 2012-03-16 15:32:14 -07:00
Vojta Jina 1faafa3158 fix(forms): Remove double registering of form 2012-03-16 12:06:29 -07:00
Vojta Jina 08bfea183a fix(forms): Set ng-valid/ng-invalid correctly 2012-03-16 12:06:29 -07:00
Igor Minar f13dd3393d feat(injector): infer _foo_ as foo
this is to enable nicer tests:

 describe('fooSvc', function() {
   var fooSvc;

   beforeEach(inject(function(_fooSvc_) {
     fooSvc = _fooSvc_;
   }));

   it('should do this thing', function() {
     //test fooSvc
   });
 });
2012-03-16 10:52:40 -07:00
Igor Minar bca96e7c7c style(ngViewSpec): pretify some tests with $destroy events 2012-03-16 10:52:40 -07:00
Igor Minar 9b1aff905b feat(scope): broadcast $destroy event on scope destruction
perf testing shows that in chrome this change adds 5-15% overhead
when destroying 10k nested scopes where each scope has a $destroy listener
2012-03-16 09:41:05 -07:00
Igor Minar 252d4548f9 style(ngSwitchSpec): fix typo 2012-03-15 15:23:49 -07:00
Igor Minar 6abafcb424 docs(changelog): fix broken links
Closes #793
2012-03-15 10:19:44 -07:00
Igor Minar 2315d9b361 fix(ng-switch): properly destroy child scopes 2012-03-14 14:33:20 -07:00
Igor Minar 8fd1b74872 chore(release): start the 1.0.0rc2 silence-absorption iteration 2012-03-14 13:45:44 -07:00
alkis 02091b2c1e style(changelog): Fix some typos 2012-03-14 10:13:03 -07:00
Igor Minar 25cd774abf chore(release): cutting 1.0.0rc1 moiré-vision 2012-03-14 01:00:46 -07:00
Igor Minar c70ead0aa1 fix(Rakefile): version.dot extractor should ignore 'rc1' 2012-03-13 23:24:17 -07:00
Igor Minar 716b5fd3e2 docs(*): fixing various docs 2012-03-13 23:17:43 -07:00
Misko Hevery 8b8fdddc0b docs(links): corrected borken links 2012-03-13 19:36:09 -07:00
Igor Minar ce4b630524 fix(docs): properly close the optional ] in directive signatures 2012-03-13 17:51:05 -07:00
Vojta Jina 13f31602f3 feat(ng-list): Allow custom separator 2012-03-13 17:51:05 -07:00
Daniel Zen 7b52586f7c docs(guide): fix non-working example + add docs for implicit DI 2012-03-13 17:14:50 -07:00
Misko Hevery e9e3ee012b feat(compile): allow ngForm on attribute and class
#feature
- ngForm directive can now be used with element, class, and attributes
2012-03-13 16:59:10 -07:00
Misko Hevery de9464c143 f(compile): boolean attributes too agresive
- compiler would rewrite boolean attributes on all elements. This is too aggressive and interferes with some third-party frameworks
2012-03-13 16:59:03 -07:00
Misko Hevery 31cd580310 fix(ng-non-bindable): increase priority to 1000
- increase ng-non-bindable prioirity to 1000 so that it prevents attribute interpolation on same level.
2012-03-13 16:58:36 -07:00
Misko Hevery d34f3bc7a6 feat(form): publish validationErrorKeys as CSS
- The validationErrorKeys are now published as CSS for easy styling. The errorKeys should be in
 camelCase and the CSS will be in snake-case
2012-03-13 16:57:36 -07:00
Misko Hevery 027801a00a doc(search): include method names in corpus 2012-03-13 16:32:15 -07:00
Vojta Jina 66e6c1ce2c docs(forms): Change validation tokens to lowercase 2012-03-13 16:18:14 -07:00
Igor Minar 4806d28a29 fix(forms): remove control.$form and use nullFormCtrl 2012-03-13 16:05:52 -07:00
Igor Minar 089c0f8b0e fix(forms): fix nesting issues and add tests 2012-03-13 16:05:52 -07:00
Igor Minar b6ae6e52f9 fix(indexOf): use native impl if available 2012-03-13 14:13:53 -07:00
Igor Minar 9277d12fc0 fix(forms): lowercase all validation error keys 2012-03-13 14:13:53 -07:00
Igor Minar ac5151a469 fix(scope): remove scope $destroy event 2012-03-13 14:13:53 -07:00
Vojta Jina 63be222326 docs(input): Fix some broken links, add missing $, use ng- in examples 2012-03-13 13:52:57 -07:00
Vojta Jina a29c2cf70c doc(form): updated to reflect the latest changes 2012-03-13 13:36:28 -07:00
Igor Minar afe617a647 docs(*): renaming incorrect widget references to control or directive 2012-03-12 23:04:12 -07:00
Igor Minar f59e4b11f1 fix(forms): prefix all form and control properties with $ 2012-03-12 23:04:11 -07:00
Igor Minar 5e6ba25201 fix(forms): remove the need for extra form scope
the forms/controls code refactored not to depend on events which forced
us to create new scope for each form element.
2012-03-12 23:04:11 -07:00
Igor Minar 9134f5ce5a style(ng-include): remove unused args 2012-03-12 23:04:11 -07:00
Igor Minar 4e6b065a2f test(ng-include): add ng-include=src test 2012-03-12 23:04:11 -07:00
Igor Minar 5e3db61b1d docs(release): release notes for 1.0.0rc1 2012-03-12 23:04:11 -07:00
Igor Minar a9ed5745a0 docs(directive): add more docs for the directive api 2012-03-12 23:04:10 -07:00
Misko Hevery 48096048cf fix(svg): normalize class access for SVG 2012-03-12 21:59:50 -07:00
Vojta Jina 317adb36a4 docs(guide.forms): Update forms guide 2012-03-12 01:40:12 -07:00
Vojta Jina 1b9277bf6f fix(forms): Propagate change from model even if it's undefined 2012-03-12 01:40:12 -07:00
Misko Hevery cce31d4c93 chore(ng-include): update to work in ng-include|src mode 2012-03-11 22:36:29 -07:00
Misko Hevery 3e5377f4f3 doc(fixes): to better support ng-directive notation 2012-03-11 21:31:35 -07:00
Misko Hevery 488a03631e Mostly Revert "fix(docs): directive events + cleanup"
This reverts commit 8fb34f008e.
2012-03-11 21:31:34 -07:00
Vojta Jina 716dd5f3f9 refactor(forms): Remove touch() method 2012-03-09 17:33:22 -08:00
Vojta Jina 83314913e7 refactor(forms): Rename read() -> setViewValue() 2012-03-09 17:33:22 -08:00
Igor Minar e0cc84ad7b docs(directives): set directive param name to directive name
so that we can render better usage examples in docs
2012-03-09 16:27:12 -08:00
Igor Minar 4a94bb9b34 fix(startTag): fix tagname extraction
the original code magically worked for ng:foo but for nothing else
2012-03-09 16:27:12 -08:00
Igor Minar 53aacb35fa chore(shiv): remove obsolete shiv code
we can't provide this functionality because the directives are lazy
loaded when the module loads, which is too late for the shiv to do
anything useful.
2012-03-09 16:14:26 -08:00
Igor Minar f4d338d393 chore(*): refactor all ng: to ng- 2012-03-09 16:14:26 -08:00
Vojta Jina 0bfaa579c0 feat($provide.service): Add $provide.service() for registering a class 2012-03-09 10:10:29 -08:00
Vojta Jina 00d4427388 refactor($provide) Rename service -> provider
It registers a provider class, so this makes more sense.

Breaks Rename $provide.service -> $provide.provider
2012-03-09 10:10:28 -08:00
Vojta Jina e0c9551fd7 refactor(forms): remove registerWidget and use event instead
Each widget (ng-model directive) emits $newFormControl event instead of getting hold of parent form
and calling form.registerWidget(this);
2012-03-09 10:10:28 -08:00
Igor Minar fae84463e4 docs(css): allow headers to wrap with blue background 2012-03-08 22:29:35 -08:00
Igor Minar 8fb34f008e fix(docs): directive events + cleanup 2012-03-08 22:29:35 -08:00
Igor Minar 5d09a1efd3 fix(ng-view, ng-include): onload and $contentLoaded
- change custom onload directive to special arguments recongnized by both
  ng-view and ng-include
- rename $contentLoaded event to $viewContentLoaded and $includeContentLoaded
- add event docs
2012-03-08 22:29:35 -08:00
Igor Minar f54db2ccda chore(directives,widgets): reorg the code under directive/ dir 2012-03-08 22:29:34 -08:00
Misko Hevery dd7b0f56fc fix(ng-cloak): work with class 2012-03-08 16:30:39 -08:00
Vojta Jina b3750103cc fix($parse): Allow property names that collide with native object properties
I.e. constructor, toString, or watch on FF
(https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch)

+ optimize parser a bit to not create getter function for operators
2012-03-08 11:39:03 -08:00
Vojta Jina b348347dad refactor(fromJson): Remove error() and just throw
It's more likely you are using angular.fromJson() inside Angular world, which means you get proper
exception handling by $exceptionHandler.

There is no point to explicitly push it to console and it causes memory leaks on most browsers 
(tried Chrome stable/canary, Safari, FF).
2012-03-08 11:38:14 -08:00
Igor Minar 512db03cc0 docs(ng-list): update the ng-list directive docs 2012-03-08 11:06:15 -08:00
Igor Minar ee7209fe26 fix(tests): fix name collisions between various tests 2012-03-08 11:06:15 -08:00
Igor Minar 772ddb983b docs(directive, module): add various missing docs and fix existing docs 2012-03-08 11:06:14 -08:00
Igor Minar 7f6c1093f5 docs(ng-view): improve the ng-view docs 2012-03-08 11:06:14 -08:00
Igor Minar 1b4289ce76 fix(docs): add a header for the directive info section 2012-03-08 11:06:14 -08:00
Igor Minar af21233820 fix(test): rename an it so that it doesn't colide with the test above 2012-03-08 11:06:14 -08:00
Igor Minar 08ad4b6a46 docs(jqlite): add docs for wrap() 2012-03-08 11:06:14 -08:00
Igor Minar 2acd60df4d fix(docs): remove undefined from examples with jsfiddle=false 2012-03-08 11:06:14 -08:00
Igor Minar e0ace15cd3 docs($rootScope): rename ttl to digestTtl + docs 2012-03-08 11:01:22 -08:00
Misko Hevery 6a98c52c84 chore(compiler): change default restriction to attribute only for directives 2012-03-08 10:07:49 -08:00
Vojta Jina 6aa3cfc31b docs($compileProvider.directive): Update iAttrs docs 2012-03-07 14:04:14 -08:00
Vojta Jina 64912069ca docs(mock.inject): Fix the example
And explicitly say that you need to load your application modules that you wanna test.
2012-03-05 19:28:03 -08:00
Vojta Jina b49ddf9848 docs($route, ng:view): Fix the examples to work on jsfiddle, update docs 2012-03-05 19:15:18 -08:00
Vojta Jina 1084ccf7ef fix(docs): Add $locationProvider methods to the docs example provider
- $locationProvider.html5Mode
- $locationProvider.hashPrefix

Docs example is basically a different application on the same page, but we don't want to instantiate multiple instances of $browser or $location service, so we are overriding these providers to return the instances from parent app.

Overriding the service with $provide.value caused a provider to be auto-generated without the necessary hashPrefix and html5Mode apis.
2012-03-05 19:09:43 -08:00
Vojta Jina c2989f6cc6 fix(ng-include): Compile only content 2012-03-05 10:41:59 -08:00
Vojta Jina 4f797fe5f3 refactor(testabilityPatch): Change JSTD fail to more general throw
"fail" is a JSTD specific API, so it's not defined when testing without JSTD (eg SlimJim).
2012-03-05 10:41:51 -08:00
Vojta Jina bbd3a3fd76 chore: Update slim-jim 2012-03-05 09:59:29 -08:00
Stephane Bisson e86bafecd2 fix(mock.TzDate): getDay() takes into account the timezone offset 2012-02-29 15:53:51 -08:00
Marcello Nuccio e68c02c537 docs($cacheFactory): Correct method's description 2012-02-29 15:48:37 -08:00
Marcello Nuccio 25d207c48c docs($injector): Correct provider suffix to "Provider" 2012-02-29 15:46:55 -08:00
Vojta Jina 4370d756e4 refactor(directive.ngModel): rename emitValidity -> setValidity 2012-02-28 18:22:41 -08:00
Vojta Jina 4e83399570 fix(ng:model-instant): defer only keydown, throttle setTimeouts 2012-02-28 18:22:41 -08:00
Vojta Jina e7d6106811 fix(input): Render 0 (number) as 0 (not empty string) 2012-02-28 18:22:41 -08:00
Vojta Jina c4c60c25b4 reafactor: Rename ng:bind-immediate -> ng:model-instant 2012-02-28 18:22:41 -08:00
Vojta Jina 139e1b09a9 docs(forms): Update API docs for forms
- API forms (ng:model + controller, form + controller)
- fix some broken links
- ng:change, ng:model-instant
2012-02-28 18:22:35 -08:00
Vojta Jina 60743fc52a feat(ng:include) Fire $contentLoaded event
+ refactor unload to listen on this event -> we can use unload with ng:view as well

Closes #743
2012-02-28 17:48:07 -08:00
Vojta Jina 9486590e1b refactor(ng:view) Make $route scope agnostic, add $contentLoaded event
Problems:

- controller was instantiated immediately on $afterRouteChange (even if no content), that's
different compare to ng:controller, which instantiates controllers after compiling
- route listened on current scope ($afterRouteChange), so if you were listening on $rootScope
($afterRouteChange), you get called first and current.scope === undefined, which is flaky
- route handles scope destroying, but scope is created by ng:view
- route fires after/before route change even if there is no route (when no otherwise specified)

Solution:

- route has no idea about scope, whole scope business moved to ng:view (creating/destroying)
- scope is created (and controller instantiated) AFTER compiling the content
- that means on $afterRouteChange - there is no scope yet (current.scope === undefined)
- added $contentLoaded event fired by ng:view, after linking the content
2012-02-28 17:46:58 -08:00
Misko Hevery e31d1c287d refactor($route): remove .parent(); ng:view scope creation 2012-02-28 17:46:58 -08:00
Misko Hevery f16bd2f747 refactor($route): move when/otherwise to provider 2012-02-28 17:46:58 -08:00
Misko Hevery ef7346ff70 docs(scope): correct formatting 2012-02-28 17:46:58 -08:00
Misko Hevery f6fb31e8ad chore(ng:view): simplify, by taking advantage of new compiler features 2012-02-28 17:46:58 -08:00
Vojta Jina 21c725f1a1 refactor(forms): Even better forms
- remove $formFactory completely
- remove parallel scope hierarchy (forms, widgets)
- use new compiler features (widgets, forms are controllers)
- any directive can add formatter/parser (validators, convertors)

Breaks no custom input types
Breaks removed integer input type
Breaks remove list input type (ng-list directive instead)
Breaks inputs bind only blur event by default (added ng:bind-change directive)
2012-02-28 17:46:58 -08:00
Vojta Jina e23fa768aa docs(directive.script): Subtle update to API docs 2012-02-28 17:41:37 -08:00
Vojta Jina d656d11489 feat(directive.style): Do not compile content of style element 2012-02-28 17:41:30 -08:00
Vojta Jina b37e8a2b14 docs(directive.script): Add simple example of inlined template 2012-02-28 14:15:44 -08:00
Vojta Jina 4c1c50fd9b fix(directive.script): Do not compile content of script tags 2012-02-28 14:15:44 -08:00
Vojta Jina d1558d7924 docs: evaluate only scripts with type text/javascript 2012-02-28 14:15:39 -08:00
Vojta Jina 5b0d068358 fix($http): Do not serialize File object 2012-02-25 18:49:54 -08:00
Vojta Jina 230f29d0a7 fix(jqLite): set event's monkey patched methods to null (on IE7) 2012-02-23 23:41:41 -08:00
Vojta Jina 3171f21591 fix($httpBackend): Set current url, if not defined or empty string
Reason to fix this was the fact that with undefined url, it ended up with weird exception
(Cannot call method 'replace' of undefined), which was more confusing than helpful.

jQuery.ajax() does request to current url, if url is not specified, so I decided for this solution.
2012-02-23 22:50:02 -08:00
Misko Hevery d6e3e1baab feta(scope): watch object refference or equality
Breaks: Must set $watch equality to true for the old behavior
2012-02-23 15:01:08 -08:00
Misko Hevery ffa8441886 bug(equals): incorect comparison of dates 2012-02-23 13:57:28 -08:00
Misko Hevery 5d8528cc2e docs(module): Describe module loading 2012-02-23 09:53:14 -08:00
Misko Hevery 80edcadb1d feat($provide): added constant 2012-02-22 13:28:42 -08:00
Misko Hevery c27a56f4da docs(scope): show which directives create scopes 2012-02-22 12:59:23 -08:00
Misko Hevery fbcb7fdd14 fix($injector): circular dependency instatiation 2012-02-22 11:32:09 -08:00
Vojta Jina fa69d10122 docs(ng:app): Move to other directives namespace 2012-02-22 11:09:33 -08:00
Vojta Jina dd321c5f4d docs(scope): update $emit/$broadcast docs 2012-02-22 10:24:40 -08:00
Misko Hevery 656a495e50 refactor(directive): use attrs.$observe 2012-02-21 22:46:01 -08:00
Vojta Jina 6d0ca95fa0 feat($compiler): Allow attr.$observe() interpolated attrs 2012-02-21 22:46:01 -08:00
Misko Hevery 3df7b8e57f fix(ng:repeat): use transclusion 2012-02-21 22:46:01 -08:00
Misko Hevery 7bd69d0f5b chore(ng:switch): rewritten with transclusion API
BREAKING CHANGE: the change event fires on scope of switch not on scope of case.
2012-02-21 22:46:01 -08:00
Misko Hevery 3773323e46 docs($compile): transclude documentation 2012-02-21 22:46:01 -08:00
Misko Hevery 78656fe0df feat($compile) add locals, isolate scope, transclusion 2012-02-21 22:46:00 -08:00
Misko Hevery cb10ccc44f feat($compile): mark scope creation with ng-scope class 2012-02-21 22:46:00 -08:00
Misko Hevery 4a051efb89 feat($compile): support compiling text nodes by wrapping them in <span> 2012-02-21 22:46:00 -08:00
Misko Hevery 1752c8c44a feat(directive): event now accessible as $event
Closes 259
2012-02-21 22:46:00 -08:00
Misko Hevery 6216dc0465 chore(select): remove inherit, replace with expression locals 2012-02-21 22:45:59 -08:00
Misko Hevery 761b2ed85a feat(parse): add support for local vars in expressions 2012-02-21 22:45:59 -08:00
Misko Hevery c8ee631c19 feat(mouseenter/mouseleave): emulating ie events 2012-02-21 22:45:59 -08:00
Misko Hevery cae9ad4ba9 docs(decorator): add missing decorate docs 2012-02-21 22:45:59 -08:00
Misko Hevery 85b2084f57 fix(select): double array issue with multislect and jQuery 2012-02-21 22:45:59 -08:00
Misko Hevery 13b21aaf5a fix(doc): example was referring to non existent CSS 2012-02-21 22:45:59 -08:00
Misko Hevery 22c1db1744 fix(ngdoc): extract keywords from properties/methods. 2012-02-21 22:45:58 -08:00
Misko Hevery 292a5dae07 chore(slim-jim) add configuration 2012-02-21 22:45:58 -08:00
Vojta Jina 6e635012fb feat(scope): scope.$emit/$broadcast return the event object, add cancelled property 2012-02-21 10:58:48 -08:00
Misko Hevery eb92735c9e fix(injector) .instantiate([Type]) produced wrong result 2012-02-16 14:32:52 -08:00
Vojta Jina 776739299b fix($injector): instantiate returns instance, if non-object value returned from constructor 2012-02-08 16:12:11 -08:00
Vojta Jina 3173d8603d fix(jqLite): fix memory leaking in IE8 (remove monkey patched methods on Event)
These methods cause IE8 holds the whole jqLite in the memory, even when page is reloaded.
jqLite's cache keeps element's data (event handlers, attached scopes, injector, etc…), so almost all used memory is never released in IE8.

jQuery creates its own Event object (wrapper around native Event) instead.
2012-02-05 00:09:02 -08:00
Vojta Jina 6c4f1391bc refactor(test): remove odd inject from describe 2012-01-30 11:44:19 -08:00
Vojta Jina 58d6da556a refactor(binder): replace jested assertions with jasmine 2012-01-29 21:59:35 -08:00
Vojta Jina b6f61a89cf docs($compileProvider.directive): fix some typos 2012-01-26 09:13:08 -08:00
Igor Minar 8b32900d72 fix($parse): simplify getterFn 2012-01-25 16:52:39 -08:00
Igor Minar 18a1e860a3 fix($parse): small fixes
- typos
- dead code removal
- remove unneeded variable
2012-01-25 16:17:44 -08:00
Igor Minar 39b3297fc3 fix($parse): get rid of $unboundFn
Closes #731
2012-01-25 16:17:43 -08:00
Misko Hevery 1268fc1a44 cleanup($scope): remove $$scope ref. 2012-01-25 11:54:00 -08:00
Misko Hevery 4804c83b7d docs(compiler): update the compiler docs 2012-01-25 11:53:59 -08:00
Misko Hevery e2b1d9e994 feat(scriptTemplateLoader): provide template inlining
populates $templateCache with content of ng-template scripts
2012-01-25 11:50:37 -08:00
Misko Hevery 9ee2cdff44 refactor(directives): connect new compiler
- turn everything into a directive
2012-01-25 11:50:37 -08:00
Misko Hevery 8af4fde182 add($compile): add compiler v2.0 - not connected 2012-01-25 11:46:36 -08:00
Misko Hevery 5001c1a121 refactor($interpolate): improve interpolation service add documentation 2012-01-25 11:46:36 -08:00
Misko Hevery 0f6b2ef982 refactor(sanitizer): turn sanitizer into a service 2012-01-25 11:46:35 -08:00
Misko Hevery 1e258d11d0 feat(test): support it('should', pending); 2012-01-25 11:46:35 -08:00
Misko Hevery 81a6601e05 fix(docs): improper rendering of JSON 2012-01-25 11:46:35 -08:00
Igor Minar 1e96d0af8c fix(injector): small perf improvement & code cleanup 2012-01-25 11:46:35 -08:00
Misko Hevery 97dae0d0a0 feat(jqLite): add contents() 2012-01-25 11:46:35 -08:00
Misko Hevery 84823b2eff feature($exceptionHandler): $exceptionHandler now supports var_args 2012-01-25 11:46:34 -08:00
Misko Hevery 517811764d cleanup(tests): remove unused variables 2012-01-25 11:46:34 -08:00
Misko Hevery 1354718365 chore(jasmine-adapter): upgrade 2012-01-25 11:46:34 -08:00
Kai Groner 56bcc04c54 feat(ng:class): support using map of classnames and conditions
enables <div ng:class="{'hide': !visible, 'warning': isAlert()}"...
2012-01-24 10:28:29 -08:00
Igor Minar b2052d08a1 fix($parse): fixing typos in JS_KEYWORDS 2012-01-23 22:33:28 -08:00
Igor Minar 7da2bdb82a fix(scope): support watching functions
currently we run into infinite digest if a function is being
watched as an expression. This is because we generate bound
function wrapper when the watch is processed via parser.

I'm not too keen on the solution because it relies on the unbound
fn that is being exposed for other reasons, but I can't think
of a better way to deal with this right now
2012-01-23 22:33:28 -08:00
Igor Minar ed78f0d830 chore(log): generic test log service with custom toEquals matcher
- any test that needs a logger can just inject provideLog
- logger has susict api that makes tests more readable
- custom toEquals matcher allows for pretty expectations
2012-01-23 22:33:28 -08:00
Vojta Jina dbffbefb7c refactor($controller): Add $controller service for instantiating controllers
So that we can allow user to override this service and use BC hack:
https://gist.github.com/1649788
2012-01-23 13:11:12 -08:00
Vojta Jina 0196411dbe refactor(scope.$watch): rearrange arguments passed into watcher (newValue, oldValue, scope)
As scopes are injected into controllers now, you have the reference anyway, so having scope as first argument makes no sense…

Breaks $watcher gets arguments in different order (newValue, oldValue, scope)
2012-01-23 11:11:27 -08:00
Vojta Jina 992c790f07 refactor(scope): separate controller from scope
Controller is standalone object, created using "new" operator, not messed up with scope anymore.
Instead, related scope is injected as $scope.

See design proposal: https://docs.google.com/document/pub?id=1SsgVj17ec6tnZEX3ugsvg0rVVR11wTso5Md-RdEmC0k

Closes #321
Closes #425

Breaks controller methods are not exported to scope automatically
Breaks Scope#$new() does not take controller as argument anymore
2012-01-23 11:05:36 -08:00
alkis f5343c9fd3 docs($http): fix missing quote 2012-01-22 00:30:39 -08:00
Igor Minar 0470ff04b4 docs(changelog): clarified breaking changes for 0.10.6 2012-01-19 15:47:55 -08:00
Igor Minar efe33a5e21 docs($http): doc fixes suggested by Gina 2012-01-19 12:39:05 -08:00
Igor Minar 7046d6053d chore(jstd): upgrade JSTD to 1.3.3d 2012-01-19 10:38:26 -08:00
Vojta Jina afc241bd28 docs(inputType): fix small typo 2012-01-19 00:27:32 -08:00
ludicast a507fb7bb3 docs(guide): update angular version in an example 2012-01-18 17:16:27 -08:00
Igor Minar 0ce139c42d chore(release): preparing the 0.10.7 moiré-vision iteration 2012-01-18 17:12:21 -08:00
Igor Minar b00262fffe chore(release): cutting the 0.10.6 bubblewrap-cape release 2012-01-17 13:54:18 -08:00
Igor Minar 3f98d6ac99 docs(*): more docs 2012-01-17 12:19:26 -08:00
Igor Minar 22309c312f fix(docs): disable appcache - causing too much trouble 2012-01-17 12:13:29 -08:00
Igor Minar fcf95a47d1 docs(*): more fixes 2012-01-17 11:23:56 -08:00
Konstantin Stepanov e1e7aca9a6 fix($locationProvider) hashPrefix's getter returned html5Mode + doc fix 2012-01-17 11:21:20 -08:00
Vojta Jina 039041e3ae docs: syntax highlight auto bootstrap code example 2012-01-17 11:00:25 -08:00
Igor Minar 3da441b580 docs(release-notes): 0.10.6 bubblewrap-cape release 2012-01-17 09:49:40 -08:00
Igor Minar f9502d2ad3 fix(docs): temp hack to get appcache properly invalidated 2012-01-17 09:49:39 -08:00
Igor Minar 0356c90af8 chore(jquery): make the license header closure friendly 2012-01-17 09:49:39 -08:00
Igor Minar 0d4def452e fix(Rakefile): rewrite version number for mocks.js 2012-01-17 09:49:39 -08:00
Vojta Jina 897d0f1424 docs(guide): update the diagram 2012-01-17 09:49:38 -08:00
Igor Minar 92af30ce6e docs(*): various doc fixes 2012-01-17 09:49:37 -08:00
Igor Minar 54581d36df fix(e2e $httpBackend): use browser.defer instead of $defer
this is necessary to avoid $apply from within $apply situations
2012-01-16 23:26:44 -08:00
Igor Minar b587091b6e feat(jqLite): added injector() helper method 2012-01-16 02:17:27 -08:00
Vojta Jina c49b8a2db5 fix($location): do not $digest if browser's url change fired within $apply/$digest
Chrome (probably other browsers as well) fires 'hashchange' event synchronously, so if you change raw location from within $apply/$digest, we don't want to $apply twice. (It would throw an exception)
2012-01-14 11:23:12 -08:00
Misko Hevery 5cdfe45aa3 feat(module): add runtime block 2012-01-13 14:28:43 -08:00
Igor Minar 16a40c626f style(*): small fixes 2012-01-13 14:28:21 -08:00
Igor Minar b7f4d8c3c3 fix($http): anonnymous response interceptors should be treated as factories 2012-01-13 14:28:20 -08:00
Igor Minar 939c8e8fac docs($http, $httpBackend): docs docs docs 2012-01-13 14:28:20 -08:00
Igor Minar d2ba4c5170 fix(ngdocs): add '=' to type signatures with optional arguments 2012-01-13 13:53:07 -08:00
Igor Minar 46691c2721 fix($http): remove support for PATCH + better whenXXX, expectXXX api
- there are too many unknowns about PATCH, so I'm dropping its support until we know that this is actually useful
- expectGET, expectHEAD and expectJSON (and the same for whenXXX) should not require response data to be specified
2012-01-13 13:53:07 -08:00
Vojta Jina e7a23e4b65 fix(docs): generate correct ids on h elements to get scrolling working 2012-01-13 01:07:17 -08:00
Vojta Jina 15fd735793 refactor($autoScroll): rename to $anchorScroll and allow disabling auto scrolling (links)
Now, that we have autoscroll attribute on ng:include, there is no reason to disable the service completely, so $anchorScrollProvider.disableAutoScrolling() means it won't be scrolling when $location.hash() changes.

And then, it's not $autoScroll at all, it actually scrolls to anchor when it's called, so I renamed
it to $anchorScroll.
2012-01-13 01:07:12 -08:00
Vojta Jina 985d3d7558 refactor($autoScroll): rename method in test + use $apply instead of $digest 2012-01-13 01:05:24 -08:00
Vojta Jina 249c89c091 fix($autoScroll): scroll even if $location is in html5 mode
+ use autoscroll in docs (ng:include)
2012-01-13 01:01:26 -08:00
Vojta Jina 5164ae545b style(mocks): remove console.log 2012-01-13 00:37:16 -08:00
Misko Hevery e1e0ddb910 docs(inject/module): add documentation 2012-01-12 17:10:48 -08:00
Misko Hevery d648d709f3 refactor(module): strict separation between module-config / app-runtime 2012-01-12 13:40:07 -08:00
Vojta Jina 9a8dbfef51 style(mock): make jslint and igor happier 2012-01-11 22:11:06 -08:00
Vojta Jina 28114de8dc refactor(mock.$httpBackend): split (e2e/unit testing version of $httpBackend mock) 2012-01-11 22:11:01 -08:00
Vojta Jina c6ea1be053 fix(mock.$httpBackend): resetExpectations should not create new array 2012-01-11 11:48:03 -08:00
Misko Hevery 5143e7bf06 feat(module): new module loader 2012-01-10 22:27:00 -08:00
Misko Hevery afd25446d2 feat(ngdocs): support for interface documentation 2012-01-10 22:21:54 -08:00
Misko Hevery 3c3e6980b3 chore(specs.js): remove unused dependency 2012-01-10 22:21:54 -08:00
Misko Hevery e0b4b107ee chore(license): update year 2012-01-10 22:21:54 -08:00
Igor Minar 614fd3d55a fix(ng:repeat): support repeating over array with null
typeof null == 'object', but it doesn't behave like an object
because its properties can't be dereferenced, so we need
to special-case it.

Closes #702
2012-01-10 22:21:53 -08:00
Igor Minar 7146f70636 fix($httpBackend): fix for jsonp requests 2012-01-09 14:38:32 -08:00
Igor Minar 11cb9423a7 chore(docs): disable disqus for localhost
it's just slowing down the test runs and debugging
2012-01-09 13:17:49 -08:00
Igor Minar c76a120bfe fix(nodeserver): add dummy favicon.ico to silence 404s 2012-01-09 13:17:49 -08:00
Igor Minar b8960c3710 chore($http): small $http fixes 2012-01-09 13:17:48 -08:00
Igor Minar 67338ce061 feat($http): turn mock backend into a decorator + e2e testing support
- provider -> decorator
- autoflush + passThrough mode
- fix noop -> angular.noop
2012-01-09 13:17:48 -08:00
Igor Minar 23f8da7cbb feat($http): expose req/resp headers to transform fns 2012-01-09 13:17:48 -08:00
Igor Minar b911e303ec feat($httpBackend): add expect/when shortcut methods 2012-01-09 13:17:48 -08:00
Igor Minar a13b5ed3bc fix($http): fix and cleanup $http and friends
$http:
- use promises internally
- get rid of XhrFuture that was previously used internally
- get rid of $browser.defer calls for async stuff (serving from cache),
  promises will take care of asynchronicity
- fix transformation bugs (when caching requested + multiple request
  pending + error is returned)
- get rid of native header parsing and instead just lazily parse the
  header string

$httpBackend:
- don't return raw/mock XMLHttpRequest object (we don't use it for
  anything anymore)
- call the callback with response headers string

mock $httpBackend:
- unify response api for expect and when
- call the callback with response headers string
- changed the expect/when failure error message so that EXPECTED and GOT
  values are aligned

Conflicts:

	src/service/http.js
	test/service/compilerSpec.js
	test/service/httpSpec.js
2012-01-09 13:17:48 -08:00
Igor Minar 63cca9afbc feat(browser.defer): flush should throw exception when queue is empty 2012-01-09 13:17:48 -08:00
Vojta Jina d47ec772c3 docs(fix): select widget name -> ng:model 2012-01-08 15:06:12 -08:00
Vojta Jina 5c19766063 feat(ng:include): enable/disable scrolling through autoscroll attribute 2012-01-07 00:18:22 -08:00
Vojta Jina f2119c7524 fix($httpBackend): respond 200/404 when on file protocol (fix protocol parsing) 2012-01-06 19:20:29 -08:00
Dhruv Manek 08029c7b72 fix(angular.copy): throw Error if source and destination are identical
Closes #693
2012-01-06 12:19:39 -08:00
Igor Minar 0bf611087b feat(scope): throw exception when recursive $apply 2012-01-06 12:19:39 -08:00
Igor Minar acb4338b70 style(widgetsSpec): ws, unused variables, etc 2012-01-06 12:19:39 -08:00
Igor Minar cd9a7b9608 fix(ng:repeat): support repeating over array with null
typeof null == 'object', but it doesn't behave like an object
because its properties can't be dereferenced, so we need
to special-case it.

Closes #702
2012-01-06 12:19:39 -08:00
Vojta Jina 1dccaaaaa2 chore(readme): add some links and update test commands 2012-01-05 19:54:42 -08:00
Igor Minar 9632f5c1c7 style(q): rename src/Deferred.js to src/service/q.js 2012-01-03 17:48:09 -08:00
Igor Minar bb3be87606 style(q): reorganize the file + drop fallback dependencies 2012-01-03 17:48:09 -08:00
Igor Minar 174952e443 docs(q): documentation for all $q apis 2012-01-03 17:31:23 -08:00
Vojta Jina 6f91ffeb91 style: prefer single quotes + some whitespaces 2012-01-03 15:09:00 -08:00
Vojta Jina c594f75b4c refactor: remove old JSTD assertions
So that we can run the tests even without JSTD :-D
2012-01-03 15:09:00 -08:00
Mark Hansen 50eb7f15b8 docs(scope): fix typo $digest -> $watch 2012-01-03 15:01:34 -08:00
Sean Gilligan 212a6ff29a docs(resource): fix params for non-get actions 2012-01-03 14:57:38 -08:00
Igor Minar 871252ab4c docs(guide): fix $xhr -> $http links 2011-12-07 16:59:06 -08:00
bartes 0c534644bc fix(input): bind inputs to the 'input' event
The input event is fired on all non-ie browsers whenever the contents of an input
field changes. This means that we now support cut&paste via mouse which
was previously unsupported.

IE8 and older don't support this events and IE9 has a problematic
support for it, so we can't rely solely on this event and drop keydown
and change events.
2011-12-07 13:07:20 -08:00
Igor Minar c28662d28d fix(filter): remove the $ prefix from filter service ids 2011-12-07 13:07:19 -08:00
Igor Minar b97c6e5f74 style(scopeSpec): clean up scopeSpec.js 2011-12-07 09:41:09 -08:00
Igor Minar 4e3c05b99e feat(injector): add $provide.decorator 2011-12-07 09:41:08 -08:00
Igor Minar 5e4d59adf0 style(injector): cleanup of InjectorSpec.js 2011-12-07 09:41:07 -08:00
Igor Minar fd38655e6c fix(): use angular.callbacks namespace for jsonp callbacks
Previously we used to put callbacks on the window object, but that
causes problems on IE8 where it is not possible to delete properties
from the window object
2011-12-07 07:54:09 -08:00
Vojta Jina b9001e9147 fix(route): $destroy scope after update and reload
When we update route (changing only search param, no route reload) and then reload (change to different
route), it did not $destroy last scope.
2011-12-06 13:35:05 -08:00
Igor Minar d1e7a5394a docs(form): add docs about form submission 2011-12-06 13:32:49 -08:00
Vojta Jina 2090136dd8 docs(ng:submit): update docs example to not add empty items 2011-12-06 13:07:27 -08:00
Vojta Jina c9f2b1eec5 feat(form): do not prevent submission if action attribute present 2011-12-06 13:07:26 -08:00
Igor Minar 163e05ed36 feat($http): allow interceptors to be services 2011-12-05 23:53:26 -08:00
Igor Minar 2986a09c0d fix(jqLite): JQLiteHasClass should work even when minified
closure compiler is smarter than we expected and drops the unused fn
argument - this breaks the meta-programing logic of jqLite.

The fix special cases JQLiteHasClass since its the only fn that needs
this treatment in a way that is minification-proof.
2011-12-05 14:12:00 -08:00
Igor Minar bb2e7488fa fix($httpBackend mock): getResponseHeader should be case insensitive 2011-12-01 18:21:45 -05:00
Igor Minar 44b2f44f93 fix($resource): forwardport exposing headers from 0.9.19 2011-12-01 16:20:08 -05:00
Igor Minar 1d14760c6d fix(ng:include): prevent race conditions by ignoring stale http callbacks
This fix is similar to what I've done in ng:view, if a new template has been requested before the
callback for the previous template returned, ignore it. Otherwise weird race conditions happen
and users might end up getting the content for the previous include rendered instead of the most
recent one.
2011-11-30 14:49:36 -05:00
Igor Minar baa7af0df0 docs($location): add docs for the $location.search setter 2011-11-30 14:49:36 -05:00
Igor Minar f43c226c67 fix(copy,equals): prevent browser crashes with Scope or Window
Scope and Window instances are special and when copied can crash browser. For this reason
it makes sense to compare them only by identity.
2011-11-30 14:49:36 -05:00
Misko Hevery 0e1fa2aefe feat($interpolate): string interpolation function 2011-11-30 14:49:36 -05:00
Igor Minar 3d0ce0ebe9 feat($location): name the watch function to ease debugging 2011-11-30 14:49:36 -05:00
Igor Minar b00da987a9 scope($digest): add new&old val to the infinite $digest log 2011-11-30 14:49:35 -05:00
Igor Minar 188bdf7768 feat($http): add response interceptors 2011-11-30 14:49:35 -05:00
Igor Minar dbd880cc0a feat($http): add promise support
quite messy, some tests are missing, contains an experimental jasmine DI support)
2011-11-30 14:49:35 -05:00
Igor Minar bf8e0540f8 feat(dump): add support for arrays, functions, errors 2011-11-30 14:49:35 -05:00
Igor Minar 78b6e8a446 feat($parse): add support for transparent evaluation of Promises
Parser now builds expressions that can detect promises and transparently
evaluate them to undefined or the promise value.

If promiseA is resolved with value 'A', then {{promiseA}} evals to 'A';
If promiseA is unresolved, then {{promiseA}} evals to undefined;

Following invocations are supported:

- {{promise}}
- {{promise.futureProp}}
- {{[promise][0]}}
- {{object.promise}}
- {{object[promise]}}
- {{array[promise]}}
- {{fn(promise)}}
- combinations of the above
2011-11-30 14:49:35 -05:00
Igor Minar b656552d68 fix(angular-boostrap): add missing jQuery/jqLite binding 2011-11-30 14:49:35 -05:00
Igor Minar 1cdfa3b960 feat(deferreds/promises): Q-like deferred/promise implementation with a ton of specs 2011-11-30 14:49:03 -05:00
Vojta Jina 16363d8000 refactor(ng:view, ng:include): pass cache instance into $http
Instead of doing all the stuff in these widgets (checking cache, etc..) we can rely on $http now...
2011-11-30 14:49:03 -05:00
Vojta Jina 92995bbce9 fix($http): default json transformation should not crash on angular template
The way we determine whether it's json is lame anyway. We need to change that.
We should probably check the content type header...
2011-11-30 11:17:25 -05:00
Vojta Jina b9707d910e style(): get rid off some jsl warnings 2011-11-30 11:17:25 -05:00
Vojta Jina 5bbd64ac65 feat($http): allow passing custom cache instance per request
You can still use cache: true, which will use $http's default cache.
2011-11-30 11:17:25 -05:00
Vojta Jina caeb1bf899 feat($httpBackend): fix 0 status code when "file" protocol
Browsers return always 0 status code for "file" protocol, so we convert them into 200/404.
2011-11-30 11:17:24 -05:00
Vojta Jina 9b4efa73f9 feat(mock.$httpBackend): say which request was expected when unexpected request error 2011-11-30 11:17:24 -05:00
Vojta Jina 4aaa2f7f6b feat(mock.$httpBackend): verify expectations after flush() 2011-11-30 11:17:24 -05:00
Vojta Jina 6290bd4587 refactor(mock.$httpBackend): rename when().then() to when().respond() 2011-11-30 11:17:24 -05:00
Vojta Jina e9f81b6631 fix(mock.$httpBackend): flush() even requests sent during callbacks 2011-11-30 11:17:23 -05:00
Vojta Jina afbe073121 feat(mock.$httpBackend): add verifyNoOutstandingRequest method
+ rename verifyExpectations to verifyNoOutstandingExpectation
2011-11-30 11:17:23 -05:00
Vojta Jina 7b705df2b7 feat($http): broadcast $http.request event 2011-11-30 11:17:23 -05:00
Vojta Jina a4c8ac7126 feat(mock.$httpBackend): throw when nothing to flush, dump data/headers when expected different 2011-11-30 11:17:23 -05:00
Vojta Jina e3e2e4436e fix($http): add .send() alias for .retry() to get better stack trace on error 2011-11-30 11:17:22 -05:00
Vojta Jina 972c3e9be0 refactor($http): change callback matching mechanism 2011-11-30 11:17:22 -05:00
Vojta Jina feacf608ee fix($resource): to work with $http, $httpBackend services
Breaks Disabling $resource caching for the moment.
2011-11-30 11:17:22 -05:00
Vojta Jina fe633dd0cf fix($http): allow multiple json vulnerability prefixes
We strip out both:
)]}',
)]}'
2011-11-30 11:17:22 -05:00
Vojta Jina fdcc2dbfd3 feat($http): expose pendingRequests and configuration object
- $http.pendingRequests is now an array of pending requests
- each request (its future object) has public property configuration
2011-11-30 11:17:22 -05:00
Vojta Jina 5ad0c7d0e4 feat($httpBackend): extract $browser.xhr into separate service
- remove whole $browser.xhr stuff
- remove whole mock $browser.xhr stuff
- add $httpBackend service + migrate unit tests from $browser
- add temporary API to access $browser's outstandingRequests count
2011-11-30 11:17:22 -05:00
Vojta Jina 540701a8d8 feat(mocks.$browser): add simple addJs() method into $browser mock 2011-11-30 11:17:22 -05:00
Vojta Jina 4d2d70e7fb feat($templateCache): add $templateCache - shared by ng:include, ng:view 2011-11-30 11:17:21 -05:00
Vojta Jina cd28a2e952 feat(mocks.$httpBackend): add $httpBackend mock
$httpBackend mock allows:
- expecting (asserting) requests
- stubbing (responding without asserting)

Add empty $httpBackend service (currently just wrapper for $browser.xhr)
2011-11-30 11:12:14 -05:00
Vojta Jina 59adadca08 feat($http): new $http service, removing $xhr.*
Features:
- aborting requests
- more flexible callbacks (per status code)
- custom request headers (per request)
- access to response headers
- custom transform functions (both request, response)
- caching
- shortcut methods (get, head, post, put, delete, patch, jsonp)
- exposing pendingCount()
- setting timeout
Breaks Renaming $xhr to $http
Breaks Takes one parameter now - configuration object
Breaks $xhr.cache removed - use configuration cache: true instead
Breaks $xhr.error, $xhr.bulk removed
Breaks Callback functions get parameters: response, status, headers
Closes #38
Closes #80
Closes #180
Closes #299
Closes #342
Closes #395
Closes #413
Closes #414
Closes #507
2011-11-30 11:12:14 -05:00
Igor Minar 497839f583 feat($cacheFactory): add general purpose $cacheFactory service 2011-11-30 11:03:42 -05:00
Vojta Jina 5487bdb3d1 feat($browser.xhr): add timeout option to abort request
Timeouted request responds internal status code -1, which should be normalized
into 0 by $xhr.
2011-11-30 11:03:42 -05:00
Vojta Jina 3ae3ccf3da fix($browser.xhr): fix IE6, IE7 bug - sync xhr when serving from cache
IE6, IE7 is sync when serving content from cache.
We want consistent api, so we have to use setTimeout to make it async.
2011-11-30 11:03:42 -05:00
Vojta Jina e9b57f9df8 fix($browser.xhr): respond with internal -2 status on jsonp error
If jsonp is not successfull, we return internal status -2.
This internal status should by normalized by $xhr into 0,
but $xhr needs to distinguish between jsonp-error/abort/timeout (all status 0).
2011-11-30 11:03:42 -05:00
Vojta Jina 45f47ff6cd fix($browser.xhr): change method "JSON" to "JSONP"
Breaks "JSON" xhr method is now called "JSONP"
2011-11-30 11:03:41 -05:00
Vojta Jina 0c8b35681e feat($browser): xhr returns raw request object 2011-11-30 11:03:41 -05:00
Igor Minar a035e88397 docs(guide): fix directives guide docs 2011-11-28 18:04:01 -05:00
Vojta Jina 3548fe3139 feat(service.$autoScroll): scroll to hash fragment
- whenever hash part of the url changes
- after ng:view / ng:include load
2011-11-21 17:49:49 -08:00
Codier 29f9e2665d fix(scope): $watch (and angular.equals) should support NaN values
- since NaN !== NaN in javascript digest can get into an infinite loop
  when model value is set to NaN
- angular.equals(NaN, NaN) should return true since that's what we
  expect when comparing primitives or objects containing NaN values

Previously NaN because of its special === properties was used as the
initial value for watches, but that results in issues when NaN is used
as model value.

In order to allow for model to be anything incuding undefined and NaN we
need to mark the initial value differently in a way that would avoid
these issues, allow us to run digest without major perf penalties and
allow for clients to determine if the listener is being called because
the watcher is being initialized or because the model changed. This
implementation covers all of these scenarios.

BREAKING CHANGE: previously to detect if the listener was called because
the watcher was being initialized, it was suggested that clients check
if old value is NaN. With this change, the check should be if the newVal
equals the oldVal.

Closes #657
2011-11-21 15:43:12 -08:00
Igor Minar 8d1944851d fix(docs): specify disqus_url 2011-11-19 15:42:17 -08:00
TEHEK Firefox 3e1a6688c3 chore(browser): rename Browser.js -> browser.js, BrowserSpec.js -> browserSpec.js
And move them to proper service subfolder...
2011-11-18 12:05:55 -08:00
Misko Hevery aba9bb2a24 fix(input): treat all not number model as blank 2011-11-15 11:47:23 -08:00
Misko Hevery 5857c44e0c fix(radio): fix binding to value={{exp}} 2011-11-15 11:44:36 -08:00
Misko Hevery 8adae2fdf2 refactor(injector): removed loadModule/ng:module
- added module property to doc:example
2011-11-14 20:31:21 -08:00
Misko Hevery 955551141d style(angularPublic): move public export definition to AnuglarPublic.js 2011-11-14 20:31:21 -08:00
Misko Hevery 94e1a07b28 doc(rename): NG_LOCALE -> ngLocale 2011-11-14 20:31:20 -08:00
Misko Hevery ac73e8877e add(doc): added missing angular.module.ng namespace 2011-11-14 20:31:19 -08:00
Misko Hevery e88dfb734a refactor(injector): $injector is no longer a function.
- $injector('abc') -> $injector.get('abc');
- $injector(fn) -> $injector.invoke(null, fn);
2011-11-14 20:31:19 -08:00
Misko Hevery 8d6dc0b9a7 del($eager): removed the support for $eager services 2011-11-14 20:31:19 -08:00
Vojta Jina acbd7cdf32 style(docs): make jslint happy - fix some warnings 2011-11-14 20:31:19 -08:00
Misko Hevery 035c751076 fix(doc) cleanup all dev guide doc link warnings 2011-11-14 20:31:18 -08:00
Misko Hevery 186a840cd3 feat(bootstrap): added angular.bootstrap method 2011-11-14 20:31:18 -08:00
Misko Hevery b09595a3c1 fix(doc) cleanup all api doc link warnings 2011-11-14 20:31:18 -08:00
Misko Hevery f6d98f1472 fix(doc): make output less noisy 2011-11-14 20:31:17 -08:00
Vojta Jina 5279de0e70 fix($location): links without path segment should not change the path
Closes #648
2011-11-14 20:31:17 -08:00
Misko Hevery 8fe77b69e8 refactor(docs): improved the visual rendering of the documentation pages 2011-11-14 20:31:17 -08:00
Misko Hevery 1cc6bee4ce docs(browser): moved and migrate browser removed unneeded files. 2011-11-14 20:31:17 -08:00
Misko Hevery a8aa193c6b doc($rootScope): scope documentation changes 2011-11-14 20:31:17 -08:00
Misko Hevery e45b013143 doc(locale): migrate docs to new format 2011-11-14 20:31:16 -08:00
Misko Hevery ea18f4548d doc($formFactory): migrated the $formFactory documentation 2011-11-14 20:31:16 -08:00
Misko Hevery 57c37a21d1 doc(service): update docs for the moved services 2011-11-14 20:31:16 -08:00
Misko Hevery 74fac45f48 doc($filter): added $filter documentation 2011-11-14 20:31:16 -08:00
Misko Hevery f0fa5e6376 doc(AUTO, NG_MOCK): Documenting the AUTO and NG_MOCK module 2011-11-14 20:31:16 -08:00
Misko Hevery c283bf6035 refactor($location): merged $locationConfig service into $locationProvider 2011-11-14 20:31:15 -08:00
Misko Hevery b3c17f3fdc chore(scope): remove $service 2011-11-14 20:31:15 -08:00
Misko Hevery 9c06394376 chore(scenario tests): make scenario tests pass again 2011-11-14 20:31:15 -08:00
Misko Hevery 085e3c611f new(directive): added ng:module directive for loading modules 2011-11-14 20:31:15 -08:00
Misko Hevery 4b35a59c6a refactor(scenario): fix scenario bootstrap & publish injector for inspection 2011-11-14 20:31:14 -08:00
Misko Hevery 7cb03c5ab9 chore(angular): clean up unused constants 2011-11-14 20:31:14 -08:00
Misko Hevery 78c7066422 refactor(angular): isDate / isArray test iframe independent fix 2011-11-14 20:31:14 -08:00
Misko Hevery 923da410bd fix(i18n): updated the way locale is being registered 2011-11-14 20:31:14 -08:00
Misko Hevery a87f2fb9e4 refactor(mock): moved mocks into its own module 2011-11-14 20:31:14 -08:00
Misko Hevery c27aba4354 refactor(api): remove type augmentation
BREAK:
  - remove angular.[Object/Array/String/Function]
  - in templates [].$filter(predicate) and friends need to change to [] | filter:predicate
2011-11-14 20:31:14 -08:00
Misko Hevery dd9151e522 refacter(filters): convert filter/limitTo/orderBy from type augmentation to filters 2011-11-14 20:31:13 -08:00
Misko Hevery 3972d2a89b refactor(json): break dependence on api.js 2011-11-14 20:31:13 -08:00
Misko Hevery cb6f832f38 refactor(filter): filters are now injectable and services
BREAK:
 - removed CSS support from filters
2011-11-14 20:31:09 -08:00
Misko Hevery 6022f3df39 move(filters): appease the History God 2011-11-14 16:39:34 -08:00
Misko Hevery 7c11531902 refactor(parser): turn parser into a service (keep compatibility hack) 2011-11-14 16:39:33 -08:00
Misko Hevery c6d2549a52 fix(JSON): json date parsing same native/ngular parser 2011-11-14 16:39:33 -08:00
Misko Hevery bee6060e4b move(parser): appease the History God 2011-11-14 16:39:33 -08:00
Misko Hevery 16597e8b52 refactor($service): removed almost all references to scope.$service
- still need to remove from factory
2011-11-14 16:39:33 -08:00
Misko Hevery f684f20c99 cleanup(parser): removed unused method 2011-11-14 16:39:33 -08:00
Misko Hevery bd04316a89 refactor(services): migrate angular.service -> module 2011-11-14 16:39:33 -08:00
Misko Hevery ed36b9da3b refactor(injector): switch to injector 2.0 introduce modules 2011-11-14 16:39:32 -08:00
Misko Hevery c925f8a657 new(injector): new injector v2.0
- not connected to keep the CL small
2011-11-14 16:39:32 -08:00
Misko Hevery 4c10d33eb4 refactor(api): cleaned up the externalization of angular API methods 2011-11-14 16:39:32 -08:00
Misko Hevery 9062996a0e feat(injector): support $inject(fn($service){}) function invocation 2011-11-14 16:39:32 -08:00
Misko Hevery 411c1ae77e feat(injector): support ['$service', function($service){}] annotations for function invocation. 2011-11-14 16:39:32 -08:00
Misko Hevery d12df0d360 refactor(compiler) turn compiler into a service
BREAK
- remove angular.compile() since the compile method is now a service and needs to be injected
2011-11-14 16:39:32 -08:00
Misko Hevery d9b58f23f6 move(compiler): appease the History God
-	renamed:    src/Compiler.js -> src/service/compiler.js
-	renamed:    test/CompilerSpec.js -> test/service/compilerSpec.js
2011-11-14 16:39:32 -08:00
Misko Hevery 03dd8c4f4c feat(injector): Service look up failures include dependency path 2011-11-14 16:39:32 -08:00
Misko Hevery 48697a2b86 refactor(injector): turn scope into a service
- turn scope into a $rootScope service.
- injector is now a starting point for creating angular application.
- added inject() method which wraps jasmine its/beforeEach/afterEach,
  and which allows configuration and injection of services.
- refactor tests to use inject() where possible

BREAK:
- removed angular.scope() method
2011-11-14 16:39:31 -08:00
Misko Hevery 93b777c916 move(scope): appease the History God
-	renamed:    src/Scope.js -> src/service/scope.js
-	renamed:    test/ScopeSpec.js -> test/service/scopeSpec.js
2011-11-14 16:39:31 -08:00
Vojta Jina 5c70ff72e2 style(docs): make jslint happy - fix some warnings 2011-11-13 16:40:31 -08:00
Vojta Jina 5e663c3dc7 fix(docs.guide): fix $location example 2011-11-13 16:40:31 -08:00
Vojta Jina 260725efcd feat(docs): allow examples with hidden source code 2011-11-13 16:40:31 -08:00
Vojta Jina 4afad1da29 feat(docs): allow custom attributes on <doc:source>
Allow any attributes, not only jsfiddle...
2011-11-13 16:40:31 -08:00
Dhruv Manek eb01fe593d feat(jquery): upgrade to jQuery 1.7
no breaking changes AFAICT
2011-11-13 16:30:21 -08:00
Misko Hevery fc7834f9ac cleanup(parser): remove unused method 2011-11-11 13:04:26 -08:00
Misko Hevery e4303a1f3a chore(test): remove stale bit-rotten code
- deleted:    test/manual.html
2011-11-09 08:54:04 -08:00
Igor Minar 1e00db8daa fix(directives): make directive names case-insensitive
+ tests
+ added docs for angular.directive
2011-11-08 21:44:46 -08:00
Igor Minar aaa0179758 chore(release): preparing the 0.10.6 bubblewrap-cape iteration 2011-11-08 16:39:19 -08:00
Igor Minar f5ef3724ce chore(release): cutting the 0.10.5 steel-fist release 2011-11-08 04:29:07 -08:00
Igor Minar e60601be4f docs(changelog): release notes for 0.10.5 steel-fist 2011-11-08 04:29:07 -08:00
Dhruv Manek e2663f62b0 feat(ng:style): compatibility + perf improvements
- better compatibility with 3rd party code - we clober 3rd party
  style only if it direcrtly collides with 3rd party styles
- better perf since it doesn't execute stuff on every digest
- lots of tests
2011-11-08 02:25:22 -08:00
Igor Minar 9f9ed4c5ff docs(ng:bind-attr): improve examples 2011-11-08 02:23:51 -08:00
Igor Minar 66fc268aeb docs(css): fixing positioning of disqus comments
float:left causes the comments to shift to the left when content is longer
than the sidebar
2011-11-05 22:30:50 -07:00
Vojta Jina 1d966f8a65 style(angularFiles): just missing semi-colon and extra comma 2011-11-01 14:14:52 -07:00
Vojta Jina ddf6f1143f test(mocks): test mocks with compiled angular
Unfortunately, there people in our team (me), who are not able to use angular.* namespace prefix
when writing angular-mocks code, so we need to test it...
2011-10-31 18:22:38 -07:00
Vojta Jina 2636105c5e feat(matchers): extract jasmine matchers into separate file for future reuse
Prefix all used functions with angular.* so that they can be used with compiled angular as well...
2011-10-31 18:22:21 -07:00
Igor Minar c0b557a96c test(scope): infinite digest test should pass on all browsers
Different browsers print function body differently, and best of all IE doesn't have
function.name property.
2011-10-31 12:46:12 -07:00
Igor Minar 84873e7f4e fix(angular-bootstrap): fix boostrap scripts that broke w\ 5a2dcb9a
Commit 5a2dcb9a doesn't properly modify angular-boostrap.js.

This fix resolves issues and makes both the regular and scenario
version of angular-boostrap.js functional.
2011-10-31 11:34:25 -07:00
Igor Minar 95fdb1231f chore(watchr): watchr scripts should output logs to terminal
Having the extra level of indirection by using logs/*.log file
only makes it more difficult to use these scripts. After this
change it will be enough to just start the watchr and watch the
terminal it was started in.
2011-10-31 11:34:25 -07:00
Igor Minar ef875ad0cf feat(scope): better logging of infinite digest error
Feedback team has often problems debugging inifinite digest errors, this change
should reveal info about what watchers are causing the infinite loop
2011-10-31 11:34:25 -07:00
Igor Minar 615841a5d3 style(widgets): fix typo in a spec comment 2011-10-31 07:19:33 -07:00
Vojta Jina 7d0c256ecd docs(jqlite): add missing methods 2011-10-30 22:31:03 -07:00
Igor Minar 6cbe096dbf feat(docs): remove the Report Issue link - duplication of disqus 2011-10-30 22:27:25 -07:00
Igor Minar 21602b5cd6 fix(docs): special case url generation for index pages 2011-10-30 22:27:25 -07:00
Igor Minar 4ae671ac88 fix(docs): increment load counter only when a valid page is requested 2011-10-30 22:27:25 -07:00
dandoyon 28ed5ba465 feat(docs): disqus integration
- add style for disqus threads in css
- add loadDisqus method to be called afterPartialLoaded
- add div container for disqus threads
2011-10-30 22:27:25 -07:00
Igor Minar 02dc81bae0 fix(css): ng:form should always be a block element 2011-10-30 22:26:32 -07:00
Igor Minar 445680f601 fix(nodeserver): properly escape all, not just first char 2011-10-27 08:44:14 -07:00
Vojta Jina bf729d550b feat(docs): Add scenario runner into dev guide
And update the link in the tutorial as well...
2011-10-26 15:58:59 -07:00
Vojta Jina dc8ffa51b7 fix(scenario.dsl): Fix dsl for $location
New $location does not have hashSearch, hashPath.
The old dsl was mixing $location / window.location so this solves the problem as well...
2011-10-26 15:58:59 -07:00
Igor Minar d7ba5bc83b feat(bootstrap): drop angular.js file name restrictions for autobind
The last script element in the dom is always us if the script that
contains angular is loaded synchronously.

For async loading manual bootstrap needs to be performed.

Close #621
2011-10-26 12:57:15 -07:00
Igor Minar 950d02b4d4 fix(docs): remove unused $browser dependency 2011-10-26 12:57:14 -07:00
Igor Minar 578e38e0af fix(example): fixes for personalLog e2e tests
Looks like this got broken with scope rewrite.
2011-10-26 12:57:14 -07:00
Igor Minar af7c51ee1d style(Angular.js): various code style fixes 2011-10-26 12:57:14 -07:00
Igor Minar 25d1822bd8 style(HashQueueMap): fixing a typo in the comment 2011-10-26 12:54:00 -07:00
Igor Minar 3945f884c5 fix(ng:repeat) with array ignore properties not representing array elements
Along the way I also changed the repeater impl to use for loop instead
of for in loop.

Iteration over objects is handled by creating an array of keys, which is
sorted and this array then determines the order of iteration over an
element. This makes repeating over objects deterministic and
cross-browser compatible.
2011-10-26 12:54:00 -07:00
Igor Minar d5ccabce60 fix(ng:view): ignore stale xhr callbacks
A lot of badness happens when we don't ignore stale xhrs. These
raceconditions are only apparent when user clicks through the app very
quckly without waiting for routes to fully load.

Closes #619
2011-10-26 12:15:07 -07:00
Igor Minar bb948176aa test(ng:view): spec cleanup
- remove optional controller definition from specs
- remove extranious digest calls
2011-10-26 12:02:30 -07:00
Dhruv Manek 163c799eff fix(angular.widget): Allow widgets to be styled in IE8 and below
Closes #584
2011-10-24 23:28:36 -07:00
Vojta Jina 7da70af1ae fix(scenario): Change title to "AngularJS" 2011-10-24 14:03:50 -07:00
Igor Minar 836e4c1428 chore(release): preparing the 0.10.5 steel-fist iteration 2011-10-24 09:16:33 -07:00
Igor Minar eabedba34d chore(release): cutting the 0.10.4 human-torch release 2011-10-22 21:39:39 -07:00
Igor Minar b4add97c17 docs(changelog): update changelog with 0.10.4 release notes 2011-10-22 21:39:39 -07:00
Igor Minar bacc31bea9 fix(defer.cancel): should return false instead of undefined 2011-10-22 21:32:48 -07:00
Igor Minar ad90c3574f feat($defer): add $defer.cancel
This functionality was previously available only as obscure $browser.defer.cancel.

I also added docs and tests and fixed an issue in .defer.cancel mock.
2011-10-22 21:32:48 -07:00
Igor Minar e28171d5e4 fix(docs): key-binding used old scope apis 2011-10-22 21:32:48 -07:00
Igor Minar ce73ed091b feat(docs): add "Loading..." notification 2011-10-22 21:32:47 -07:00
Igor Minar 90ac8d57b0 fix(docs): update page title only when content loads 2011-10-22 21:32:47 -07:00
Igor Minar 6eb1179505 style(docs): change "this" to "scope" in the controller 2011-10-22 21:32:47 -07:00
Vojta Jina 9b85757102 fix($location): rewrite links with nested elements
For example:
<a href="some/link">inner <span>text</span></a>

If you click on "text", then the span element is event.target, so we need to traverse the DOM.
2011-10-22 15:35:18 -07:00
Igor Minar c6c3949b14 feat(filter.date): use mediumDate as default
Breaking change!

Previously the default was fullDate.
2011-10-20 16:51:28 -07:00
Igor Minar e175db37c6 fix(date filter): default to fullDate format
The browser's behave inconsistently, so we should just stick to one format
when the format is not specified by the developer

Closes #605
2011-10-20 16:51:28 -07:00
Igor Minar f38010d3a2 fix(compiler): revert 8611ebe6 - calling \$digest after linking
Change introduced by me in 8611ebe6 results in considerable inefficiencies when the compiler
and linker is used from within a widget, in which case, we call $digest unnecessary since it
will be called by the $apply which called the directive/widget in the first place.

There are only two places when the extra $digest call can be useful - when manually bootstrapping
the app or in tests. However even in tests this behavior can result in unwanted results (especially
when ng:controller is involved). So it is better to leave it for the developer to call $digest
when it is really needed.
2011-10-20 15:51:14 -07:00
Misko Hevery 7fc18b263d fix(radio): allows data-binding on value property. Closes#316 2011-10-20 11:30:40 -07:00
Igor Minar fabc9f77a3 feat(sanitizer): add html5 elements to the whitelist
Closes #89
2011-10-20 09:44:52 -07:00
Igor Minar c17c731fdc style(select): cleaning up select.js 2011-10-19 22:52:14 -07:00
TEHEK Firefox 3692885810 fix(ng:options): compile null/blank option tag
Fixes #562
2011-10-19 22:52:14 -07:00
Igor Minar 5d43439dbe fix(ng:pattern): correctly parse out inlined regexp 2011-10-19 21:52:20 -07:00
Igor Minar a46f2a0db3 docs(textarea): add docs for angular.widget.textarea 2011-10-19 16:49:34 -07:00
Igor Minar 3217a249e1 style(input): fix style violations in the input.js file 2011-10-19 16:49:34 -07:00
Konstantin Stepanov 78f394fd17 feat(input): add ng:minlength and ng:maxlength validation
notes(igor): I also e2e tests and refactorred the e2e test example to be
more clear about what is a variable and what is an html/framework api.
2011-10-19 16:49:20 -07:00
Konstantin Stepanov e82e64d57b fix(input): recognize 'password' as an html input type 2011-10-19 10:36:36 -07:00
Vojta Jina 8978e066b5 fix(gen-docs): require files without touching PATH
So that it works on latest revision of node...
New version of Node (v0.5.x) does not support require.paths.push().
2011-10-18 22:23:52 -07:00
Igor Minar 833eb3c844 fix(ng:repeat): repeater should ignore $ and $$ properties 2011-10-18 17:27:43 -07:00
Igor Minar 07926ff1ef chore(version.yaml): add missing snapshot version suffix 2011-10-18 17:25:10 -07:00
Igor Minar e801faba2e chore(jstd adapter): switch to our version with backported fixes
sha of the version: da92db714142b49f9cf61db664e782bb0ccad80b
2011-10-18 16:21:52 -07:00
TEHEK Firefox ee6af9a978 fix(ng:options): select correct element when '?'-option was previously selected
Closes #599
2011-10-18 14:02:54 -07:00
Igor Minar 74379df6c4 chore(release): preparing the 0.10.4 human-torch iteration 2011-10-14 15:29:17 -07:00
Igor Minar fe65dd926c chore(release): cutting the 0.10.3 shattering-heartbeat release 2011-10-14 08:31:39 -07:00
Igor Minar 669b53ede2 fix(docs): fix jsfiddle integration
this got accidentally messed up during the forms refactoring and mass renaming
2011-10-14 08:31:00 -07:00
Igor Minar b0c3f28e8f docs(forms): fix devguide forms example code 2011-10-14 08:30:02 -07:00
Igor Minar 9810dc0993 docs(cookbook): disable jsfiddle for deeplinking example
it uses extra resources, so it won't work on fiddle
2011-10-14 08:29:33 -07:00
Vojta Jina ab5df20dfa chore(libs): update libs (jasmine, jstd, jasmine-jstd adapter) 2011-10-13 17:36:11 -07:00
Igor Minar d83a92c121 fix(checkbox): prefix true-value & false-value with ng: 2011-10-13 17:35:00 -07:00
Igor Minar d0425de29e chore(release): preparing release notes for 0.10.3 2011-10-13 16:54:30 -07:00
Igor Minar ad5e42cf82 docs($location): Html5 -> HTML5 2011-10-13 14:42:49 -07:00
Igor Minar 9ed1126adb docs($location): update replace() docs 2011-10-13 14:37:37 -07:00
Igor Minar 7a19eb84aa docs($location): fix $config -> $locationConfig in docs 2011-10-13 14:07:48 -07:00
Igor Minar 718741acab chore(logo): add hi-res ng logo 2011-10-13 13:44:38 -07:00
Vojta Jina ec8bb675b4 fix(docs): set proper base href when hashbang url requested 2011-10-13 11:10:20 -07:00
Vojta Jina 8e32f3fd35 fix(nodeserver): docs rewriting
There can be url /api which does not end with / and we want to rewrite this url as well...
2011-10-13 11:10:20 -07:00
Vojta Jina 02332107e5 feat(nodeserver): if index.html exists, serve it instead of directory listing 2011-10-13 11:10:20 -07:00
Vojta Jina afc81b554e fix($location): do not rewrite link when meta key pressed 2011-10-13 11:10:19 -07:00
Vojta Jina 26e8ab3693 feat(scenario): allow key pressing when triggering browser event
Add parameter to our browserTriger function to allow specifying which keys are pressed.

Note, this does not work on IE<9 !
2011-10-13 11:10:19 -07:00
Igor Minar 28ccc76aa1 docs(dev_guide.bootstrap.auto_bootstrap): fixing a typo 2011-10-12 23:04:48 -07:00
Igor Minar b3c4cb7cff docs(*): remove @workInProgress from everywhere
it's not useful any more and it only makes the docs look ugly
2011-10-12 23:04:48 -07:00
Misko Hevery 4af4378b11 fix(forms): broken tests on jQuery and ie8&9 2011-10-12 23:04:48 -07:00
Igor Minar 8611ebe6a0 fix(compiler): linking function should call $digest
The linked scope should be $digest-ed but only if a $digest isn't
already running on it.
2011-10-12 23:04:48 -07:00
Igor Minar 8f46a3c9ac fix(jqLite): attr for boolean attribute should lowercase value 2011-10-12 23:04:47 -07:00
Igor Minar 66fdb36ecb refactor(ng:bind-attr): simplify impl by leveraging jquery 2011-10-12 23:04:47 -07:00
Igor Minar f0f5ffa9aa test(jstd-config): add widget specs to jsTestDriver-jquery.conf 2011-10-12 23:04:47 -07:00
Igor Minar 2bc7afd3ba fix(ng:class): ignore undefined or NaN classnames 2011-10-12 23:04:47 -07:00
Igor Minar a4b45397e0 docs(forms): add ng:change docs and other fixes 2011-10-12 11:49:42 -07:00
Igor Minar de4e06ed73 test(checkbox): add test for ng:change 2011-10-12 11:11:10 -07:00
Misko Hevery fd822bdaf9 chore(formating): clean code to be function() { 2011-10-11 11:01:46 -07:00
Misko Hevery 4f78fd692c feat(forms): new and improved forms 2011-10-11 11:01:45 -07:00
Misko Hevery df6d2ba326 style(examples): clean up dead examples 2011-10-11 10:53:07 -07:00
Misko Hevery ccda436f94 style(.gitignore) added IDEA 2011-10-11 10:53:07 -07:00
Misko Hevery e86c435349 refactor(bindings): remove the decoration of the DOM with errors.
Only $exceptionHandler gets notified now.
2011-10-11 10:53:07 -07:00
Misko Hevery 1942861472 refactor(hover): delete hover service 2011-10-11 10:53:06 -07:00
Misko Hevery b96e978178 fix(jqlite): removeClass would clobber class names 2011-10-11 10:53:06 -07:00
Misko Hevery bda2bba2be feat(jqlite): added .inheritedData method and $destroy event.
- refactored .scope() to use .inheritedData() instead.
- .bind('$destroy', callback) will call when the DOM element is removed
2011-10-11 10:53:05 -07:00
Misko Hevery ca08c004c8 feat(jqlite): support required as a no-value attribute 2011-10-11 10:53:05 -07:00
Misko Hevery 25a62b58db refactor(injection) infer injection args in ng:controller only
Because only controllers don't have currying, we can infer its arguments, all other APIs needing currying, automatic inference complicates the matters unecessary.
2011-10-11 10:53:04 -07:00
Misko Hevery 97e3ec4d1b style(gitignore): added xproject to ignore list 2011-10-11 10:53:04 -07:00
Misko Hevery 75f11f1fc4 feat(ng:repeat) collection items and DOM elements affinity / stability 2011-10-11 10:53:04 -07:00
Misko Hevery e134a8335f fix(filter): make json filter ignore private properties 2011-10-11 10:53:03 -07:00
Igor Minar 8ee32a75f0 chore(release): prepare the 0.10.3 shattering-heartbeat iteration 2011-10-10 11:23:08 -07:00
Igor Minar f6a8ad87ee chore(release): cutting the 0.10.2 sneaky-seagull release 2011-10-08 09:18:19 -07:00
Igor Minar 7e6ff401b8 docs(changelog): release notes for 0.10.2 sneaky-seagull 2011-10-08 09:15:10 -07:00
Dhruv Manek 7aeb6a24f7 fix(docs): rename doc dev_guide.templates.css to dev_guide.templates.css-styling
Closes #580
2011-10-07 18:20:20 -07:00
Dhruv Manek e1ecc34edd fix(parser): Fix short circuit of logical AND and OR operators
Closes #433
2011-10-07 16:01:09 -07:00
Misko Hevery 29d36e94e1 feat(gdocs): better error handling 2011-10-05 14:19:33 -07:00
dandoyon 091c173632 docs(started): fixing pluralization 2011-10-05 13:47:43 -07:00
TEHEK Firefox c115fa9924 fix($limitTo): properly handle excessive limits
`angular.Array.limitTo`'s  result should not exceed original input array size

Closes #571
2011-10-05 11:01:32 -07:00
Igor Minar b7a7fc7065 doc($log): fix the $log service example
is no longer auto-published on the root scope, so we need to publish
it via a controller
2011-09-29 03:21:24 +02:00
Igor Minar 21b2a5bd21 chore(directives): add a todo for ng:style 2011-09-28 23:57:01 +02:00
Igor Minar ca1e45beaf fix(jqLite): css should convert dash-separated properties to camelCase
this fix is needed for Firefox or other browsers that strictly follow
dom/css spec which states that element.style should make properties
available in camelCased form.

Closes #569
2011-09-28 23:57:00 +02:00
Igor Minar 084b83ffa9 test(matchers): add toBeOneOf matcher 2011-09-27 21:48:47 +02:00
Marcello Nuccio bf5e5f7bc9 fix($resource): action defaults should override resource defaults
defaults definned per action should take precedence over defaults
defined for the whole resource.

This is potentialy a BREAKING CHANGE in case someone relied on the buggy
behavior.
2011-09-27 00:44:10 +02:00
Igor Minar 2e9fed7b6c fix(e2e): add index-nocache.html to run e2e tests without cache
using appcache while running e2e tests was causing the following
problems:
- Safari would occasionally reload the app (as a result of the appcache
  refresh) during the angular.validator.asychronous test, which would
  result in test failure and false positivy.
- Firefox6 would run the tests very slowly, disabling the cache resolved
  the latency issues
- Sometimes tests would run with stale code pulled from cache, which
  would result in flaky tests.
2011-09-26 23:51:55 +02:00
Igor Minar ea3228e311 fix(scenario): workaround for FF6 dispatchEvent issue #684208 2011-09-26 23:51:54 +02:00
Igor Minar 2eb49147d6 Revert "fix(scenario): temporary fix for FF6"
This reverts commit aac68bf2ba.
2011-09-26 23:51:54 +02:00
Vojta Jina 13f92de624 feat(docs): use html5 history api for all routing in the docs app
- Configure our docs app to use new $location with html5 history api!

- Update simple node web server to serve index.html for all links
  (rewritting).

- Update .htaccess file to serve index.html for all links (rewritting).

- At runtime determine the base href path and attach it to the DOM. We
  needed the absolute URL to get all browsers to work well.

- Because of the above, we also need to dynamically determine all needed
  js/css resources and add them to the DOM. This was needed because FF6
  would eagerly fetch resources with wrong URL since the base element is
  added to the dom at runtime.

- All content html files were moved to the partials directory, because
  with the new html5 urls it was impossible to tell if request for
  http://domain/api/angular.filter.html was an html5 url for the html
  filter doc page, or an xhr/appcache request for the content html file
  for the html filter.

f
2011-09-26 23:51:53 +02:00
Igor Minar 2bc39bb0b4 fix($route): fix regex escaping in route matcher 2011-09-21 13:47:17 +02:00
Igor Minar 62ae7fccbc fix(angular-mocks): fix .defer.cancel when i=0 2011-09-16 14:18:45 +02:00
Igor Minar 3ace81b92a fix(e2e tests): use prop() instead of attr() and quote attributes
Because of changes in jQuery, we need to use element().prop() instead of element().attr() to retrieve className and other element properties.

Additionally all attribute selectors (e.g. input[name=value]) must have value quoted if it contains dots (".").
2011-09-16 02:44:35 +02:00
Igor Minar 9acf45127e fix(scenarioRunner): navigateTo should use prop('contentWindow')
... instead of attr('contentWindow')
2011-09-16 02:44:35 +02:00
Igor Minar 6883e8c7a0 feat(scenarioRunner): adding support for element().prop()
since jQuery 1.6.4 attr() focuses only on work with element attributes and doesn't deal well with element properties, so adding prop() support is required for getting many e2e tests to pass after upgrading the runner to jQuery 1.6.4.
2011-09-16 02:44:34 +02:00
Igor Minar 7ae536d053 fix(specs): various fixes to get IE8+jquery unit tests green 2011-09-16 02:44:33 +02:00
Igor Minar 2170c06924 fix(specs): fix jQuery to jqLite binding on IE8
It appears that this whole time all IE8 unit tests ran only with jqLite. Due to a weird bug in IE[1], we never overwrote jqLite implementation with jQuery, so the tests ran with our jqLite instead.

This affected only IE8 (and likely older) and only in unit testing mode. angular.js - the built artifact binds to jQuery just find.

[1] https://plus.google.com/104744871076396904202/posts/Kqjuj6RSbbT
2011-09-16 02:44:33 +02:00
Igor Minar 0e5a24c584 fix(specs): jQuery now returns attr name instead of true/false for special attrs
for special attrs like 'checked' or 'multiple', jquery now returns the name or undedefined.

e.g. foo.attr('checked') => 'checked' || undefined

The solution is a combination of updating our tests as well as switching
over to prop() instead which properly returns true/false
2011-09-16 02:44:32 +02:00
Igor Minar 4e8f0d6e9f fix($location) $location specs must unbind document listener
link rewriting used in html5 mode on legacy browsers binds to document.onClick - we need to destroy this listener after each test to prevent test collisions (global state is evil).
2011-09-16 02:44:31 +02:00
Igor Minar f9b6b61468 fix(scenario dsl): jQuery getters must have no value
jQuery now requires getter methods to have no value at all -
they do arguments.length check to identify getters vs setters.
2011-09-16 02:44:31 +02:00
Igor Minar 555f415290 fix(ng:options): fix selecting options
Contains 3 fixes:

- the internal model was by mistake using "checked" property instead of
  "selected"
- use jqLite.prop() to set 'selected' property
- added inChangeEvent check - we should not interfere with the browser
  selecting elements when not necessary
2011-09-16 02:44:30 +02:00
Igor Minar 3800d17703 feat(jqLite): add prop() support
since jQuery 1.6.4 prop() became very important because attr() does't have access to certain properties any more (e.g. className), so I'm adding it to jqLite as well so that jqLite preserves the feature-set it had before the jQuery upgrade.
2011-09-16 02:44:30 +02:00
Igor Minar 009059dd1b fix(jqLite): make css() on IE8 behave the same way as jQuery 1.6.4 2011-09-16 02:44:29 +02:00
Igor Minar 6b7ddf414d feat(jqLite): add support for unbind()
supports these invocation types:

- foo.unbind();
- foo.unbind('eventType');
- foo.unbind('eventType', fn);

more info: http://api.jquery.com/unbind/
2011-09-16 02:44:29 +02:00
Igor Minar 8259f10138 fix(jqLite): make attr() compatible with jQuery 1.6.4
The behavior of attr() getter and setter changed in jQuery 1.6 and now they treat element properties and attributes as two different things, but in order to not break everyone there is a partial backwards compatibility for checking and updating element properties as well. see http://api.jquery.com/prop/ for more info.
2011-09-16 02:44:28 +02:00
Igor Minar ab407de54d fix(jqLiteSpec): jQuery's css() getter works only for valid rules
foo.css('bogus', 'value')
foo.css('bogus') => null

so I had to change all tests to use valid css rules
2011-09-16 02:44:28 +02:00
Igor Minar 0d7fe97aff fix(jqLite): attr() should not special-case 'class' attribute
since jQuery 1.6 'class' is not treated specially, so we have to revert this fix and use className in tests instead
2011-09-16 02:44:28 +02:00
Igor Minar a2a830e227 feat (jquery): upgrade everything to jQuery 1.6.4
Closes #556
2011-09-16 02:44:27 +02:00
Igor Minar 8336f3f0ba fix(angular-mocks): fix forEach -> angular.forEach in $browser.defer.cancel 2011-09-16 01:39:03 +02:00
Di Peng e14ac2c3b0 style(bootstrap): fix some missing spaces 2011-09-13 01:02:23 +02:00
Di Peng a13653c814 refactor(angular): externalize script load order into JSON
- move all script load order into angularFiles.js
- rakefile and angular-bootstrap.js use angularFiles.js to get script orders
- gen_jstd_configs.js uses angularFiles.js to generate various jstd config files
- run gen_jstd_configs.js whenever we run server.sh

Closes #470
2011-09-13 01:02:22 +02:00
Igor Minar 8017340cd1 chore(version): preparing the 0.10.2 sneaky-seagull iteration 2011-09-12 19:23:37 +02:00
Igor Minar 17d1aef66a chore(release): cutting the angular 0.10.1 inexorable-juggernaut release 2011-09-09 01:01:46 -07:00
Igor Minar 1856f62cb1 docs(changelog): release notes for angular 0.10.1 inexorable-juggernaut 2011-09-09 01:01:05 -07:00
Kai Groner 7e1f364177 fix($location): Use encodeUriQuery instead of escape
Closes #492
2011-09-08 23:00:59 +02:00
Vojta Jina aac68bf2ba fix(scenario): temporary fix for FF6
https://bugzilla.mozilla.org/show_bug.cgi?id=684208
2011-09-08 23:00:59 +02:00
Vojta Jina 4b4292edb8 style: fix some missing semi-colons and spaces, typos 2011-09-08 23:00:59 +02:00
Vojta Jina 292d5d1421 refactor($route): remove some odd code and rename allowReload to forceReload 2011-09-08 23:00:59 +02:00
Vojta Jina 66dec77555 fix(scenario): do not navigate if click event was cancelled
This is jQuery incompatible hack.
But we were doing monkey patching there anyway...

`$(...).trigger('click')` returns an array of return values, so that scenario
runner knows, whether the event default action was cancelled.

Without this fix, scenario runner was doing navigation even if JS code called
`event.preventDefault()`.

Note, this does not work in FF6
2011-09-08 23:00:59 +02:00
Vojta Jina 8fa79066e2 doc($location): $location docs + using $location guide 2011-09-08 23:00:59 +02:00
Vojta Jina 909415d5ed feat(scenario): browserTrigger returns false if preventDefault()
https://developer.mozilla.org/en/DOM/element.dispatchEvent
dispatchEvent method returns false if at least one of the event handlers called
preventDefault(), true otherwise.

It's helpful when browserTrigger method returns this value, as we can assert,
whether the default operation was cancelled or not.
2011-09-08 23:00:59 +02:00
Vojta Jina 4421f3d435 fix(docs): update docs to reflect new $location and fix e2e tests 2011-09-08 23:00:59 +02:00
Vojta Jina 22cb600280 fix($route): update $route to reflect $location changes
* update $route to reflect new $location
* add some more unit tests to $route
* fix some other failing unit tests
* redirect overrides the url now

Breaks $route custom redirect fn has only 3 params now
2011-09-08 23:00:59 +02:00
Vojta Jina 5ba227c7cd feat($location): $location service with html5 history api support
See documentation of $location for more info

Breaks $location has no properties, only get/set methods

Closes #168
Closes #146
Closes #281
Closes #234
2011-09-08 23:00:49 +02:00
Vojta Jina f37f0ea16e feat(jqLite): add event.isDefaultPrevented() as jQuery
Chrome's Event has defaultPrevented property, but other browsers haven't.
This is workaround for other browsers - same as jQuery.
2011-09-08 20:37:28 +02:00
Vojta Jina 91ccb4ba6e feat($browser): add $browser.baseHref()
This method abstracts <base href="" /> in document.head - returns the value.
If absolute href set, it converts the href to relative.
2011-09-08 20:37:28 +02:00
Vojta Jina d0f459c56f feat($sniffer): basic implementation of browser feature testing
This only extracts our 'hashchange' event and html5 history api detection from
$browser.

Closes #400
2011-09-08 20:37:28 +02:00
Vojta Jina cbedf55641 refactor($browser): extract MockWindow, use toHaveBeenCalledOnce 2011-09-08 20:36:33 +02:00
Vojta Jina 988ed451b5 feat($browser): jQuery style url method, onUrlChange event
This is just basic implementation of $browser.url, $browser.onUrlChange methods:

$browser.url() - returns current location.href

$browser.url('/new') - set url to /new
If supported, history.pushState is used, location.href property otherwise.

$browser.url('/new', true) - replace current url with /new
If supported, history.replaceState is used, location.replace otherwise.

$browser.onUrlChange is only fired when url is changed from the browser:
- user types into address bar
- user clicks on back/forward button
- user clicks on link

It's not fired when url is changed using $browser.url()

Breaks Removed $browser.setUrl(), $browser.getUrl(), use $browser.url()
Breaks Removed $browser.onHashChange(), use $browser.onUrlChange()
2011-09-08 20:36:33 +02:00
Vojta Jina fc2f188d4d style(filter): Couple of missing spaces, semi-colons, add empty lines 2011-09-08 17:59:52 +02:00
Vojta Jina 4b1913c5ec fix(filter.currency): Return empty string for non-numbers 2011-09-08 17:59:45 +02:00
Igor Minar 06534413d3 fix(ng:options): ng:change should be called after the new val is set
Closes #547
2011-09-07 23:37:37 -07:00
Igor Minar e54909f5ef fix(docs): use window.execScript instead of window.eval on IE
IE's window.eval doesn't execute in the global context, so we have to
use window.execScript instead which works like window.eval on normal
browsers. However execScript throws an exception when an empty string is
passed in, so I created a workaround with a workaround.
2011-09-06 14:57:37 -07:00
Vojta Jina 79f2512ba7 chore(config): Remove updateView from jstd config
This should have been part of 42062dab34
2011-09-06 17:36:53 +02:00
Vojta Jina b0eb831bce fix($browser.xhr): not convert 0 status to 200 2011-09-05 23:53:53 +02:00
Igor Minar 7f0b97e02c test(jsonp): fixing jsonp e2e tests
- buzz api keeps on throttling our requests which makes our build fail
  so I'm disabling the buzz demo e2e test
- the $xhr service jsonp test was modified to use jsonp on angularjs.org
  instead of buzz api for the same reason as mentioned above
2011-09-02 16:17:05 -07:00
Igor Minar fc7f1ef6a0 chore(version.yaml): preparing the 0.10.1 inexorable-juggernaut iteration 2011-09-02 15:41:41 -07:00
Igor Minar 8bae2a5ecb cutting the 0.10.0 chicken-hands release 2011-09-02 11:32:29 -07:00
Igor Minar 30e5f6274a docs(changelog): release notes for 0.10.0 chicken-hands 2011-09-02 10:53:41 -07:00
Igor Minar bc6e0cc954 docs(guide/tutorial/misc): sync with google docs 2011-09-02 10:44:19 -07:00
Igor Minar 8d11db0757 docs(ng:bind): fix example code 2011-09-01 16:37:08 -07:00
Igor Minar 2a8fe56997 fix(ng:class): make ng:class friendly towards other code adding/removing classes
ng:class as well as ng:class-odd and ng:class-even always reset the
class list to whatever it was before compilation, this makes it
impossible to create another directive which adds its own classes on the
element on which ng:class was applied.

the fix simply removes all classes that were added previously by
ng:class and add classes that the ng:class expression evaluates to.

we can now guarantee that we won't clobber stuff added before or after
compilation as long as all class names are unique.

in order to implement this I had to beef up jqLite#addClass and
jqLite#removeClass to be able to add/remove multiple classes without
creating duplicates.
2011-09-01 16:37:08 -07:00
Igor Minar 622c3ec974 fix(jqLite): addClass should ignore falsy values 2011-09-01 16:37:07 -07:00
Igor Minar db78aa1ce1 test(jqLite): add test for mass assignment to style 2011-09-01 16:37:07 -07:00
Igor Minar 986608fe76 fix(jqLite): special-case attr('class') because of IE9 bug 2011-09-01 16:37:06 -07:00
Igor Minar 31b8624121 feat(scope): add listener deregistration fn for $watch and $on
- both $watch and $on now return a function which when called
  deregisters the listener
- $removeListener was removed and replaced with the above
- added more tests for $watch and $on

Closes #542
2011-09-01 15:00:22 -07:00
Igor Minar a5607e3061 docs(API): various api doc fixes from Toni 2011-09-01 00:19:35 -07:00
Igor Minar ff2cb86d5d style(e2e tests): shorten jquery/jqlite describe 2011-08-31 23:03:58 -07:00
Igor Minar 825cbadf80 kill(merge): removing merge fn - dead buggy code with no specs 2011-08-31 22:32:27 -07:00
Igor Minar 93f96a16f6 fix(scope): fix edge case for $digest & $broadcast scope traversal
- fixed traversal originating on a scope with with a right sibling
- unified code for both $broadcast and $digest
2011-08-31 14:34:56 -07:00
Misko Hevery c763b009ac feat(gdocs.js): output usefull error messages when not logged in. 2011-08-31 14:34:56 -07:00
Misko Hevery e5da0c956b feat(jasmine-node): use the jasmine-node NPM to run our non-browser specs 2011-08-31 14:34:56 -07:00
Misko Hevery 3c80cf3df6 style(docs): improve the formatting of events in docs 2011-08-31 14:34:56 -07:00
Misko Hevery ad3cc16eef feat($route): add events before/after route change
BREAKING CHANGE
* removing `onChange`

FEATURE
* adding three events: $beforeRouteChange, $afterRouteChange, $routeReload
2011-08-31 14:31:23 -07:00
Misko Hevery 08d09ecbaa feat(docs): add support for events 2011-08-31 14:30:21 -07:00
Misko Hevery 456c7f62c5 bug($xhr.bulk): fix exceptions under some circumstances 2011-08-31 14:29:37 -07:00
Misko Hevery c9e7fb894b style(tests): correct indentation 2011-08-30 22:05:13 -07:00
Di Peng 4a9ccc0abc test(i18n): Update some i18n/e2e tests 2011-08-30 02:11:10 -07:00
Di Peng bceadd8e30 feat(i18n): locale specific files changed due to change in ClosureSlurper.js 2011-08-30 02:11:10 -07:00
Di Peng 545b31aa2e feat(closureSlurper): closureSlurper plural rules
- fetch plural rules from closure
- distribtue pluralization rules into each locale specific files
2011-08-30 02:11:09 -07:00
Di Peng e068addadb feat(widget): add ng:pluralize as an Angular widget 2011-08-30 02:11:09 -07:00
Di Peng 0da4902e9d feat(locale): add getPluralCat function 2011-08-30 02:11:08 -07:00
Igor Minar 3ba90003b4 fix(test): improve $cookie service test to work with Safari 5.1
the max size for safari cookies has changed sligtly so I had to adjust
the test to make cookie creation fail on this browser
2011-08-29 14:38:28 -07:00
Di Peng 5927b23ef3 fix(markup): Make special attrs such as ng:href work even without binding
- special attrs such as ng:href, ng:check did not work as intended when
their values do not contain bindings. And this commit is to fix that

Closes #534
2011-08-25 16:34:18 -07:00
Igor Minar 452607fc64 fix(events): fixing IE specific issues
IE doesn't have Array#indexOf and [].splice.call doesn't work there
either.
2011-08-24 18:36:38 -07:00
Di Peng 19401280ae feat(doc): generate both normal and debug version of index.html
- index.html has manifest file and angular.min.js
- index-jq.html has manifest file, angular.min.js and jquery.min.js
- index-debug.html has angular.js
- index-jq-debug.html has angular.js and jquery.min.js
2011-08-24 15:03:09 -07:00
Igor Minar 08a33e7bb3 feat(scope): support for events
- register listeners with $on
- remove listeners with $removeListener
- fire event that bubbles to root with $emit
- fire event that propagates to all child scopes with $broadcast
2011-08-24 15:01:50 -07:00
Igor Minar 30753cb131 feat(ng:cloak): add ng:cloak directive 2011-08-24 15:01:49 -07:00
Di Peng dbf8afcba0 fix(AngularPublic): expose missing angular public methods
- expose lowercase, uppercase and isDate to angular public api
- remove unnecessary extention of jqLite at an early stage
2011-08-24 08:00:33 -07:00
Toni Thompson 446f6b233f doc(API): various API documentation improvements 2011-08-24 11:06:55 +02:00
Igor Minar e3fad0feb3 fix(jqlite): correct the jqLite.removeClass method 2011-08-23 10:27:51 -07:00
Igor Minar 0f6e199d98 chore(ide): add pom.xml for IDEs that grok maven 2011-08-23 08:17:46 -07:00
Di Peng 15e6105779 fix(docs): remove more unecessary use of hide() and show() method
- tutorial section of docs fails to render properly as
doc:tutorial-instructions widget uses deprecated show and hide methods
of jQlite.
2011-08-21 09:40:53 -07:00
Igor Minar ee38918059 doc(changelog): add info about the memory leak in ng:options 2011-08-21 01:31:54 -07:00
Igor Minar 94e3b28d24 preparing the project for 0.10.0 chicken-hands iteration 2011-08-21 00:52:26 -07:00
Igor Minar 38e6d1e313 release notes of the 0.9.19 canine-psychokinesis 2011-08-21 00:50:58 -07:00
Igor Minar 607de75fa4 fix(docs): work around the lame ng:show directive 2011-08-21 00:46:58 -07:00
Igor Minar db04241beb fix(docs): change docs.css to avoid css clashes in buzz example 2011-08-21 00:46:46 -07:00
Di Peng 774db0aecb fix(sample): Fix for jsFiddle integration 2011-08-19 15:27:21 -07:00
Igor Minar dc0b0c77c7 feat($route): add reloadOnSearch route param to avoid reloads
In order to avoid unnecesary route reloads when just hashSearch part
of the url changes, it is now possible to disable this behavior by
setting reloadOnSearch param of the route declaration to false.

Closes #354
2011-08-19 03:55:47 -07:00
Karl Seamon 6114c8f504 fix($resource): properly call error callback when resource is called with two arguments 2011-08-18 15:07:04 -04:00
Vojta Jina b99b0a8072 feat(test): toHaveBeenCalledOnce jasmine matcher 2011-08-18 17:41:23 +02:00
dandoyon 431b748cac doc(sample): Add javascript sandbox integration (jsFiddle)
Change doc_widget.js to:

- render "edit in jsfiddle" button next to all examples
- make opt out certain examples by adding jsfiddle="false" attribute to
  doc:source element
2011-08-16 15:15:06 -07:00
Igor Minar de34ca0b64 fix(filters): fix lint warnings 2011-08-15 12:52:09 -07:00
Igor Minar 793ecb4817 refactor(jqLite): remove jqLite show/hide support
it turns out that even with our tricks, jqLite#show is not usable in
practice and definitely not on par with jQuery. so rather than
introducing half-baked apis which introduce issues, I'm removing them.

I also removed show/hide uses from docs, since they are not needed.

Breaks jqLite.hide/jqLite.show which are no longer available.
2011-08-15 12:51:41 -07:00
Igor Minar 1d45e65f4a chore(jasmine): disable 'Jasmine waiting for..' msg 2011-08-15 00:21:02 -07:00
Igor Minar 2bbef363e4 style(*): remove extra semicolons 2011-08-15 00:21:02 -07:00
Igor Minar 035ad72726 refactor(json): use angularString instead of angular.String 2011-08-15 00:21:02 -07:00
Igor Minar 9d808239b3 style(*): wrap all assignments in if statements
we commonly assign stuff in if statments like this:

if (variable = someFn()) {
  //do something with variable
}

This results in lint and IDE warnings (did you mean ==?).

It is better to be explicit about our intention and wrap the assignement
into parens:

if ((variable = someFn())) {
  //do something with variable
}

Doing so suppresses warnings + is easier to understand the intention.

I verified that the closure compiler strips the extra parens, so there
is no byte overhead for this safety practice.

We should use this style going forward...
2011-08-15 00:20:48 -07:00
Igor Minar ef01362e44 chore(.idea): remove all obsolete idea files 2011-08-15 00:15:07 -07:00
Igor Minar 6c30601ad8 feat(i18n): add i18n/locale rule set files 2011-08-14 23:44:21 -07:00
Igor Minar 37b5c5cfe9 break(date): remove support for 'long', 'longtime' date formats and 'z' flag
The support for the 'z' formatting flag was removed becase the timezone
info can't be retrieved from the browser apis (except for en-US locale
on some but not all browsers). For this reason we don't want to support
this flag at all.

Related to this, since the 'long' and 'longtime' datetime formats require
the 'z' flag in the formatting string, we are removing support for this
format as well.
2011-08-14 23:44:21 -07:00
Di Peng 966cbd4cf8 feat(i18n): collect and convert locale info from closure
- add i18n/closure directory with closure i18n files and
  update-closure.sh script to update them
- generate.sh script runs node.js scripts that extract localization
  rules from the closure library, transform them to a more suitable
format and dumps them into i18n/locale directory as angular's $locale
services
- update Rakefile to copy i18n files to build/ and pkg/ dirs
- copy i18n stuff during rake build
- e2e tests for several locales
2011-08-14 23:44:20 -07:00
Di Peng 8534b7c7c0 refactor(date,curreny,number): inject and use $locale in filters
- filter.number, filter.currency and filter.date are injected with
$locale service so that we can just swap the service to localize these
- date filter was beefed up in order to support literal strings found in
  localization rules
2011-08-14 23:44:20 -07:00
Di Peng 6802a76007 feat($locale): add default locale service for en-US 2011-08-14 23:44:20 -07:00
Di Peng 7ec8a89362 fix(directives): make ng:class-even/odd work with ng:class
Closes #508
2011-08-14 22:46:51 -07:00
Misko Hevery 34f174066f refactor(scope): non-recursive $digest method 2011-08-14 21:32:15 -07:00
Misko Hevery 530dc412c4 refactor(scope): use double-linked-list for children
Much faster $destroy operations for large ng:repeat sets.
2011-08-14 21:32:13 -07:00
Misko Hevery 3f99cdbdc3 feat(scope): $evalAsync support 2011-08-12 16:18:41 -07:00
Misko Hevery 13e7df68a6 perf(scope): re-enable statement cacheing 2011-08-12 15:48:12 -07:00
Misko Hevery 42062dab34 refactor(scope): remove $flush/$observe ng:eval/ng:eval-order 2011-08-12 15:47:47 -07:00
Misko Hevery 1c9fc1e1de fix(scope): rerun $digest from root, rather then per scope. 2011-08-12 15:47:44 -07:00
Misko Hevery 8bc7beacd8 fix(bootstrap): missing var failed strict mode boot 2011-08-12 10:19:28 -07:00
Vojta Jina 842741ee99 doc($browser): remove duplication of $browser to docs
This was causing to show up the "$browser" twice in the menu.
2011-08-10 11:51:24 +02:00
Vojta Jina 40ad543d27 doc($browser): hide $browser.notifyWhenNoOustandingRequest method
Closes #506
2011-08-10 11:50:15 +02:00
Igor Minar 06835a462a style($function): replace $function with 'function' 2011-08-06 01:54:06 -07:00
Di Peng 142cffcf64 refactor(widgets): remove input[button, submit, reset, image] and button windgets
These widgets are useless and only trigger extra $updateViews.

The only reason we had them was to support ng:change on these widgets,
but since there are no bindings present in these cases it doesn't make
sense to support ng:change here. It's likely just a leftover from
getangular.com

Breaking change: ng:change for input[button], input[submit], input[reset], input[image]
and button widgets is not supported any more
2011-08-06 01:54:05 -07:00
Di Peng 862d78c1d9 doc(xhr): add e2e test for JSONP error handling
- add e2e tests
- refactor the example by removing clear button and simplifying the code
2011-08-06 01:54:05 -07:00
Di Peng 6f8904e027 feat($browser): JSONP error handling
since we don't know if the error was due to a client error (4xx) or
server error (5xx), we leave the status code as undefined.
2011-08-06 01:54:05 -07:00
Igor Minar 4dc9e6416a doc(tutorial): updates needed for 0.9.18 rebase 2011-08-04 10:48:17 -07:00
DiPeng 4f6e947e49 fix(docs): fix qfs.read() encoding issue
- must use binary reading when using read function in q-fs module
otherwise some unicode character may be garbled.

Closes #497
2011-08-03 16:50:25 -07:00
Vojta Jina 15efbbdc1f fix($xhr.error): fix docs and add missed breaking change
$xhr.error's first argument (request) has no callback property anymore,
it's called success now...

This breaking change was introduced by b5594a773a
2011-08-02 19:01:36 +02:00
DiPeng 67a3315e1d refactor(angular): remove unnecessary parameter for slice function
- the end index for slice, if not specified, is default to the
end of the array it operates on.
2011-08-02 07:11:47 -07:00
Misko Hevery 8f0dcbab80 feat(scope): new and improved scope implementation
- Speed improvements (about 4x on flush phase)
- Memory improvements (uses no function closures)
- Break $eval into $apply, $dispatch, $flush
- Introduced $watch and $observe

Breaks angular.equals() use === instead of ==
Breaks angular.scope() does not take parent as first argument
Breaks scope.$watch() takes scope as first argument
Breaks scope.$set(), scope.$get are removed
Breaks scope.$config is removed
Breaks $route.onChange callback has not "this" bounded
2011-08-02 01:00:03 +02:00
dandoyon 1f4b417184 doc(typos): fix couple of typos in the docs
Minor documentation fixes. Should not be any code changes.
One test changed due to dependency on text in documentation.
2011-07-30 16:41:42 +02:00
Igor Minar 2d8d5aef29 prepare the 0.9.19 canine-psychokinesis iteration 2011-07-29 20:06:32 -07:00
Igor Minar eb758bc605 fix(Rakefile): index-jq.html needs to be rewritten like index.html 2011-07-29 19:35:27 -07:00
Igor Minar 761997e082 doc(release notes): small fixes for the 0.9.18 release 2011-07-29 19:34:22 -07:00
898 changed files with 143614 additions and 48269 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"directory": "bower_components",
"json": "bower.json"
}
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;launchConfigurationWorkingSet editPageId=&quot;org.eclipse.ui.resourceWorkingSetPage&quot; factoryID=&quot;org.eclipse.ui.internal.WorkingSetFactory&quot; id=&quot;1262905463390_2&quot; label=&quot;workingSet&quot; name=&quot;workingSet&quot;&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/angular.js/test&quot; type=&quot;2&quot;/&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/angular.js/src&quot; type=&quot;2&quot;/&gt;&#10;&lt;/launchConfigurationWorkingSet&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
</launchConfiguration>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/angular.js/perf&quot; type=&quot;2&quot;/&gt;&#10;&lt;item path=&quot;/angular.js/src&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/perf.sh}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
</launchConfiguration>
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/angular.js/build&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/angular.js/docs&quot; type=&quot;2&quot;/&gt;&#10;&lt;item path=&quot;/angular.js/src&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
</launchConfiguration>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/angular.js/docs&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
</launchConfiguration>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/lib/jsl/jsl}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-conf lib/jsl/jsl.default.conf"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
</launchConfiguration>
+4
View File
@@ -10,3 +10,7 @@ performance/temp*.html
*~
angular.js.tmproj
node_modules
angular.xcodeproj
.idea
libpeerconnection.log
npm-debug.log
Generated
-67
View File
@@ -1,67 +0,0 @@
IMPORTANT: THIS IS TO CERTIFY THE RIGHT TO USE THE JETBRAINS SOFTWARE PRODUCT, GRANTED BY JETBRAINS S.R.O. UNDER THE TERMS AND CONDITIONS OF THE LICENSE AGREEMENT INCLUDED WITH THE SOFTWARE. PLEASE SAVE A COPY OF THIS EMAIL FOR FUTURE REFERENCES.
========LICENSE DETAILS========
Type: Open Source License
Reference No*: LC-93161-D352729080
Date of Issue: 3 November 2010
Expiration Date: 3 November 2011
Number of Authorized Users: not limited
* Please quote this reference when contacting JetBrains
===========LICENSEE============
Name: angularjs
Customer ID: 93161
Address:
=======SOFTWARE PRODUCT========
Product Name: WebStorm
Licensed Version: 1.0 and any new product release which is made generally available before 3 November 2011
The software is shipped electronically and is available for download from:
http://www.jetbrains.com/webstorm/download/
Your WebStorm license includes a 1-year upgrade subscription qualifying you for free upgrades to any new versions of WebStorm released by JetBrains during your upgrade subscription period starting on your license issue date and ending on 3 November 2011. To check availability of the new versions of WebStorm, please visit http://www.jetbrains.com.
For running any new version of WebStorm released by JetBrains during your upgrade subscription period, please use the included below licensing details.
You can renew your upgrade subscription before or after its expiration. Your new subscription period will start on the date following the expiration date of your current upgrade subscription.
=========INSTALLATION==========
Run WebStorm and follow the Installation Wizard's instructions. To register for use of the software or change your existing registration details, go to Help/Register menu of the software and enter the included below the User Name and License Key(s) into the registration dialog:
User Name: angularjs
===== LICENSE BEGIN =====
93161-03112010
00000jBsEx59XVlc79fV"aAqWXQ09e
jQsg5TNp5X4HGhc10LNBdu!!ejRcFG
7h3S6T09YcRWs23TH0RgaM87!HqmQo
===== LICENSE END =====
===DOCUMENTATION AND SUPPORT===
WebStorm documentation:
http://www.jetbrains.com/webstorm/documentation/
Available support resources:
http://www.jetbrains.com/support/
Technical support contact:
support@jetbrains.com
Contact for the license renewal requests:
opensource@jetbrains.com
For questions, please contact:
sales@jetbrains.com
JetBrains Sales Team
http://www.jetbrains.com
"Develop with pleasure!"
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DependencyValidationManager">
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</component>
<component name="ProjectRootManager" version="2" />
<component name="SvnBranchConfigurationManager">
<option name="mySupportsUserInfoFilter" value="true" />
</component>
</project>
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/angular.js.iml" filepath="$PROJECT_DIR$/.idea/angular.js.iml" />
</modules>
</component>
</project>
-68
View File
@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="USE_SAME_INDENTS" value="true" />
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</value>
</option>
<ADDITIONAL_INDENT_OPTIONS fileType="js">
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="jsp">
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="sass">
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="xml">
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="yml">
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</component>
</project>
-15
View File
@@ -1,15 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="gen_docs" type="BashConfigurationType" factoryName="Bash">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="INTERPRETER_PATH" value="/bin/bash" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="PARENT_ENVS" value="true" />
<envs />
<module name="angular.js" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/gen_docs.sh" />
<option name="PARAMETERS" value="" />
<RunnerSettings RunnerId="BashRunner" />
<ConfigurationWrapper RunnerId="BashRunner" />
<method />
</configuration>
</component>
-15
View File
@@ -1,15 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="rake compile" type="BashConfigurationType" factoryName="Bash">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="INTERPRETER_PATH" value="/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="PARENT_ENVS" value="true" />
<envs />
<module name="angular.js" />
<option name="SCRIPT_NAME" value="/usr/bin/rake" />
<option name="PARAMETERS" value="compile" />
<RunnerSettings RunnerId="BashRunner" />
<ConfigurationWrapper RunnerId="BashRunner" />
<method />
</configuration>
</component>
Generated
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
-47
View File
@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>angular.js</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/docs.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/JSTD_Tests.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/JSTD_perf.launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="test/" kind="src" path="src"/>
<classpathentry excluding="docs-data.js|docs-scenario.js" kind="src" path="docs"/>
<classpathentry excluding="test/" kind="src" path="test"/>
<classpathentry kind="src" path="test/test"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
<classpathentry kind="output" path=""/>
</classpath>
@@ -1,16 +0,0 @@
#Mon Jan 24 10:31:47 PST 2011
activeContentFilterList=*.makefile,makefile,*.Makefile,Makefile,Makefile.*,*.mk,MANIFEST.MF
addNewLine=true
convertActionOnSaave=AnyEdit.CnvrtTabToSpaces
eclipse.preferences.version=1
inActiveContentFilterList=
javaTabWidthForJava=true
org.eclipse.jdt.ui.editor.tab.width=2
projectPropsEnabled=false
removeTrailingSpaces=true
replaceAllSpaces=false
replaceAllTabs=false
saveAndAddLine=true
saveAndConvert=true
saveAndTrim=true
useModulo4Tabs=false
@@ -1 +0,0 @@
org.eclipse.wst.jsdt.launching.JRE_CONTAINER
@@ -1 +0,0 @@
Global
+19
View File
@@ -0,0 +1,19 @@
language: node_js
node_js:
- 0.10
env:
global:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
before_script:
- export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
- ./lib/sauce/sauce_connect_setup.sh
- npm install -g grunt-cli
- grunt ci-checks package
- ./lib/sauce/sauce_connect_block.sh
script:
- grunt parallel:travis --reporters dots --browsers SL_Chrome
+2856 -45
View File
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
## Submitting issues
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].
### Guidelines
* 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 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.
[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
## 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!
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.
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[contribute]: http://docs.angularjs.org/misc/contribute
+228
View File
@@ -0,0 +1,228 @@
var files = require('./angularFiles').files;
var util = require('./lib/grunt/utils.js');
module.exports = function(grunt) {
//grunt plugins
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-ddescribe-iit');
grunt.loadNpmTasks('grunt-merge-conflict');
grunt.loadNpmTasks('grunt-parallel');
grunt.loadTasks('lib/grunt');
var NG_VERSION = util.getVersion();
var dist = 'angular-'+ NG_VERSION.full;
//global beforeEach
util.init();
//config
grunt.initConfig({
NG_VERSION: NG_VERSION,
parallel: {
travis: {
options: {
stream: true,
},
tasks: [
util.parallelTask('test:modules'),
util.parallelTask('test:jquery'),
util.parallelTask('test:jqlite'),
util.parallelTask('test:e2e')
]
}
},
connect: {
devserver: {
options: {
port: 8000,
hostname: '0.0.0.0',
base: '.',
keepalive: true,
middleware: function(connect, options){
return [
//uncomment to enable CSP
// util.csp(),
util.rewrite(),
connect.favicon('images/favicon.ico'),
connect.static(options.base),
connect.directory(options.base)
];
}
}
},
testserver: {
options: {
// We use end2end task (which does not start the webserver)
// and start the webserver as a separate process (in travis_build.sh)
// to avoid https://github.com/joyent/libuv/issues/826
port: 8000,
hostname: '0.0.0.0',
middleware: function(connect, options){
return [
function(req, resp, next) {
// cache get requests to speed up tests on travis
if (req.method === 'GET') {
resp.setHeader('Cache-control', 'public, max-age=3600');
}
next();
},
connect.favicon('images/favicon.ico'),
connect.static(options.base)
];
}
}
}
},
test: {
jqlite: 'karma-jqlite.conf.js',
jquery: 'karma-jquery.conf.js',
modules: 'karma-modules.conf.js',
//NOTE run grunt test:e2e instead and it will start a webserver for you
end2end: 'karma-e2e.conf.js'
},
autotest: {
jqlite: 'karma-jqlite.conf.js',
jquery: 'karma-jquery.conf.js'
},
clean: {build: ['build']},
build: {
scenario: {
dest: 'build/angular-scenario.js',
src: [
'lib/jquery/jquery.js',
util.wrap([files['angularSrc'], files['angularScenario']], 'ngScenario/angular')
],
styles: {
css: ['css/angular.css', 'css/angular-scenario.css']
}
},
angular: {
dest: 'build/angular.js',
src: util.wrap([files['angularSrc']], 'angular'),
styles: {
css: ['css/angular.css'],
minify: true
}
},
loader: {
dest: 'build/angular-loader.js',
src: util.wrap(['src/loader.js'], 'loader')
},
mocks: {
dest: 'build/angular-mocks.js',
src: ['src/ngMock/angular-mocks.js'],
strict: false
},
sanitize: {
dest: 'build/angular-sanitize.js',
src: util.wrap([
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
], 'module')
},
resource: {
dest: 'build/angular-resource.js',
src: util.wrap(['src/ngResource/resource.js'], 'module')
},
cookies: {
dest: 'build/angular-cookies.js',
src: util.wrap(['src/ngCookies/cookies.js'], 'module')
},
bootstrap: {
dest: 'build/angular-bootstrap.js',
src: util.wrap(['src/bootstrap/bootstrap.js'], 'module')
},
bootstrapPrettify: {
dest: 'build/angular-bootstrap-prettify.js',
src: util.wrap(['src/bootstrap/bootstrap-prettify.js', 'src/bootstrap/google-prettify/prettify.js'], 'module'),
styles: {
css: ['src/bootstrap/google-prettify/prettify.css'],
minify: true
}
}
},
min: {
angular: 'build/angular.js',
cookies: 'build/angular-cookies.js',
loader: 'build/angular-loader.js',
resource: 'build/angular-resource.js',
sanitize: 'build/angular-sanitize.js',
bootstrap: 'build/angular-bootstrap.js',
bootstrapPrettify: 'build/angular-bootstrap-prettify.js',
},
docs: {
process: ['build/docs/*.html', 'build/docs/.htaccess']
},
"ddescribe-iit": {
files: [
'test/**/*.js',
'!test/ngScenario/DescribeSpec.js'
]
},
"merge-conflict": {
files: [
'src/**/*',
'test/**/*',
'docs/**/*',
'css/**/*'
]
},
copy: {
i18n: {
files: [
{ src: 'src/ngLocale/**', dest: 'build/i18n/', expand: true, flatten: true }
]
}
},
compress: {
build: {
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
}
},
write: {
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
versionJSON: {file: 'build/version.json', val: JSON.stringify(NG_VERSION)}
}
});
//alias tasks
grunt.registerTask('test:unit', ['test:jqlite', 'test:jquery', 'test:modules']);
grunt.registerTask('minify', ['clean', 'build', 'minall']);
grunt.registerTask('test:e2e', ['connect:testserver', 'test:end2end']);
grunt.registerTask('webserver', ['connect:devserver']);
grunt.registerTask('package', ['clean', 'buildall', 'minall', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict']);
grunt.registerTask('default', ['package']);
};
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+33 -6
View File
@@ -1,12 +1,39 @@
Angular
======
AngularJS
=========
Compiling
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
use good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTMLs
syntax to express your applications components clearly and succinctly. It automatically
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
binding. To help you structure your application better and make it easy to test, AngularJS teaches
the browser how to do dependency injection and inversion of control. Oh yeah and it also helps with
server-side communication, taming async callbacks with promises and deferreds; and make client-side
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
it makes development fun!
* Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/tutorial
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
Building AngularJS
---------
rake compile
[Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
grunt package
Running Tests
-------------
rake server:start
rake test
To execute all unit tests, use:
grunt test:unit
To execute end-to-end (e2e) tests, use:
grunt package
grunt test:e2e
To learn more about the grunt tasks, run `grunt --help` and also read our
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
-368
View File
@@ -1,368 +0,0 @@
require 'yaml'
include FileUtils
ANGULAR = [
'src/Angular.js',
'src/JSON.js',
'src/Compiler.js',
'src/Scope.js',
'src/Injector.js',
'src/parser.js',
'src/Resource.js',
'src/Browser.js',
'src/sanitizer.js',
'src/jqLite.js',
'src/apis.js',
'src/filters.js',
'src/formatters.js',
'src/validators.js',
'src/service/cookieStore.js',
'src/service/cookies.js',
'src/service/defer.js',
'src/service/document.js',
'src/service/exceptionHandler.js',
'src/service/hover.js',
'src/service/invalidWidgets.js',
'src/service/location.js',
'src/service/log.js',
'src/service/resource.js',
'src/service/route.js',
'src/service/updateView.js',
'src/service/window.js',
'src/service/xhr.bulk.js',
'src/service/xhr.cache.js',
'src/service/xhr.error.js',
'src/service/xhr.js',
'src/directives.js',
'src/markups.js',
'src/widgets.js',
'src/AngularPublic.js',
]
ANGULAR_SCENARIO = [
'src/scenario/Scenario.js',
'src/scenario/Application.js',
'src/scenario/Describe.js',
'src/scenario/Future.js',
'src/scenario/ObjectModel.js',
'src/scenario/Describe.js',
'src/scenario/Runner.js',
'src/scenario/SpecRunner.js',
'src/scenario/dsl.js',
'src/scenario/matchers.js',
'src/scenario/output/Html.js',
'src/scenario/output/Json.js',
'src/scenario/output/Xml.js',
'src/scenario/output/Object.js'
]
BUILD_DIR = 'build'
task :default => [:compile, :test]
desc 'Init the build workspace'
task :init do
FileUtils.mkdir(BUILD_DIR) unless File.directory?(BUILD_DIR)
v = YAML::load( File.open( 'version.yaml' ) )
match = v['version'].match(/^([^-]*)(-snapshot)?$/)
NG_VERSION = Struct.new(:full, :major, :minor, :dot, :codename).
new(match[1] + (match[2] ? ('-' + %x(git rev-parse HEAD)[0..7]) : ''),
match[1].split('.')[0],
match[1].split('.')[1],
match[1].split('.')[2],
v['codename'])
end
desc 'Clean Generated Files'
task :clean do
FileUtils.rm_r(BUILD_DIR, :force => true)
FileUtils.mkdir(BUILD_DIR)
end
desc 'Compile Scenario'
task :compile_scenario => :init do
deps = [
'lib/jquery/jquery-1.4.2.js',
'src/scenario/angular.prefix',
ANGULAR,
ANGULAR_SCENARIO,
'src/scenario/angular.suffix',
]
concat = 'cat ' + deps.flatten.join(' ')
File.open(path_to('angular-scenario.js'), 'w') do |f|
f.write(%x{#{concat}}.gsub('"NG_VERSION_FULL"', NG_VERSION.full))
f.write(gen_css('css/angular.css') + "\n")
f.write(gen_css('css/angular-scenario.css'))
end
end
desc 'Compile JSTD Scenario Adapter'
task :compile_jstd_scenario_adapter => :init do
deps = [
'src/jstd-scenario-adapter/angular.prefix',
'src/jstd-scenario-adapter/Adapter.js',
'src/jstd-scenario-adapter/angular.suffix',
]
concat = 'cat ' + deps.flatten.join(' ')
File.open(path_to('jstd-scenario-adapter.js'), 'w') do |f|
f.write(%x{#{concat}}.gsub('"NG_VERSION_FULL"', NG_VERSION.full))
end
# TODO(vojta) use jstd configuration when implemented
# (instead of including jstd-adapter-config.js)
File.open(path_to('jstd-scenario-adapter-config.js'), 'w') do |f|
f.write("/**\r\n" +
" * Configuration for jstd scenario adapter \n */\n" +
"var jstdScenarioAdapter = {\n relativeUrlPrefix: '/build/docs/'\n};\n")
end
end
desc 'Generate IE css js patch'
task :generate_ie_compat => :init do
css = File.open('css/angular.css', 'r') {|f| f.read }
# finds all css rules that contain backround images and extracts the rule name(s), content type of
# the image and base64 encoded image data
r = /\n([^\{\n]+)\s*\{[^\}]*background-image:\s*url\("data:([^;]+);base64,([^"]+)"\);[^\}]*\}/
images = css.scan(r)
# create a js file with multipart header containing the extracted images. the entire file *must*
# be CRLF (\r\n) delimited
File.open(path_to('angular-ie-compat.js'), 'w') do |f|
f.write("/*\r\n" +
"Content-Type: multipart/related; boundary=\"_\"\r\n" +
"\r\n")
images.each_index do |idx|
f.write("--_\r\n" +
"Content-Location:img#{idx}\r\n" +
"Content-Transfer-Encoding:base64\r\n" +
"\r\n" +
images[idx][2] + "\r\n")
end
f.write("--_--\r\n" +
"*/\r\n")
# generate a css string containing *background-image rules for IE that point to the mime type
# images in the header
cssString = ''
images.each_index do |idx|
cssString += "#{images[idx][0]}{*background-image:url(\"mhtml:' + jsUri + '!img#{idx}\")}"
end
# generate a javascript closure that contains a function which will append the generated css
# string as a stylesheet to the current html document
jsString = "(function(){ \r\n" +
" var jsUri = document.location.href.replace(/\\/[^\\\/]+(#.*)?$/, '/') + \r\n" +
" document.getElementById('ng-ie-compat').src,\r\n" +
" css = '#{cssString}',\r\n" +
" s = document.createElement('style'); \r\n" +
"\r\n" +
" s.setAttribute('type', 'text/css'); \r\n" +
"\r\n" +
" if (s.styleSheet) { \r\n" +
" s.styleSheet.cssText = css; \r\n" +
" } else { \r\n" +
" s.appendChild(document.createTextNode(css)); \r\n" +
" } \r\n" +
" document.getElementsByTagName('head')[0].appendChild(s); \r\n" +
"})();\r\n"
f.write(jsString)
end
end
desc 'Compile JavaScript'
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter, :generate_ie_compat] do
deps = [
'src/angular.prefix',
ANGULAR,
'src/angular.suffix',
]
File.open(path_to('angular.js'), 'w') do |f|
concat = 'cat ' + deps.flatten.join(' ')
content = %x{#{concat}}.
gsub('"NG_VERSION_FULL"', NG_VERSION.full).
gsub('"NG_VERSION_MAJOR"', NG_VERSION.major).
gsub('"NG_VERSION_MINOR"', NG_VERSION.minor).
gsub('"NG_VERSION_DOT"', NG_VERSION.dot).
gsub('"NG_VERSION_CODENAME"', NG_VERSION.codename).
gsub(/^\s*['"]use strict['"];?\s*$/, ''). # remove all file-specific strict mode flags
gsub(/'USE STRICT'/, "'use strict'") # rename the placeholder in angular.prefix
f.write(content)
f.write(gen_css('css/angular.css', true))
end
%x(java -jar lib/closure-compiler/compiler.jar \
--compilation_level SIMPLE_OPTIMIZATIONS \
--language_in ECMASCRIPT5_STRICT \
--js #{path_to('angular.js')} \
--js_output_file #{path_to('angular.min.js')})
end
desc 'Generate docs'
task :docs => [:init] do
`node docs/src/gen-docs.js`
File.open(path_to('docs/.htaccess'), File::RDWR) do |f|
text = f.read
f.truncate 0
f.rewind
f.write text.sub('"NG_VERSION_FULL"', NG_VERSION.full)
end
end
desc 'Create angular distribution'
task :package => [:clean, :compile, :docs] do
tarball = "angular-#{NG_VERSION.full}.tgz"
pkg_dir = path_to("pkg/angular-#{NG_VERSION.full}")
FileUtils.rm_r(path_to('pkg'), :force => true)
FileUtils.mkdir_p(pkg_dir)
['src/angular-mocks.js',
path_to('angular.js'),
path_to('angular.min.js'),
path_to('angular-ie-compat.js'),
path_to('angular-scenario.js'),
path_to('jstd-scenario-adapter.js'),
path_to('jstd-scenario-adapter-config.js'),
].each do |src|
dest = src.gsub(/^[^\/]+\//, '').gsub(/((\.min)?\.js)$/, "-#{NG_VERSION.full}\\1")
FileUtils.cp(src, pkg_dir + '/' + dest)
end
FileUtils.cp_r path_to('docs'), "#{pkg_dir}/docs-#{NG_VERSION.full}"
File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/index.html", File::RDWR) do |f|
text = f.read
f.truncate 0
f.rewind
f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js")
end
File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/docs-scenario.html", File::RDWR) do |f|
text = f.read
f.truncate 0
f.rewind
f.write text.sub('angular-scenario.js', "angular-scenario-#{NG_VERSION.full}.js")
end
File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/appcache.manifest", File::RDWR) do |f|
text = f.read
f.truncate 0
f.rewind
f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js")
end
File.open("#{pkg_dir}/docs-#{NG_VERSION.full}/appcache-offline.manifest", File::RDWR) do |f|
text = f.read
f.truncate 0
f.rewind
f.write text.sub('angular.min.js', "angular-#{NG_VERSION.full}.min.js")
end
%x(tar -czf #{path_to(tarball)} -C #{path_to('pkg')} .)
FileUtils.cp path_to(tarball), pkg_dir
FileUtils.mv pkg_dir, path_to(['pkg', NG_VERSION.full])
puts "Package created: #{path_to(tarball)}"
end
namespace :server do
desc 'Run JsTestDriver Server'
task :start do
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
end
desc 'Run JavaScript tests against the server'
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
end
end
desc 'Run JavaScript tests'
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
end
desc 'Lint'
task :lint do
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
print out
end
desc 'push_angularjs'
task :push_angularjs => :compile do
sh %(cat angularjs.ftp | ftp -N angularjs.netrc angularjs.org)
end
###################
# utility methods #
###################
##
# generates css snippet from a given files and optionally applies simple minification rules
#
def gen_css(cssFile, minify = false)
css = ''
File.open(cssFile, 'r') do |f|
css = f.read
end
if minify
css.gsub! /\n/, ''
css.gsub! /\/\*.*?\*\//, ''
css.gsub! /:\s+/, ':'
css.gsub! /\s*\{\s*/, '{'
css.gsub! /\s*\}\s*/, '}'
css.gsub! /\s*\,\s*/, ','
css.gsub! /\s*\;\s*/, ';'
end
#escape for js
css.gsub! /\\/, "\\\\\\"
css.gsub! /'/, "\\\\'"
css.gsub! /\n/, "\\n"
return %Q{angular.element(document).find('head').append('<style type="text/css">#{css}</style>');}
end
##
# returns path to the file in the build directory
#
def path_to(filename)
return File.join(BUILD_DIR, *filename)
end
+190
View File
@@ -0,0 +1,190 @@
angularFiles = {
'angularSrc': [
'src/Angular.js',
'src/loader.js',
'src/AngularPublic.js',
'src/jqLite.js',
'src/apis.js',
'src/auto/injector.js',
'src/ng/anchorScroll.js',
'src/ng/browser.js',
'src/ng/cacheFactory.js',
'src/ng/compile.js',
'src/ng/controller.js',
'src/ng/document.js',
'src/ng/exceptionHandler.js',
'src/ng/interpolate.js',
'src/ng/location.js',
'src/ng/log.js',
'src/ng/parse.js',
'src/ng/q.js',
'src/ng/route.js',
'src/ng/routeParams.js',
'src/ng/rootScope.js',
'src/ng/sniffer.js',
'src/ng/window.js',
'src/ng/http.js',
'src/ng/httpBackend.js',
'src/ng/locale.js',
'src/ng/timeout.js',
'src/ng/filter.js',
'src/ng/filter/filter.js',
'src/ng/filter/filters.js',
'src/ng/filter/limitTo.js',
'src/ng/filter/orderBy.js',
'src/ng/directive/directives.js',
'src/ng/directive/a.js',
'src/ng/directive/booleanAttrs.js',
'src/ng/directive/form.js',
'src/ng/directive/input.js',
'src/ng/directive/ngBind.js',
'src/ng/directive/ngClass.js',
'src/ng/directive/ngCloak.js',
'src/ng/directive/ngController.js',
'src/ng/directive/ngCsp.js',
'src/ng/directive/ngEventDirs.js',
'src/ng/directive/ngInclude.js',
'src/ng/directive/ngInit.js',
'src/ng/directive/ngNonBindable.js',
'src/ng/directive/ngPluralize.js',
'src/ng/directive/ngRepeat.js',
'src/ng/directive/ngShowHide.js',
'src/ng/directive/ngStyle.js',
'src/ng/directive/ngSwitch.js',
'src/ng/directive/ngTransclude.js',
'src/ng/directive/ngView.js',
'src/ng/directive/script.js',
'src/ng/directive/select.js',
'src/ng/directive/style.js'
],
'angularSrcModules': [
'src/ngCookies/cookies.js',
'src/ngResource/resource.js',
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
'src/ngMock/angular-mocks.js',
'src/bootstrap/bootstrap.js'
],
'angularScenario': [
'src/ngScenario/Scenario.js',
'src/ngScenario/Application.js',
'src/ngScenario/Describe.js',
'src/ngScenario/Future.js',
'src/ngScenario/ObjectModel.js',
'src/ngScenario/Runner.js',
'src/ngScenario/SpecRunner.js',
'src/ngScenario/dsl.js',
'src/ngScenario/matchers.js',
'src/ngScenario/output/Html.js',
'src/ngScenario/output/Json.js',
'src/ngScenario/output/Xml.js',
'src/ngScenario/output/Object.js'
],
'angularTest': [
'test/testabilityPatch.js',
'test/matchers.js',
'test/ngScenario/*.js',
'test/ngScenario/output/*.js',
'test/*.js',
'test/auto/*.js',
'test/bootstrap/*.js',
'test/ng/*.js',
'test/ng/directive/*.js',
'test/ng/filter/*.js',
'test/ngCookies/*.js',
'test/ngResource/*.js',
'test/ngSanitize/*.js',
'test/ngSanitize/directive/*.js',
'test/ngSanitize/filter/*.js',
'test/ngMock/*.js'
],
'karma': [
'lib/jquery/jquery.js',
'test/jquery_remove.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'@angularTest',
'example/personalLog/*.js',
'example/personalLog/test/*.js'
],
'karmaExclude': [
'test/jquery_alias.js',
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js'
],
'karmaScenario': [
'build/angular-scenario.js',
'build/docs/docs-scenario.js'
],
"karmaModules": [
'build/angular.js',
'src/ngMock/angular-mocks.js',
'src/ngCookies/cookies.js',
'src/ngResource/resource.js',
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
'test/matchers.js',
'test/ngMock/*.js',
'test/ngCookies/*.js',
'test/ngResource/*.js',
'test/ngSanitize/*.js',
'test/ngSanitize/directive/*.js',
'test/ngSanitize/filter/*.js'
],
'karmaJquery': [
'lib/jquery/jquery.js',
'test/jquery_alias.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'@angularTest',
'example/personalLog/*.js',
'example/personalLog/test/*.js'
],
'karmaJqueryExclude': [
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js',
'test/jquery_remove.js'
]
};
if (exports) {
exports.files = angularFiles;
exports.mergeFilesFor = function() {
var files = [];
Array.prototype.slice.call(arguments, 0).forEach(function(filegroup) {
angularFiles[filegroup].forEach(function(file) {
// replace @ref
var match = file.match(/^\@(.*)/);
if (match) {
files = files.concat(angularFiles[match[1]]);
} else {
files.push(file);
}
});
});
return files;
};
}
-5
View File
@@ -1,5 +0,0 @@
bin
cd angularjs.org/ng
put angular-debug.js js/angular-debug.js
put angular-minified.js js/angular-minified.js
put angular-scenario.js js/angular-scenario.js
Executable
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env node
// TODO(vojta): pre-commit hook for validating messages
// TODO(vojta): report errors, currently Q silence everything which really sucks
var child = require('child_process');
var fs = require('fs');
var util = require('util');
var q = require('qq');
var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD';
var GIT_TAG_CMD = 'git describe --tags --abbrev=0';
var HEADER_TPL = '<a name="%s"></a>\n# %s (%s)\n\n';
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() {
console.log('WARNING:', util.format.apply(null, arguments));
};
var parseRawCommit = function(raw) {
if (!raw) return null;
var lines = raw.split('\n');
var msg = {}, match;
msg.hash = lines.shift();
msg.subject = lines.shift();
msg.closes = [];
msg.breaks = [];
lines.forEach(function(line) {
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
if (match) msg.closes.push(parseInt(match[1]));
});
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
if (match) {
msg.breaking = match[1];
}
msg.body = lines.join('\n');
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
if (!match || !match[1] || !match[3]) {
warn('Incorrect message: %s %s', msg.hash, msg.subject);
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];
return msg;
};
var linkToIssue = function(issue) {
return util.format(LINK_ISSUE, issue, issue);
};
var linkToCommit = function(hash) {
return util.format(LINK_COMMIT, hash.substr(0, 8), hash);
};
var currentDate = function() {
var now = new Date();
var pad = function(i) {
return ('0' + i).substr(-2);
};
return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate()));
};
var printSection = function(stream, title, section, printCommitLinks) {
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
var components = Object.getOwnPropertyNames(section).sort();
if (!components.length) return;
stream.write(util.format('\n## %s\n\n', title));
components.forEach(function(name) {
var prefix = '-';
var nested = section[name].length > 1;
if (name !== EMPTY_COMPONENT) {
if (nested) {
stream.write(util.format('- **%s:**\n', name));
prefix = ' -';
} else {
prefix = util.format('- **%s:**', name);
}
}
section[name].forEach(function(commit) {
if (printCommitLinks) {
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
if (commit.closes.length) {
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', '));
}
stream.write(')\n');
} else {
stream.write(util.format('%s %s', prefix, commit.subject));
}
});
});
stream.write('\n');
};
var readGitLog = function(grep, from) {
var deferred = q.defer();
// TODO(vojta): if it's slow, use spawn and stream it instead
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
var commits = [];
stdout.split('\n==END==\n').forEach(function(rawCommit) {
var commit = parseRawCommit(rawCommit);
if (commit) commits.push(commit);
});
deferred.resolve(commits);
});
return deferred.promise;
};
var writeChangelog = function(stream, commits, version) {
var sections = {
fix: {},
feat: {},
breaks: {}
};
sections.breaks[EMPTY_COMPONENT] = [];
commits.forEach(function(commit) {
var section = sections[commit.type];
var component = commit.component || EMPTY_COMPONENT;
if (section) {
section[component] = section[component] || [];
section[component].push(commit);
}
if (commit.breaking) {
sections.breaks[component] = sections.breaks[component] || [];
sections.breaks[component].push({
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking),
hash: commit.hash,
closes: []
});
};
});
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
printSection(stream, 'Bug Fixes', sections.fix);
printSection(stream, 'Features', sections.feat);
printSection(stream, 'Breaking Changes', sections.breaks, false);
}
var getPreviousTag = function() {
var deferred = q.defer();
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
if (code) deferred.reject('Cannot get the previous tag.');
else deferred.resolve(stdout.replace('\n', ''));
});
return deferred.promise;
};
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|BREAKING', tag).then(function(commits) {
console.log('Parsed', commits.length, 'commits');
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
});
});
};
// publish for testing
exports.parseRawCommit = parseRawCommit;
// hacky start if not run by jasmine :-D
if (process.argv.join('').indexOf('jasmine-node') === -1) {
generate(process.argv[2], process.argv[3]);
}
+43
View File
@@ -0,0 +1,43 @@
describe('changelog.js', function() {
var ch = require('./changelog');
describe('parseRawCommit', function() {
it('should parse raw commit', function() {
var msg = ch.parseRawCommit(
'9b1aff905b638aa274a5fc8f88662df446d374bd\n' +
'feat(scope): broadcast $destroy event on scope destruction\n' +
'perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
expect(msg.type).toBe('feat');
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n')
expect(msg.component).toBe('scope');
});
it('should parse closed issues', function() {
var msg = ch.parseRawCommit(
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'Closes #123\nCloses #25\n');
expect(msg.closes).toEqual([123, 25]);
});
it('should parse breaking changes', function() {
var msg = ch.parseRawCommit(
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'BREAKING CHANGE: first breaking change\nsomething else\n' +
'another line with more info\n');
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
});
});
});
+80
View File
@@ -0,0 +1,80 @@
<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))
Executable
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
grunt minify
gzip -c < build/angular.min.js > build/angular.min.js.gzip
ls -l build/angular.min.*
+5 -82
View File
@@ -1,87 +1,10 @@
@charset "UTF-8";
.ng-format-negative {
color: red;
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak {
display: none !important;
}
.ng-exception {
border: 2px solid #FF0000;
font-family: "Courier New", Courier, monospace;
font-size: smaller;
white-space: pre;
}
.ng-validation-error {
border: 2px solid #FF0000;
}
/*****************
* TIP
*****************/
#ng-callout {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 13px;
font-weight: normal;
font-family: Verdana, Arial, Helvetica, sans-serif;
vertical-align: baseline;
background: transparent;
text-decoration: none;
}
#ng-callout .ng-arrow-left{
background-image: url("data:image/gif;base64,R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrSLoc/AG8FeUUIN+sGebWAnbKSJodqqlsOxJtqYooU9vvk+vcJIcTkg+QAAA7");
background-repeat: no-repeat;
background-position: left top;
position: absolute;
z-index:101;
left:-12px;
height:23px;
width:10px;
top:-3px;
}
#ng-callout .ng-arrow-right{
background-image: url("data:image/gif;base64,R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrCLTcoM29yN6k9socs91e5X3EyJloipYrO4ohTMqA0Fn2XVNswJe+H+SXAAA7");
background-repeat: no-repeat;
background-position: left top;
position: absolute;
z-index:101;
height:23px;
width:11px;
top:-2px;
}
#ng-callout {
position: absolute;
z-index:100;
border: 2px solid #CCCCCC;
background-color: #fff;
}
#ng-callout .ng-content{
padding:10px 10px 10px 10px;
color:#333333;
}
#ng-callout .ng-title{
background-color: #CCCCCC;
text-align: left;
padding-left: 8px;
padding-bottom: 5px;
padding-top: 2px;
font-weight:bold;
}
/*****************
* indicators
*****************/
.ng-input-indicator-wait {
background-image: url("data:image/png;base64,R0lGODlhEAAQAPQAAP///wAAAPDw8IqKiuDg4EZGRnp6egAAAFhYWCQkJKysrL6+vhQUFJycnAQEBDY2NmhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFdyAgAgIJIeWoAkRCCMdBkKtIHIngyMKsErPBYbADpkSCwhDmQCBethRB6Vj4kFCkQPG4IlWDgrNRIwnO4UKBXDufzQvDMaoSDBgFb886MiQadgNABAokfCwzBA8LCg0Egl8jAggGAA1kBIA1BAYzlyILczULC2UhACH5BAkKAAAALAAAAAAQABAAAAV2ICACAmlAZTmOREEIyUEQjLKKxPHADhEvqxlgcGgkGI1DYSVAIAWMx+lwSKkICJ0QsHi9RgKBwnVTiRQQgwF4I4UFDQQEwi6/3YSGWRRmjhEETAJfIgMFCnAKM0KDV4EEEAQLiF18TAYNXDaSe3x6mjidN1s3IQAh+QQJCgAAACwAAAAAEAAQAAAFeCAgAgLZDGU5jgRECEUiCI+yioSDwDJyLKsXoHFQxBSHAoAAFBhqtMJg8DgQBgfrEsJAEAg4YhZIEiwgKtHiMBgtpg3wbUZXGO7kOb1MUKRFMysCChAoggJCIg0GC2aNe4gqQldfL4l/Ag1AXySJgn5LcoE3QXI3IQAh+QQJCgAAACwAAAAAEAAQAAAFdiAgAgLZNGU5joQhCEjxIssqEo8bC9BRjy9Ag7GILQ4QEoE0gBAEBcOpcBA0DoxSK/e8LRIHn+i1cK0IyKdg0VAoljYIg+GgnRrwVS/8IAkICyosBIQpBAMoKy9dImxPhS+GKkFrkX+TigtLlIyKXUF+NjagNiEAIfkECQoAAAAsAAAAABAAEAAABWwgIAICaRhlOY4EIgjH8R7LKhKHGwsMvb4AAy3WODBIBBKCsYA9TjuhDNDKEVSERezQEL0WrhXucRUQGuik7bFlngzqVW9LMl9XWvLdjFaJtDFqZ1cEZUB0dUgvL3dgP4WJZn4jkomWNpSTIyEAIfkECQoAAAAsAAAAABAAEAAABX4gIAICuSxlOY6CIgiD8RrEKgqGOwxwUrMlAoSwIzAGpJpgoSDAGifDY5kopBYDlEpAQBwevxfBtRIUGi8xwWkDNBCIwmC9Vq0aiQQDQuK+VgQPDXV9hCJjBwcFYU5pLwwHXQcMKSmNLQcIAExlbH8JBwttaX0ABAcNbWVbKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICSRBlOY7CIghN8zbEKsKoIjdFzZaEgUBHKChMJtRwcWpAWoWnifm6ESAMhO8lQK0EEAV3rFopIBCEcGwDKAqPh4HUrY4ICHH1dSoTFgcHUiZjBhAJB2AHDykpKAwHAwdzf19KkASIPl9cDgcnDkdtNwiMJCshACH5BAkKAAAALAAAAAAQABAAAAV3ICACAkkQZTmOAiosiyAoxCq+KPxCNVsSMRgBsiClWrLTSWFoIQZHl6pleBh6suxKMIhlvzbAwkBWfFWrBQTxNLq2RG2yhSUkDs2b63AYDAoJXAcFRwADeAkJDX0AQCsEfAQMDAIPBz0rCgcxky0JRWE1AmwpKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICKZzkqJ4nQZxLqZKv4NqNLKK2/Q4Ek4lFXChsg5ypJjs1II3gEDUSRInEGYAw6B6zM4JhrDAtEosVkLUtHA7RHaHAGJQEjsODcEg0FBAFVgkQJQ1pAwcDDw8KcFtSInwJAowCCA6RIwqZAgkPNgVpWndjdyohACH5BAkKAAAALAAAAAAQABAAAAV5ICACAimc5KieLEuUKvm2xAKLqDCfC2GaO9eL0LABWTiBYmA06W6kHgvCqEJiAIJiu3gcvgUsscHUERm+kaCxyxa+zRPk0SgJEgfIvbAdIAQLCAYlCj4DBw0IBQsMCjIqBAcPAooCBg9pKgsJLwUFOhCZKyQDA3YqIQAh+QQJCgAAACwAAAAAEAAQAAAFdSAgAgIpnOSonmxbqiThCrJKEHFbo8JxDDOZYFFb+A41E4H4OhkOipXwBElYITDAckFEOBgMQ3arkMkUBdxIUGZpEb7kaQBRlASPg0FQQHAbEEMGDSVEAA1QBhAED1E0NgwFAooCDWljaQIQCE5qMHcNhCkjIQAh+QQJCgAAACwAAAAAEAAQAAAFeSAgAgIpnOSoLgxxvqgKLEcCC65KEAByKK8cSpA4DAiHQ/DkKhGKh4ZCtCyZGo6F6iYYPAqFgYy02xkSaLEMV34tELyRYNEsCQyHlvWkGCzsPgMCEAY7Cg04Uk48LAsDhRA8MVQPEF0GAgqYYwSRlycNcWskCkApIyEAOwAAAAAAAAAAAA==");
background-position: right;
background-repeat: no-repeat;
ng\:form {
display: block;
}
-29
View File
@@ -1,29 +0,0 @@
@workInProgress
@ngdoc overview
@name angular.service
@description
The services API provides objects for carrying out common web app tasks. Service objects are
managed by angular's {@link guide/dev_guide.di dependency injection system}.
* {@link angular.service.$browser $browser } - Provides an instance of a browser object
* {@link angular.service.$cookieStore $cookieStore } - Provides key / value storage backed by
session cookies
* {@link angular.service.$cookies $cookies } - Provides read / write access to browser cookies
* {@link angular.service.$defer $defer } - Defers function execution and try / catch block
* {@link angular.service.$document $document } - Provides reference to `window.document` element
* {@link angular.service.$exceptionHandler $exceptionHandler } - Receives uncaught angular
exceptions
* {@link angular.service.$hover $hover } -
* {@link angular.service.$invalidWidgets $invalidWidgets } - Holds references to invalid widgets
* {@link angular.service.$location $location } - Parses the browser location URL
* {@link angular.service.$log $log } - Provides logging service
* {@link angular.service.$resource $resource } - Creates objects for interacting with RESTful
server-side data sources
* {@link angular.service.$route $route } - Provides deep-linking services
* {@link angular.service.$updateView $updateView } - Queues view updates
* {@link angular.service.$window $window } - References the browsers `window` object
* {@link angular.service.$xhr $xhr} - Generates an XHR request.
For information on how angular services work and how to write your own services, see {@link
guide/dev_guide.services Angular Services} in the angular Developer Guide.
+3 -70
View File
@@ -2,73 +2,6 @@
@name API Reference
@description
## Angular Compiler API
* {@link angular.widget Widgets} - Angular custom DOM element
* {@link angular.directive Directives} - Angular DOM element attributes
* {@link angular.markup Markup} and {@link angular.attrMarkup Attribute Markup}
* {@link angular.filter Filters} - Angular output filters
* {@link angular.formatter Formatters} - Angular converters for form elements
* {@link angular.validator Validators} - Angular input validators
* {@link angular.compile angular.compile()} - Template compiler
## Angular Scope API
* {@link angular.scope Scope Object} - Angular scope object
## Angular Services & Dependency Injection API
* {@link angular.service Angular Services}
* {@link angular.injector angular.injector() }
## Angular Testing API
* {@link angular.mock Testing Mocks API} - Mock objects for testing
* {@link
https://docs.google.com/document/d/11L8htLKrh6c92foV71ytYpiKkeKpM4_a5-9c3HywfIc/edit?hl=en_US
Angular Scenario Runner} - Automated scenario testing documentation
## Angular Utility Functions
### HTML & DOM Manipulation
* {@link angular.element angular.element()}
### Misc
* {@link angular.bind angular.bind() }
* {@link angular.extend angular.extend() }
* {@link angular.forEach angular.forEach() }
* {@link angular.identity angular.identity() }
* {@link angular.noop angular.noop() }
## Type Identification
* {@link angular.isArray angular.isArray() }
* {@link angular.isDate angular.isDate() }
* {@link angular.isDefined angular.isDefined() }
* {@link angular.isFunction angular.isFunction() }
* {@link angular.isNumber angular.isNumber() }
* {@link angular.isObject angular.isObject() }
* {@link angular.isString angular.isString() }
* {@link angular.isUndefined angular.isUndefined() }
## Strings
* {@link angular.lowercase angular.lowercase() }
* {@link angular.uppercase angular.uppercase() }
### JSON
* {@link angular.fromJson angular.fromJson() }
* {@link angular.toJson angular.toJson() }
## Utility methods for JavaScript types
* {@link angular.Object Object API} - Utility functions for JavaScript objects
* {@link angular.Array Array API} - Utility functions for JavaScript arrays
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}.
+5
View File
@@ -0,0 +1,5 @@
@ngdoc overview
@name ng
@description
The `ng` is an angular module which contains all of the core angular services.
+68 -48
View File
@@ -1,4 +1,3 @@
@workInProgress
@ngdoc overview
@name Cookbook: Advanced Form
@description
@@ -9,12 +8,8 @@ detection, and preventing invalid form submission.
<doc:example>
<doc:source>
<script>
UserForm.$inject = ['$invalidWidgets'];
function UserForm($invalidWidgets){
this.$invalidWidgets = $invalidWidgets;
this.state = /^\w\w$/;
this.zip = /^\d\d\d\d\d$/;
this.master = {
function UserForm($scope) {
var master = {
name: 'John Smith',
address:{
line1: '123 Main St.',
@@ -26,56 +21,81 @@ detection, and preventing invalid form submission.
{type:'phone', value:'1(234) 555-1212'}
]
};
this.cancel();
$scope.state = /^\w\w$/;
$scope.zip = /^\d\d\d\d\d$/;
$scope.cancel = function() {
$scope.form = angular.copy(master);
};
$scope.save = function() {
master = $scope.form;
$scope.cancel();
};
$scope.addContact = function() {
$scope.form.contacts.push({type:'', value:''});
};
$scope.removeContact = function(contact) {
var contacts = $scope.form.contacts;
for (var i = 0, ii = contacts.length; i < ii; i++) {
if (contact === contacts[i]) {
contacts.splice(i, 1);
}
}
};
$scope.isCancelDisabled = function() {
return angular.equals(master, $scope.form);
};
$scope.isSaveDisabled = function() {
return $scope.myForm.$invalid || angular.equals(master, $scope.form);
};
$scope.cancel();
}
UserForm.prototype = {
cancel: function(){
this.form = angular.copy(this.master);
},
save: function(){
this.master = this.form;
this.cancel();
}
};
</script>
<div ng:controller="UserForm">
<div ng-controller="UserForm">
<label>Name:</label><br/>
<input type="text" name="form.name" ng:required/> <br/><br/>
<form name="myForm">
<label>Address:</label><br/>
<input type="text" name="form.address.line1" size="33" ng:required/> <br/>
<input type="text" name="form.address.city" size="12" ng:required/>,
<input type="text" name="form.address.state" size="2" ng:required ng:validate="regexp:state"/>
<input type="text" name="form.address.zip" size="5" ng:required
ng:validate="regexp:zip"/><br/><br/>
<label>Name:</label><br/>
<input type="text" ng-model="form.name" required/> <br/><br/>
<label>Contacts:</label>
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
<div ng:repeat="contact in form.contacts">
<select name="contact.type">
<option>email</option>
<option>phone</option>
<option>pager</option>
<option>IM</option>
</select>
<input type="text" name="contact.value" ng:required/>
[ <a href="" ng:click="form.contacts.$remove(contact)">X</a> ]
</div>
<button ng:click="cancel()" ng:disabled="{{master.$equals(form)}}">Cancel</button>
<button ng:click="save()" ng:disabled="{{$invalidWidgets.visible() ||
master.$equals(form)}}">Save</button>
<label>Address:</label> <br/>
<input type="text" ng-model="form.address.line1" size="33" required/> <br/>
<input type="text" ng-model="form.address.city" size="12" required/>,
<input type="text" ng-model="form.address.state" size="2"
ng-pattern="state" required/>
<input type="text" ng-model="form.address.zip" size="5"
ng-pattern="zip" required/><br/><br/>
<label>Contacts:</label>
[ <a href="" ng-click="addContact()">add</a> ]
<div ng-repeat="contact in form.contacts">
<select ng-model="contact.type">
<option>email</option>
<option>phone</option>
<option>pager</option>
<option>IM</option>
</select>
<input type="text" ng-model="contact.value" required/>
[ <a href="" ng-click="removeContact(contact)">X</a> ]
</div>
<button ng-click="cancel()" ng-disabled="isCancelDisabled()">Cancel</button>
<button ng-click="save()" ng-disabled="isSaveDisabled()">Save</button>
</form>
<hr/>
Debug View:
<pre>form={{form}}
master={{master}}</pre>
<pre>form={{form}}</pre>
</div>
</doc:source>
<doc:scenario>
it('should enable save button', function(){
it('should enable save button', function() {
expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy();
input('form.name').enter('');
expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy();
@@ -84,13 +104,13 @@ master.$equals(form)}}">Save</button>
element(':button:contains(Save)').click();
expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy();
});
it('should enable cancel button', function(){
it('should enable cancel button', function() {
expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy();
input('form.name').enter('change');
expect(element(':button:contains(Cancel)').attr('disabled')).toBeFalsy();
element(':button:contains(Cancel)').click();
expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy();
expect(element(':input[name=form.name]').val()).toEqual('John Smith');
expect(element(':input[ng\\:model="form.name"]').val()).toEqual('John Smith');
});
</doc:scenario>
</doc:example>
+25 -25
View File
@@ -1,10 +1,9 @@
@workInProgress
@ngdoc overview
@name Cookbook: Resources - Buzz
@description
External resources are URLs that provide JSON data, which are then rendered with the help of
templates. angular has a resource factory that can be used to give names to the URLs and then
templates. Angular has a resource factory that can be used to give names to the URLs and then
attach behavior to them. For example you can use the
{@link http://code.google.com/apis/buzz/v1/getting_started.html#background-operations| Google Buzz
API}
@@ -13,47 +12,48 @@ to retrieve Buzz activity and comments.
<doc:example>
<doc:source>
<script>
BuzzController.$inject = ['$resource'];
function BuzzController($resource) {
this.Activity = $resource(
BuzzController.$inject = ['$scope', '$resource'];
function BuzzController($scope, $resource) {
$scope.userId = 'googlebuzz';
$scope.Activity = $resource(
'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
{alt: 'json', callback: 'JSON_CALLBACK'},
{ get: {method: 'JSON', params: {visibility: '@self'}},
replies: {method: 'JSON', params: {visibility: '@self', comments: '@comments'}}
{ get: {method: 'JSONP', params: {visibility: '@self'}},
replies: {method: 'JSONP', params: {visibility: '@self', comments: '@comments'}}
});
}
BuzzController.prototype = {
fetch: function() {
this.activities = this.Activity.get({userId:this.userId});
},
expandReplies: function(activity) {
activity.replies = this.Activity.replies({userId: this.userId, activityId: activity.id});
$scope.fetch = function() {
$scope.activities = $scope.Activity.get({userId:this.userId});
}
$scope.expandReplies = function(activity) {
activity.replies = $scope.Activity.replies({userId: this.userId, activityId: activity.id});
}
};
</script>
<div ng:controller="BuzzController">
<input name="userId" value="googlebuzz"/>
<button ng:click="fetch()">fetch</button>
<div ng-controller="BuzzController">
<input ng-model="userId"/>
<button ng-click="fetch()">fetch</button>
<hr/>
<div class="buzz" ng:repeat="item in activities.data.items">
<div class="buzz" ng-repeat="item in activities.data.items">
<h1 style="font-size: 15px;">
<img ng:src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
<a ng:href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
<a href ng:click="expandReplies(item)" style="float: right;">
<img ng-src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
<a ng-href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
<a href ng-click="expandReplies(item)" style="float: right;">
Expand replies: {{item.links.replies[0].count}}
</a>
</h1>
{{item.object.content | html}}
<div class="reply" ng:repeat="reply in item.replies.data.items" style="margin-left: 20px;">
<img ng:src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
<a ng:href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>:
<div class="reply" ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;">
<img ng-src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
<a ng-href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>:
{{reply.content | html}}
</div>
</div>
</div>
</doc:source>
<doc:scenario>
it('fetch buzz and expand', function() {
xit('fetch buzz and expand', function() {
element(':button:contains(fetch)').click();
expect(repeater('div.buzz').count()).toBeGreaterThan(0);
element('.buzz a:contains(Expand replies):first').click();
+99 -63
View File
@@ -1,4 +1,3 @@
@workInProgress
@ngdoc overview
@name Cookbook: Deep Linking
@description
@@ -6,7 +5,7 @@
Deep linking allows you to encode the state of the application in the URL so that it can be
bookmarked and the application can be restored from the URL to the same state.
While <angular/> does not force you to deal with bookmarks in any particular way, it has services
While Angular does not force you to deal with bookmarks in any particular way, it has services
which make the common case described here very easy to implement.
# Assumptions
@@ -28,88 +27,125 @@ controller.
In this example we have a simple app which consist of two screens:
* Welcome: url `#` Show the user contact information.
* Settings: url `#/settings` Show an edit screen for user contact information.
* Welcome: url `welcome` Show the user contact information.
* Settings: url `settings` Show an edit screen for user contact information.
<example module="deepLinking" deps="angular-sanitize.js">
<file name="script.js">
angular.module('deepLinking', ['ngSanitize'])
.config(function($routeProvider) {
$routeProvider.
when("/welcome", {templateUrl:'welcome.html', controller:WelcomeCntl}).
when("/settings", {templateUrl:'settings.html', controller:SettingsCntl});
});
The two partials are defined in the following URLs:
AppCntl.$inject = ['$scope', '$route']
function AppCntl($scope, $route) {
$scope.$route = $route;
* {@link ./examples/settings.html}
* {@link ./examples/welcome.html}
// initialize the model to something useful
$scope.person = {
name:'anonymous',
contacts:[{type:'email', url:'anonymous@example.com'}]
};
}
<doc:example>
<doc:source>
<script>
AppCntl.$inject = ['$route']
function AppCntl($route) {
// define routes
$route.when("", {template:'./examples/welcome.html', controller:WelcomeCntl});
$route.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
$route.parent(this);
function WelcomeCntl($scope) {
$scope.greet = function() {
alert("Hello " + $scope.person.name);
};
}
// initialize the model to something useful
this.person = {
name:'anonymous',
contacts:[{type:'email', url:'anonymous@example.com'}]
};
}
function SettingsCntl($scope, $location) {
$scope.cancel = function() {
$scope.form = angular.copy($scope.person);
};
function WelcomeCntl($route){}
WelcomeCntl.prototype = {
greet: function(){
alert("Hello " + this.person.name);
}
};
$scope.save = function() {
angular.copy($scope.form, $scope.person);
$location.path('/welcome');
};
function SettingsCntl(){
this.cancel();
}
SettingsCntl.prototype = {
cancel: function(){
this.form = angular.copy(this.person);
},
$scope.cancel();
}
</file>
<file name="style.css">
[ng-view] {
border: 1px solid blue;
margin: 0;
padding:1em;
}
save: function(){
angular.copy(this.form, this.person);
window.location.hash = "#";
}
};
</script>
<div ng:controller="AppCntl">
.partial-info {
background-color: blue;
color: white;
padding: 3px;
}
</file>
<file name="index.html">
<div ng-controller="AppCntl">
<h1>Your App Chrome</h1>
[ <a href="#">Welcome</a> | <a href="#/settings">Settings</a> ]
[ <a href="welcome">Welcome</a> | <a href="settings">Settings</a> ]
<hr/>
<span style="background-color: blue; color: white; padding: 3px;">
<span class="partial-info">
Partial: {{$route.current.template}}
</span>
<ng:view style="border: 1px solid blue; margin: 0; display:block; padding:1em;"></ng:view>
<div ng-view></div>
<small>Your app footer </small>
</div>
</doc:source>
<doc:scenario>
it('should navigate to URL', function(){
element('a:contains(Welcome)').click();
expect(element('ng\\:view').text()).toMatch(/Hello anonymous/);
element('a:contains(Settings)').click();
input('form.name').enter('yourname');
element(':button:contains(Save)').click();
element('a:contains(Welcome)').click();
expect(element('ng\\:view').text()).toMatch(/Hello yourname/);
</file>
<file name="settings.html">
<label>Name:</label>
<input type="text" ng:model="form.name" required>
<div ng:repeat="contact in form.contacts">
<select ng:model="contact.type">
<option>url</option>
<option>email</option>
<option>phone</option>
</select>
<input type="text" ng:model="contact.url">
[ <a href="" ng:click="form.contacts.$remove(contact)">X</a> ]
</div>
<div>
[ <a href="" ng:click="form.contacts.$add()">add</a> ]
</div>
<button ng:click="cancel()">Cancel</button>
<button ng:click="save()">Save</button>
</file>
<file name="welcome.html">
Hello {{person.name}},
<div>
Your contact information:
<div ng:repeat="contact in person.contacts">{{contact.type}}:
<span ng-bind-html="contact.url|linky"></span>
</div>
</div>
</file>
<file name="scenario.js">
it('should navigate to URL', function() {
element('a:contains(Welcome)').click();
expect(element('[ng-view]').text()).toMatch(/Hello anonymous/);
element('a:contains(Settings)').click();
input('form.name').enter('yourname');
element(':button:contains(Save)').click();
element('a:contains(Welcome)').click();
expect(element('[ng-view]').text()).toMatch(/Hello yourname/);
});
</doc:scenario>
</doc:example>
</file>
</example>
# Things to notice
* Routes are defined in the `AppCntl` class. The initialization of the controller causes the
initialization of the {@link api/angular.service.$route $route} service with the proper URL
routes.
* The {@link api/angular.service.$route $route} service then watches the URL and instantiates the
initialization of the {@link api/ng.$route $route} service with the proper URL
routes.
* The {@link api/ng.$route $route} service then watches the URL and instantiates the
appropriate controller when the URL changes.
* The {@link api/angular.widget.ng:view ng:view} widget loads the view when the URL changes. It
also
sets the view scope to the newly instantiated controller.
* The {@link api/ng.directive:ngView ngView} widget loads the
view when the URL changes. It also sets the view scope to the newly instantiated controller.
* Changing the URL is sufficient to change the controller and view. It makes no difference whether
the URL is changed programatically or by the user.
+53 -40
View File
@@ -1,9 +1,8 @@
@workInProgress
@ngdoc overview
@name Cookbook: Form
@description
A web application's main purpose is to present and gather data. For this reason angular strives
A web application's main purpose is to present and gather data. For this reason Angular strives
to make both of these operations trivial. This example shows off how you can build a simple form to
allow a user to enter data.
@@ -11,76 +10,91 @@ allow a user to enter data.
<doc:example>
<doc:source>
<script>
function FormController(){
this.user = {
function FormController($scope) {
var user = $scope.user = {
name: 'John Smith',
address:{line1: '123 Main St.', city:'Anytown', state:'AA', zip:'12345'},
contacts:[{type:'phone', value:'1(234) 555-1212'}]
};
this.state = /^\w\w$/;
this.zip = /^\d\d\d\d\d$/;
$scope.state = /^\w\w$/;
$scope.zip = /^\d\d\d\d\d$/;
$scope.addContact = function() {
user.contacts.push({type:'email', value:''});
};
$scope.removeContact = function(contact) {
for (var i = 0, ii = user.contacts.length; i < ii; i++) {
if (contact === user.contacts[i]) {
$scope.user.contacts.splice(i, 1);
}
}
};
}
</script>
<div ng:controller="FormController" class="example">
<div ng-controller="FormController" class="example">
<label>Name:</label><br/>
<input type="text" name="user.name" ng:required/> <br/><br/>
<label>Name:</label><br>
<input type="text" ng-model="user.name" required/> <br><br>
<label>Address:</label><br/>
<input type="text" name="user.address.line1" size="33" ng:required/> <br/>
<input type="text" name="user.address.city" size="12" ng:required/>,
<input type="text" name="user.address.state" size="2" ng:required ng:validate="regexp:state"/>
<input type="text" name="user.address.zip" size="5" ng:required
ng:validate="regexp:zip"/><br/><br/>
<label>Address:</label><br>
<input type="text" ng-model="user.address.line1" size="33" required> <br>
<input type="text" ng-model="user.address.city" size="12" required>,
<input type="text" ng-model="user.address.state"
ng-pattern="state" size="2" required>
<input type="text" ng-model="user.address.zip" size="5"
ng-pattern="zip" required><br><br>
<label>Phone:</label>
[ <a href="" ng:click="user.contacts.$add()">add</a> ]
<div ng:repeat="contact in user.contacts">
<select name="contact.type">
[ <a href="" ng-click="addContact()">add</a> ]
<div ng-repeat="contact in user.contacts">
<select ng-model="contact.type">
<option>email</option>
<option>phone</option>
<option>pager</option>
<option>IM</option>
</select>
<input type="text" name="contact.value" ng:required/>
[ <a href="" ng:click="user.contacts.$remove(contact)">X</a> ]
<input type="text" ng-model="contact.value" required>
[ <a href="" ng-click="removeContact(contact)">X</a> ]
</div>
<hr/>
Debug View:
<pre>user={{user}}</pre>
<pre>user={{user | json}}</pre>
</div>
</doc:source>
<doc:scenario>
it('should show debug', function(){
it('should show debug', function() {
expect(binding('user')).toMatch(/John Smith/);
});
it('should add contact', function(){
it('should add contact', function() {
using('.example').element('a:contains(add)').click();
using('.example div:last').input('contact.value').enter('you@example.org');
expect(binding('user')).toMatch(/\(234\) 555\-1212/);
expect(binding('user')).toMatch(/you@example.org/);
});
it('should remove contact', function(){
it('should remove contact', function() {
using('.example').element('a:contains(X)').click();
expect(binding('user')).not().toMatch(/\(234\) 555\-1212/);
});
it('should validate zip', function(){
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
.not().toMatch(/ng-validation-error/);
it('should validate zip', function() {
expect(using('.example').
element(':input[ng\\:model="user.address.zip"]').
prop('className')).not().toMatch(/ng-invalid/);
using('.example').input('user.address.zip').enter('abc');
expect(using('.example').element(':input[name=user.address.zip]').attr('className'))
.toMatch(/ng-validation-error/);
expect(using('.example').
element(':input[ng\\:model="user.address.zip"]').
prop('className')).toMatch(/ng-invalid/);
});
it('should validate state', function(){
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
.not().toMatch(/ng-validation-error/);
it('should validate state', function() {
expect(using('.example').element(':input[ng\\:model="user.address.state"]').prop('className'))
.not().toMatch(/ng-invalid/);
using('.example').input('user.address.state').enter('XXX');
expect(using('.example').element(':input[name=user.address.state]').attr('className'))
.toMatch(/ng-validation-error/);
expect(using('.example').element(':input[ng\\:model="user.address.state"]').prop('className'))
.toMatch(/ng-invalid/);
});
</doc:scenario>
</doc:example>
@@ -88,14 +102,13 @@ ng:validate="regexp:zip"/><br/><br/>
# Things to notice
* The user data model is initialized {@link api/angular.directive.ng:controller controller} and is
available in
the {@link api/angular.scope scope} with the initial data.
* The user data model is initialized {@link api/ng.directive:ngController controller} and is
available in the {@link api/ng.$rootScope.Scope scope} with the initial data.
* For debugging purposes we have included a debug view of the model to better understand what
is going on.
* The {@link api/angular.widget.HTML input widgets} simply refer to the model and are auto bound.
* The inputs {@link api/angular.validator validate}. (Try leaving them blank or entering non digits
in the zip field)
* The {@link api/ng.directive:input input directives} simply refer
to the model and are data-bound.
* The inputs validate. (Try leaving them blank or entering non digits in the zip field)
* In your application you can simply read from or write to the model and the form will be updated.
* By clicking the 'add' link you are adding new items into the `user.contacts` array which are then
reflected in the view.
+16 -9
View File
@@ -1,16 +1,22 @@
@workInProgress
@ngdoc overview
@name Cookbook: Hello World
@description
<doc:example>
<doc:source>
Your name: <input type="text" name="name" value="World"/>
<hr/>
Hello {{name}}!
<script>
function HelloCntl($scope) {
$scope.name = 'World';
}
</script>
<div ng-controller="HelloCntl">
Your name: <input type="text" ng-model="name"/>
<hr/>
Hello {{name || "World"}}!
</div>
</doc:source>
<doc:scenario>
it('should change the binding when user enters text', function(){
it('should change the binding when user enters text', function() {
expect(binding('name')).toEqual('World');
input('name').enter('angular');
expect(binding('name')).toEqual('angular');
@@ -22,10 +28,11 @@
Take a look through the source and note:
* The script tag that {@link guide/dev_guide.bootstrap bootstraps} the angular environment.
* The text {@link api/angular.widget.HTML input widget} which is bound to the greeting name text.
* 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/angular.scope scope}.
* The script tag that {@link guide/bootstrap bootstraps} the Angular environment.
* The text {@link api/ng.directive:input input form control} which is
bound to the greeting name text.
* 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
changes to the
+4 -5
View File
@@ -1,9 +1,8 @@
@workInProgress
@ngdoc overview
@name Cookbook
@description
Welcome to the angular cookbook. Here we will show you typical uses of angular by example.
Welcome to the Angular cookbook. Here we will show you typical uses of Angular by example.
# Hello World
@@ -45,8 +44,8 @@ allowing you to send links to specific screens in your app.
# Services
{@link api/angular.service Services}: Services are long lived objects in your applications that are
available across controllers. A collection of useful services are pre-bundled with angular but you
{@link api/ng Services}: Services are long lived objects in your applications that are
available across controllers. A collection of useful services are pre-bundled with Angular but you
will likely add your own. Services are initialized using dependency injection, which resolves the
order of initialization. This safeguards you from the perils of global state (a common way to
implement long lived objects).
@@ -56,4 +55,4 @@ implement long lived objects).
{@link buzz Resources}: Web applications must be able to communicate with the external
services to get and update data. Resources are the abstractions of external URLs which are
specially tailored to angular data binding.
specially tailored to Angular data binding.
+54 -53
View File
@@ -1,23 +1,22 @@
@workInProgress
@ngdoc overview
@name Cookbook: MVC
@description
MVC allows for a clean an testable separation between the behavior (controller) and the view
MVC allows for a clean and testable separation between the behavior (controller) and the view
(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the
view. This makes it very easy for the controller and the view to share the model.
The model is simply the controller's this. This makes it very easy to test the controller in
isolation since one can simply instantiate the controller and test without a view, because there is
no connection between the controller and the view.
The model is a set of objects and primitives that are referenced from the Scope ($scope) object.
This makes it very easy to test the controller in isolation since one can simply instantiate the
controller and test without a view, because there is no connection between the controller and the
view.
<doc:example>
<doc:source>
<script>
function TicTacToeCntl($location){
this.$location = $location;
this.cellStyle= {
function TicTacToeCntl($scope, $location) {
$scope.cellStyle= {
'height': '20px',
'width': '20px',
'border': '1px solid black',
@@ -25,30 +24,40 @@ no connection between the controller and the view.
'vertical-align': 'middle',
'cursor': 'pointer'
};
this.reset();
this.$watch('$location.hashSearch.board', this.readUrl);
}
TicTacToeCntl.prototype = {
dropPiece: function(row, col) {
if (!this.winner && !this.board[row][col]) {
this.board[row][col] = this.nextMove;
this.nextMove = this.nextMove == 'X' ? 'O' : 'X';
this.setUrl();
}
},
reset: function(){
this.board = [
$scope.reset = function() {
$scope.board = [
['', '', ''],
['', '', ''],
['', '', '']
];
this.nextMove = 'X';
this.winner = '';
this.setUrl();
},
grade: function(){
var b = this.board;
this.winner =
$scope.nextMove = 'X';
$scope.winner = '';
setUrl();
};
$scope.dropPiece = function(row, col) {
if (!$scope.winner && !$scope.board[row][col]) {
$scope.board[row][col] = $scope.nextMove;
$scope.nextMove = $scope.nextMove == 'X' ? 'O' : 'X';
setUrl();
}
};
$scope.reset();
$scope.$watch(function() { return $location.search().board;}, readUrl);
function setUrl() {
var rows = [];
angular.forEach($scope.board, function(row) {
rows.push(row.join(','));
});
$location.search({board: rows.join(';') + '/' + $scope.nextMove});
}
function grade() {
var b = $scope.board;
$scope.winner =
row(0) || row(1) || row(2) ||
col(0) || col(1) || col(2) ||
diagonal(-1) || diagonal(1);
@@ -56,44 +65,36 @@ no connection between the controller and the view.
function col(col) { return same(b[0][col], b[1][col], b[2][col]);}
function diagonal(i) { return same(b[0][1-i], b[1][1], b[2][1+i]);}
function same(a, b, c) { return (a==b && b==c) ? a : '';};
},
setUrl: function(){
var rows = [];
angular.forEach(this.board, function(row){
rows.push(row.join(','));
});
this.$location.hashSearch.board = rows.join(';') + '/' + this.nextMove;
},
readUrl: function(value) {
}
function readUrl(value) {
if (value) {
value = value.split('/');
this.nextMove = value[1];
$scope.nextMove = value[1];
angular.forEach(value[0].split(';'), function(row, col){
this.board[col] = row.split(',');
}, this);
this.grade();
} else {
this.reset();
$scope.board[col] = row.split(',');
});
grade();
}
}
};
}
</script>
<h3>Tic-Tac-Toe</h3>
<div ng:controller="TicTacToeCntl">
<div ng-controller="TicTacToeCntl">
Next Player: {{nextMove}}
<div class="winner" ng:show="winner">Player {{winner}} has won!</div>
<div class="winner" ng-show="winner">Player {{winner}} has won!</div>
<table class="board">
<tr ng:repeat="row in board" style="height:15px;">
<td ng:repeat="cell in row" ng:style="cellStyle"
ng:click="dropPiece($parent.$index, $index)">{{cell}}</td>
<tr ng-repeat="row in board" style="height:15px;">
<td ng-repeat="cell in row" ng-style="cellStyle"
ng-click="dropPiece($parent.$index, $index)">{{cell}}</td>
</tr>
</table>
<button ng:click="reset()">reset board</button>
<button ng-click="reset()">reset board</button>
</div>
</doc:source>
<doc:scenario>
it('should play a game', function(){
it('should play a game', function() {
piece(1, 1);
expect(binding('nextMove')).toEqual('O');
piece(3, 1);
@@ -114,7 +115,7 @@ no connection between the controller and the view.
# Things to notice
* The controller is defined in JavaScript and has no reference to the rendering logic.
* The controller is instantiated by <angular/> and injected into the view.
* The controller is instantiated by Angular and injected into the view.
* The controller can be instantiated in isolation (without a view) and the code will still execute.
This makes it very testable.
* The HTML view is a projection of the model. In the above example, the model is stored in the
@@ -124,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/angular.scope.$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
api/ng.$rootScope.Scope#$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
+114
View File
@@ -0,0 +1,114 @@
@ngdoc overview
@name Developer Guide: Bootstrap
@description
# Overview
This page explains the Angular initialization process and how you can manually initialize Angular
if necessary.
## Angular `<script>` Tag
This example shows the recommended path for integrating Angular with what we call automatic
initialization.
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org" ng-app>
<body>
...
<script src="angular.js">
</body>
</html>
</pre>
* Place the `script` tag at the bottom of the page. Placing script tags at the end of the page
improves app load time because the HTML loading is not blocked by loading of the `angular.js`
script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link
your production code to this URL, as it will expose a security hole on your site. For
experimental development linking to our site is fine.
* Choose: `angular-[version].js` for a human-readable file, suitable for development and
debugging.
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
production.
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
angular to auto-bootstrap your application.
<html ng-app>
* If IE7 support is required add `id="ng-app"`
<html ng-app id="ng-app">
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
`ng:`.)
<html xmlns:ng="http://angularjs.org">
## Automatic Initialization
Angular initializes automatically upon `DOMContentLoaded` event, at which point Angular looks for
the {@link api/ng.directive:ngApp `ng-app`} directive which
designates your application root. If the {@link
api/ng.directive:ngApp `ng-app`} directive is found then Angular
will:
* load the {@link guide/module module} associated with the directive.
* create the application {@link api/AUTO.$injector injector}
* compile the DOM treating the {@link api/ng.directive:ngApp
`ng-app`} directive as the root of the compilation. This allows you to tell it to treat only a
portion of the DOM as an Angular application.
<pre>
<!doctype html>
<html ng-app="optionalModuleName">
<body>
I can add: {{ 1+2 }}.
<script src="angular.js"></script>
</body>
</html>
</pre>
## Manual Initialization
If you need to have more control over the initialization process, you can use a manual
bootstrapping method instead. Examples of when you'd need to do this include using script loaders
or the need to perform an operation before Angular compiles a page.
Here is an example of manually initializing Angular:
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org">
<body>
Hello {{'World'}}!
<script src="http://code.angularjs.org/angular.js"></script>
<script>
angular.element(document).ready(function() {
angular.bootstrap(document, ['optionalModuleName']);
});
</script>
</body>
</html>
</pre>
Note that we have provided the name of our application module to be loaded into the injector as the second
parameter of the {@link api/angular.bootstrap} function. This example is equivalent to using the
{@link api/ng.directive:ngApp ng-app} directive, with `ng-app="optionalModuleName"`, as in the automatic
initialization example above.
This is the sequence that your code should follow:
1. After the page and all of the code is loaded, find the root element of your AngularJS
application, which is typically the root of the document.
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the element into an
executable, bi-directionally bound application.
+142
View File
@@ -0,0 +1,142 @@
@ngdoc overview
@name Developer Guide: HTML Compiler
@description
# 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}.
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
browser how the window size needs to be divided in half so that the center is found, and that this
center needs to be aligned with the text's center. Simply add an `align="center"` attribute to any
element to achieve the desired behavior. Such is the power of declarative language.
But the declarative language is also limited, since it does not allow you to teach the browser new
syntax. For example there is no easy way to get the browser to align the text at 1/3 the position
instead of 1/2. What is needed is a way to teach the browser new HTML syntax.
Angular comes pre-bundled with common directives which are useful for building any app. We also
expect that you will create directives that are specific to your app. These extensions become a
Domain Specific Language for building your application.
All of this compilation takes place in the web browser; no server side or pre-compilation step is
involved.
# Compiler
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
function.
2. **Link:** combine the directives with a scope and produce a live view. Any changes in the
scope model are reflected in the view, and any user interactions with the view are reflected
in the scope model. This makes the scope model the single source of truth.
Some directives such as {@link api/ng.directive:ngRepeat `ng-repeat`} clone DOM elements once
for each item in a collection. Having a compile and link phase improves performance since the
cloned template only needs to be compiled once, and then linked once for each clone instance.
# 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
names, as well as comments. Here are some equivalent examples of invoking the {@link
api/ng.directive:ngBind `ng-bind`} directive.
<pre>
<span ng-bind="exp"></span>
<span class="ng-bind: exp;"></span>
<ng-bind></ng-bind>
<!-- directive: ng-bind exp -->
</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
to write directives.
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
`<span>` element.
<example module="drag">
<file name="script.js">
angular.module('drag', []).
directive('draggable', function($document) {
return function(scope, element, attr) {
var startX = 0, startY = 0, x = 0, y = 0;
element.css({
position: 'relative',
border: '1px solid red',
backgroundColor: 'lightgrey',
cursor: 'pointer'
});
element.bind('mousedown', function(event) {
// Prevent default dragging of selected content
event.preventDefault();
startX = event.screenX - x;
startY = event.screenY - y;
$document.bind('mousemove', mousemove);
$document.bind('mouseup', mouseup);
});
function mousemove(event) {
y = event.screenY - startY;
x = event.screenX - startX;
element.css({
top: y + 'px',
left: x + 'px'
});
}
function mouseup() {
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
}
});
</file>
<file name="index.html">
<span draggable>Drag ME</span>
</file>
</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.
# Understanding View
There are many templating systems out there. Most of them 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.
Angular is different. The Angular compiler consumes the DOM with directives, 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.
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
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.
+467
View File
@@ -0,0 +1,467 @@
@ngdoc overview
@name Conceptual Overview
@description
# Overview
This document gives a quick overview of the main angular components and how they work together.
These are:
* {@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
This is how we get the ball rolling (refer to the diagram and example below):
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
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!`
<div class="clear">
</div>
<example>
<file name="index.html">
<p ng-init=" name='World' ">Hello {{name}}!</p>
</file>
</example>
<a name="runtime"></a>
# Runtime
<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#$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.
<div class="clear">
</div>
<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="clear">
</div>
<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>
<img class="center" src="img/guide/concepts-scope.png">
<a name="controller"></a>
# Controller
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
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.
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.
<div class="clear">
</div>
<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.
<div class="clear">
</div>
<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.
<div class="clear">
</div>
<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.bind('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}.
<div class='clear'></div>
<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;
});
// 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>
</example>
<a name="angular_namespace"></a>
# Angular Namespace
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,101 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Initializing Angular: Automatic Initiialization
@description
Angular initializes automatically when you load the angular script into your page, specifying
angular's `ng:autobind` attribute with no arguments:
<script src="angular.js" ng:autobind>
From a high-level view, this is what happens during angular's automatic initialization process:
1. The browser loads the page, and then runs the angular script.
The `ng:autobind` attribute tells angular to compile and manage the whole HTML document. The
compilation phase is initiated in the page's `onLoad()` handler. Angular doesn't begin processing
the page until after the page load is complete.
2. Angular finds the root of the HTML document and creates the global variable `angular` in the
global namespace. Everything that angular subsequently creates is bound to fields in this global
object.
3. Angular walks the DOM looking for angular widgets, directives, and markup (such as `ng:init` or
`ng:repeat`). As angular encounters these, it creates child scopes as necessary and attaches them
to the DOM, registers listeners on those scopes, associates any controller functions with their
data and their part of the view, and ultimately constructs a runnable application. The resulting
app features two-way data-binding and a nice separation between data, presentation, and business
logic.
4. For the duration of the application session (while the page is loaded), angular monitors the
state of the application, and updates the view and the data model whenever the state of either one
changes.
For details on how the compiler works, see {@link dev_guide.compiler Angular HTML Compiler}.
## Initialization Options
The reason why `ng:autobind` exists is because angular should not assume that the entire HTML
document should be processed just because the `angular.js` script is included. In order to compile
only a part of the document, specify the ID of the element you want to use for angular's root
element as the value of the `ng:autobind` attribute:
ng:autobind="angularContent"
## Auto-bootstrap with `#autobind`
In some rare cases you can't define the `ng:` prefix before the script tag's attribute (for
example, in some CMS systems). In those situations it is possible to auto-bootstrap angular by
appending `#autobind` to the `<script src=...>` URL, like in this snippet:
<pre>
<!doctype html>
<html>
<head>
<script type="text/javascript"
src="http://code.angularjs.org/angular.js#autobind"></script>
</head>
<body>
<div xmlns:ng="http://angularjs.org">
Hello {{'world'}}!
</div>
</body>
</html>
</pre>
As with `ng:autobind`, you can specify an element id that should be exclusively targeted for
compilation as the value of the `#autobind`, for example: `#autobind=angularContent`.
## Filename Restrictions for Auto-bootstrap
In order for us to find the auto-bootstrap from a script attribute or URL fragment, the value of
the `script` `src` attribute that loads the angular script must match one of these naming
conventions:
- `angular.js`
- `angular-min.js`
- `angular-x.x.x.js`
- `angular-x.x.x.min.js`
- `angular-x.x.x-xxxxxxxx.js` (dev snapshot)
- `angular-x.x.x-xxxxxxxx.min.js` (dev snapshot)
- `angular-bootstrap.js` (used for development of angular)
Optionally, any of the filename formats above can be prepended with a relative or absolute URL that
ends with `/`.
## Global Angular Object
The angular script creates a single global variable `angular` in the global namespace. All angular
APIs are bound to fields of this global object.
## Related Topics
* {@link dev_guide.bootstrap Initializing Angular}
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
## Related API
{@link api/angular.compile Compiler API}
@@ -1,48 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Initializing Angular: Manual Initialization
@description
Letting angular handle the initialization process (bootstrapping) is a handy way to start using
angular, but advanced users who want more control over the initialization process can choose to use
the manual bootstrapping method instead.
The best way to get started with manual bootstrapping is to look at the what happens when you use
{@link api/angular.directive.ng:autobind ng:autobind}, by showing each step of the process
explicitly.
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org">
<head>
<script type="text/javascript" src="http://code.angularjs.org/angular.js"
ng:autobind></script>
<script type="text/javascript">
(angular.element(document).ready(function() {
angular.compile(document)();
})(document);
</script>
</head>
<body>
Hello {{'World'}}!
</body>
</html>
</pre>
This is the sequence that your code should follow if you bootstrap angular on your own:
1. After the page is loaded, find the root of the HTML template, which is typically the root of
the document.
2. Run angular's {@link dev_guide.compiler Angular HTML compiler}, which converts a template into
an executable, bi-directionally bound application.
## Related Topics
* {@link dev_guide.bootstrap Initializing Angular}
* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization}
* {@link dev_guide.compiler Angular HTML compiler}
## Related API
{@link api/angular.compile Compiler API}
@@ -1,65 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Initializing Angular
@description
Initializing angular consists of loading the `angular.js` script in your page, and specifying how
angular should process and manage the page. To initialize angular you do the following:
* Specify the angular namespace in the `<html>` page
* Choose which flavor of angular script to load (debug or production)
* Specify whether or not angular should process and manage the page automatically (`ng:autobind`)
The simplest way to initialize angular is to load the angular script and tell angular to compile
and manage the whole page. You do this as follows:
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org">
<head>
...
</head>
<body>
...
<script src="angular.js" ng:autobind>
</body>
</pre>
## Specifying the Angular Namespace
<html xmlns:ng="http://angularjs.org">
You need to declare the angular namespace declaration in the following cases:
* For all types of browser if you are using XHTML.
* For Internet Explorer older than version 9 (because older versions of IE do not render widgets
properly for either HTML or XHTML).
## Creating Your Own Namespaces
When you are ready to define your own {@link dev_guide.compiler.widgets widgets}, you must create
your own namespace in addition to specifying the angular namespace. You use your own namespace to
form the fully qualified name for widgets that you create.
For example, you could map the alias `my` to your domain, and create a widget called `my:widget`.
To create your own namespace, simply add another `xmlns` tag to your page, create an alias, and set
it to your unique domain:
<html xmlns:ng="http://angularjs.org" xmlns:my="http://mydomain.com">
## Loading the Angular Bootstrap Script
The angular bootstrap script comes in two flavors; a debug script, and a production script:
* angular-[version].js - This is a human-readable file, suitable for development and debugging.
* angular-[version].min.js - This is a compressed and obfuscated file, suitable for use in
production.
## Related Topics
* {@link dev_guide.bootstrap.auto_bootstrap Automatic Initialization}
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
@@ -1,39 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Directives: Creating Custom Angular Directives
@description
The following code snippet shows how to define a custom directive. You define a new directive by
extending the {@link dev_guide.compiler Angular HTML compiler}. The code snippet below is a
simplified definition of the built-in {@link api/angular.directive.ng:bind ng:bind} directive:
<pre>
angular.directive('ng:bind', function(expression, compiledElement) {
var compiler = this;
return function(linkElement) {
var currentScope = this;
currentScope.$watch(expression, function(value) {
linkElement.text(value);
});
};
});
</pre>
# Additional Compiler Methods for Custom Directives
The angular compiler exposes methods that you may need to use when writing your own widgets and
directives. For example, the `descend()` method lets you control whether the compiler ignores or
processes child elements of the element it is compiling. For information on this and other
compiler methods, see the {@link api/angular.compile Compiler API doc}.
## Related Docs
* {@link dev_guide.compiler.directives Understanding Angular Directives}
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
* {@link dev_guide.compiler Angular HTML Compiler}
## Related API
* {@link api/angular.directive Angular Directive API}.
@@ -1,47 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Understanding Angular Directives
@description
An angular directive is a custom HTML attribute that angular knows how to process. You add them to
a template element like any other attribute. Angular directives all have a `ng:` prefix. In the
following example, the angular directive (`ng:controller`) is a div tag:
<div ng:controller>
You use angular directives to modify DOM element properties. The element you modify can be an
existing HTML element type or a custom DOM element type that you created. You can use any number of
directives per element.
You add angular directives to a standard HTML tag as in the following example, in which we have
added the {@link api/angular.directive.ng:click ng:click} directive to a button tag:
<button name="button1" ng:click="foo()">Click This</button>
In the example above, `name` is the standard HTML attribute, and `ng:click` is the angular
directive. The `ng:click` directive lets you implement custom behavior in an associated controller
function.
In the next example, we add the {@link api/angular.directive.ng:bind ng:bind} directive to a
`<span>` tag:
<span ng:bind="1+2"></span>
The `ng:bind` directive tells angular to set up {@link dev_guide.templates.databinding data
binding} between the data model and the view for the specified expression. When the angular {@link
dev_guide.compiler compiler} encounters an `ng:bind` directive in a template, it passes the
attribute value to the `ng:bind` function, which in turn sets up the data binding. On any change to
the expression in the model, the view is updated to display the span text with the changed
expression value.
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.directives.creating_directives Creating Angular Directives}
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
## Related API:
* {@link api/angular.directive Directive API}
* {@link api/angular.widget Widget API}
@@ -1,48 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Comparing Directives and Attribute Widgets
@description
Although directives and {@link dev_guide.compiler.widgets attribute widgets} appear the same in a
template (`ng:init` is a directive, `ng:repeat` is an attribute widget), there is a difference in
the order in which they are evaluated. The user of existing directives or widgets cannot determine
the order of evaluation. The evaluation order is the responsibility of the developer creating
custom directives and widgets.
For example, consider this piece of HTML, which uses the `ng:repeat`, `ng:init`, and `ng:bind`
widget and directives:
<pre>
<ul ng:init="people=['mike', 'mary']">
<li ng:repeat="person in people"
ng:init="a=a+1"
ng:bind="person">
</li>
</ul>
</pre>
Notice that the order of execution matters here. Because we want to run the `ng:init="a=a+1` and
`ng:bind="person"` once for each `person in people`, we need to execute {@link
api/angular.widget.@ng:repeat ng:repeat} to make copies of the `<li>` element before we run the
{@link api/angular.directive.ng:init ng:init}, and {@link api/angular.directive.ng:bind ng:bind}
for each of the `<li>`copies.
If you implemented `ng:repeat` as a directive, there would be no guarantee that the attributes
`ng:repeat`, `ng:init`, and `ng:bind` would be evaluated in the order they are declared, because
the order of element attributes in HTML is not significant to the browser.
So, when creating a custom HTML attribute, you will have to consider whether a directive or a
widget is more appropriate. When the order of execution doesn't matter, directives are the right
choice. In a situation where the order matters and one attribute should be processed with a higher
priority than others, use a widget for the attribute that must be processed first.
## Related Topics
* {@link dev_guide.compiler.directives Understanding Angular Directives}
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
## Related API:
* {@link api/angular.directive Directive API}
* {@link api/angular.widget Widget API}
@@ -1,97 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Extending the Angular Compiler
@description
Let's say that we want to create a new DOM element called `<my:greeter/>` that displays a greeting.
We want this HTML source:
<pre>
<div ng:init="s='Hello'; n='World'">
<my:greeter salutation="s" name="n"></my:greeter>
</div>
</pre>
to produce this DOM:
<pre>
<div ng:init="s='Hello'; n='World'">
<my:greeter salutation="s" name="n"/>
<span class="salutation">Hello</span>
<span class="name">World</span>!
</my:greeter>
</div>
</pre>
That is, the new `<my:greeter></my:greeter>` tag's `salutation` and `name` attributes should be
transformed by the compiler such that two `<span>` tags display the values of the attributes, with
CSS classes applied to the output.
The following code snippet shows how to write a following widget definition that will be processed
by the compiler. Note that you have to declare the {@link dev_guide.bootstrap namespace} `my` in
the page:
<pre>
angular.widget('my:greeter', function(compileElement){
var compiler = this;
compileElement.css('display', 'block');
var salutationExp = compileElement.attr('salutation');
var nameExp = compileElement.attr('name');
return function(linkElement){
var salutationSpan = angular.element('<span class="salutation"></span');
var nameSpan = angular.element('<span class="name"></span>');
linkElement.append(salutationSpan);
linkElement.append(' ');
linkElement.append(nameSpan);
linkElement.append('!');
this.$watch(salutationExp, function(value){
salutationSpan.text(value);
});
this.$watch(nameExp, function(value){
nameSpan.text(value);
});
};
});
</pre>
Note: For more about widgets, see {@link dev_guide.compiler.widgets Understanding Angular Widgets}
and the {@link api/angular.widget widget API reference page}.
# Compilation process for `<my:greeter>`
Here are the steps that the compiler takes in processing the page that contains the widget
definition above:
## Compile Phase
1. Recursively traverse the DOM depth-first.
2. Find the angular.widget definition.
3. Find and execute the widget's compileElement function, which includes the following steps:
1. Add a style element with attribute display: block; to the template DOM so that the browser
knows to treat the element as block element for rendering. (Note: because this style element was
added on the template compileElement, this style is automatically applied to any clones of the
template (i.e. any repeating elements)).
2. Extract the salutation and name HTML attributes as angular expressions.
4. Return the aggregate link function, which includes just one link function in this example.
## Link Phase
1. Execute the aggregate link function, which includes the following steps:
1. Create a <span> element set to the salutation class
2. Create a <span> element set to the name class.
2. Add the span elements to the linkElement. (Note: be careful not to add them to the
compileElement, because that's the template.)
3. Set up watches on the expressions. When an expression changes, copy the data to the
corresponding spans.
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
## Related API
* {@link api/angular.compile angular.compile()}
@@ -1,93 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Understanding Angular Markup
@description
Markup in angular is a feature that you can use in templates to transform the content of DOM
elements prior to the compile phase (in which elements are compiled and link functions are
returned. See the {@link dev_guide.compiler compiler docs} for details on how the compiler
works.) The ability to make pre-compile changes to DOM elements lets you create shorthand for
{@link api/angular.widget widget} and {@link api/angular.directive directive} declarations.
Angular provides one built-in markup feature: the double curly-braces used to declare binding
points (between the model and view) for angular expressions. You can also create your own custom
markup.
# Using Double Curly-brace Markup (`{{ }}`)
The double curly-brace (`{{ }}`) markup translates an enclosed expression into an {@link
api/angular.directive.ng:bind ng:bind} directive:
<pre>
{{expression}}
</pre>
is transformed to:
<pre>
<span ng:bind="expression"></span>
</pre>
Markup is useful for the simple reason that `{{1+2}}` is easier to write and understand than `<span
ng:bind="1+2"></span>`. After markup shorthand is expanded into the DOM elements it represents, the
expanded elements are then {@link dev_guide.compiler compiled} normally.
# Creating Custom Markup
Let's say you want to define markup that transforms `---` into a horizontal rule (`<hr/>`):
<pre>
header
---
footer
</pre>
should translate to:
<pre>
header
<hr/>
footer
</pre>
Here is how you could extend the angular compiler to create the "---" markup:
<pre>
angular.markup('---', function(text, textNode, parentElement) {
var compiler = this;
var index = text.indexOf('---');
if (index > -1) {
textNode.after(text.substring(index + 3));
textNode.after(angular.element('<hr>'));
textNode.after(text.substring(0, index));
textNode.remove();
}
});
</pre>
Unlike the way the compiler processes {@link api/angular.widget widgets} and {@link
api/angular.directive directives} (matching the name of the handler function to a DOM element or
attribute name), the compiler calls every markup handler for every text node, giving the handler a
chance to transform the text. The markup handler needs to find all the matches in the text.
## Attribute Markup
Attribute markup extends the angular compiler in a very similar way to markup, except that it
allows you to modify the state of attribute text rather then the content of a node.
<pre>
angular.attrMarkup('extraClass', function(attrValue, attrName, element){
if (attrName == 'additional-class') {
element.addClass(attrValue);
}
});
</pre>
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
## Related API
* {@link api/angular.compile Compiler API Reference}
@@ -1,27 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler
@description
The core of angular is its HTML compiler. The compiler processes angular directives, widgets, and
markup to transform a static HTML page into a dynamic web application.
The default HTML transformations that the angular compiler provides are useful for building generic
apps, but you can also extend the compiler to create a domain-specific language for building
specific types of web applications.
All compilation takes place in the web browser; no server is involved.
## Related Topics
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
* {@link dev_guide.compiler.directives Understanding Angular Directives}
* {@link dev_guide.compiler.markup Understanding Angular Markup}
## Related API
* {@link api/angular.compile Angular Compiler API}
@@ -1,18 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Testing a New DOM Element
@description
"Testing, testing, come in, over?"
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
## Related API
* {@link api/angular.compile angular.compile()}
@@ -1,69 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Understanding How the Compiler Works
@description
Every {@link api/angular.widget widget}, {@link api/angular.directive directive} and {@link
dev_guide.compiler.markup markup} is defined with a compile function, which the angular compiler
executes on each widget or directive it encounters. The compile function optionally returns a link
function. This compilation process happens automatically when the page is loaded when you specify
`ng:autobind` in the script tag from which you load the angular script file. (See {@link
dev_guide.bootstrap Initializing Angular}.)
The compile and link functions are related as follows:
* **compile function** — Registers a listener for the widget, directive, or markup expression. The
compiler calls this function exactly once.
* **link function** — Sets up the listener registered by the compile function. This function can be
called multiple times, once per cloned DOM element. For example, in the case of the {@link
api/angular.widget.@ng:repeat repeater widget} used in a list element (`<li ng:repeat="[item in
dataset]"`), the link function gets called to set up a listener on each element in the list.
Note that angular's built-in widgets, directives, and markup have predefined compile and link
functions that you don't need to modify. When you create your own widgets, directives, or markup,
you must write compile and link functions for them. Refer to the {@link api/angular.compile
Compiler API} for details.
When the angular compiler compiles a page, it proceeds through 3 phases: Compile, Create Root
Scope, and Link:
1. Compile Phase
1. Recursively traverse the DOM, depth-first.
2. Look for a matching compile function of type widget, then markup, then directive.
3. If a compile function is found then execute it.
4. When the compile function completes, it should return a link function. Aggregate this link
function with all link functions returned previously by step 3.
5. Repeat steps 3 and 4 for all compile functions found.
The result of the compilation phase is an aggregate link function, which comprises all of the
individual link functions.
2. Create Root Scope Phase
* Inject all services into the root scope.
3. Link Phase
1. Execute the aggregate link function with the root scope. The aggregate link function calls
all of the individual link functions that were generated in the compile phase.
2. If there are any clones of the DOM caused by repeating elements, call the link function
multiple times, one for each repeating item.
Note that while the compile function is executed exactly once, the link function can be executed
multiple times, for example, once for each iteration in a repeater.
The angular compiler exposes methods that you will need to make use of when writing your own
widgets and directives. For information on these methods, see the {@link api/angular.compile
Compiler API doc}.
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
## Related API
* {@link api/angular.compile angular.compile()}
@@ -1,96 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Widgets: Creating Custom Widgets
@description
When you create your own widgets, you must set up your own namespace for them. (See
dev_guide.bootstrap Initializing Angular} for information about namespaces in angular.)
Let's say we would like to create a new element type in the namespace `my` that can watch an
expression and `alert()` the user with each new value:
<pre>
// An element widget
<my:watch exp="name"></my:watch>
</pre>
You can implement `my:watch` like this:
<pre>
angular.widget('my:watch', function(compileElement) {
var compiler = this;
var exp = compileElement.attr('exp');
return function(linkElement) {
var currentScope = this;
currentScope.$watch(exp, function(value){
alert(value);
});
};
});
</pre>
# Creating a Custom Attribute Widget
Let's implement the same widget as in the example in Defining an Element Widget, but this time as
an attribute that can be added to any existing DOM element:
<pre>
// An attribute widget (my:watch) in a div tag
<div my:watch="name">text</div>
</pre>
You can implement `my:watch` attribute like this:
<pre>
angular.widget('@my:watch', function(expression, compileElement) {
var compiler = this;
return function(linkElement) {
var currentScope = this;
currentScope.$watch(expression, function(value) {
alert(value);
});
};
});
</pre>
# Live Example of a Custom Element Widget
<doc:example>
<doc:source>
<script>
angular.widget('my:time', function(compileElement){
compileElement.css('display', 'block');
return function(linkElement){
function update(){
linkElement.text('Current time is: ' + new Date());
setTimeout(update, 1000);
}
update();
};
});
</script>
<my:time></my:time>
</doc:source>
<doc:scenario>
</doc:scenario>
</doc:example>
# Additional Compiler Methods for Custom Widgets
The angular compiler exposes methods that you may need to use of when writing your own widgets and
directives. For example, the `descend()` method lets you control whether the compiler ignores or
processes child elements of the element it is compiling. For information on this and other
compiler methods, see the {@link api/angular.compile Compiler API doc}.
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.directives Angular Directives}
* {@link dev_guide.compiler.widgets Angular Widgets}
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
## Related API
* {@link api/angular.compile Compiler API}
@@ -1,36 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Understanding Angular Widgets
@description
Widgets are DOM elements that the browser doesn't already understand. Angular provides some
built-in widgets (such as {@link api/angular.widget.@ng:repeat ng:repeat}), and you can create your
own custom widgets.
Widgets are intended to manipulate the DOM tree by adding new elements (unlike {@link
dev_guide.compiler.directives angular directives}, which are intended to modify only element
properties).
Widgets come in two types:
* Element Widget — A custom DOM element. An example of a custom element is shown in {@link
dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
* Attribute Widget — A custom attribute on an existing DOM element. An attribute widget is similar
to an angular directive, with the main difference being that an attribute widget will always be
processed before any directives that are specified on the same element. Only one attribute widget
is allowed per element. An example of an attribute widget is shown in {@link
dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.directives Angular Directives}
* {@link dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
## Related API
* {@link api/angular.compile Compiler API}
-33
View File
@@ -1,33 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: About Dependency Injection (DI)
@description
Dependency Injection (DI) is an object-oriented software design pattern that supports the
decoupling and dependency management of application components.
The idea behind DI is to decouple each component from all of the other components that it depends
on to do its particular job. The way this is done in DI is by moving the responsibility for
managing dependencies out of each individual component and into a provider component. The provider
(or injector) component manages the life cycles and dependencies for all of the other components in
an application.
Angular has a built-in dependency management subsystem that helps to make your applications easier
to develop, understand, and test.
For more information on DI in general, see {@link http://en.wikipedia.org/wiki/Dependency_injection
Dependency Injection} at Wikipedia, and {@link http://martinfowler.com/articles/injection.html
Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
book.
## Related Topics
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
* {@link dev_guide.services Angular Services}
## Related API
* {@link api/angular.service Service API}
* {@link api/angular.injector Angular Injector API}
@@ -1,106 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: DI: Understanding DI in Angular
@description
While DI is widely used in statically typed languages such as Java or C++, it has not been widely
used in JavaScript. Angular brings the benefits of DI into JavaScript apps.
In angular, DI is implemented as a subsystem that manages dependencies between services,
controllers, widgets, and filters. The most important of these are {@link api/angular.service
services}.
Services are objects that handle common tasks in web applications. Angular provides several{@link
api/angular.service built-in services}, and you can create your own custom services.
The main job of angular's DI subsystem is to provide services to angular components that depend on
them. The way the DI subsystem provides services is as follows: all services are registered with
angular's {@link api/angular.service service API}, and all components that depend on services
define those dependencies as a property (`$inject`). With this information, the DI subsystem
manages the creation of service objects and the provision of those objects to the components that
need them, at the time they need them. The following illustration steps through the sequence of
events:
<img src="img/guide/di_sequence_final.png">
In the illustration above, the dependency injection sequence proceeds as follows:
1. Service factory functions are registered with angular's service factory repository.
2. `ng:autobind` triggers angular's bootstrap sequence, during which angular compiles the template,
creates the root scope, and creates the dependency injector.
3. The `ng:controller` directive implicitly creates a new child scope, augmented by the application
of the `PhoneListCtrl` controller function.
4. The Injector identifies the `$xhr` service as `PhoneListCtrl` controller's only dependency.
5. The Injector checks if the `$xhr` service has already been instantiated, and if not uses the
factory function from the service factory repository to construct it.
6. DI provides the instance of $xhr service to the PhoneListCtrl controller constructor
## How Scope Relates to DI
The {@link api/angular.injector injector} is responsible for resolving the service dependencies in
the application. It gets created and configured with the creation of a root scope. The injector
caches instances of services, with the services cache bound to the root scope.
Different root scopes have different instances of the injector. While typical angular applications
will only have one root scope (and hence the services will act like application singletons), in
tests it is important to not share singletons across test invocations for isolation reasons. We
achieve the necessary isolation by having each test create its own separate root scope.
<pre>
// create a root scope
var rootScope = angular.scope();
// access the service locator
var myService = rootScope.$service('myService');
</pre>
## Inferring dependencies from the signature of the factory function or constructor
**EXPERIMENTAL FEATURE**: This is an experimental feature. See the important note at the end of
this section for drawbacks.
We resort to `$inject` and our own annotation because there is no way in JavaScript to get a list
of arguments. Or is there? It turns out that calling `.toString()` on a function returns the
function declaration along with the argument names as shown below:
<pre>
function myFn(a,b){}
expect(myFn.toString()).toEqual('function myFn(a,b){}');
</pre>
This means that angular can infer the function names after all and use that information to generate
the `$inject` annotation automatically. Therefore the following two function definitions are
equivalent:
<pre>
// given a user defined service
angular.service('serviceA', ...);
// inject '$window', 'serviceA', curry 'name';
function fnA($window, serviceA, name){};
fnA.$inject = ['$window', 'serviceA'];
// inject '$window', 'serviceA', curry 'name';
function fnB($window, serviceA_, name){};
// implies: fnB.$inject = ['$window', 'serviceA'];
</pre>
If angular does not find a `$inject` annotation on the function, then it calls the `.toString()`
method and tries to infer what should be injected by using function argument names as dependency
identifiers.
**IMPORTANT**
Minifiers/obfuscators change the names of function arguments and will therefore break the `$inject`
inference. For this reason, either explicitly declare the `$inject` or do not use
minifiers/obfuscators. In the future, we may provide a pre-processor which will scan the source
code and insert the `$inject` into the source code so that it can be minified/obfuscated.
## Related Topics
* {@link dev_guide.services Angular Services}
## Related API
* {@link api/angular.service Services API}
@@ -1,54 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: DI: Using DI in Controllers
@description
The most common place to use dependency injection in angular applications is in {@link
dev_guide.mvc.understanding_controller controllers}. Here is a simple example:
<pre>
function MyController($route){
// configure the route service
$route.when(...);
}
MyController.$inject = ['$route'];
</pre>
In this example, the `MyController` constructor function takes one argument, the {@link
api/angular.service.$route $route} service. Angular is then responsible for supplying the instance
of `$route` to the controller when the constructor is instantiated. There are two ways to cause
controller instantiation by configuring routes with the `$route` service, or by referencing the
controller from the HTML template, as follows:
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org" ng:controller="MyController">
<script src="http://code.angularjs.org/angular.min.js" ng:autobind></script>
<body>
...
</body>
</html>
</pre>
When angular is instantiating your controller, it needs to know what services, if any, should be
injected (passed in as arguments) into the controller. Since there is no reflection in JavaScript,
we have to supply this information to angular in the form of an additional property on the
controller constructor function called `$inject`. Think of it as annotations for JavaScript.
<pre>
MyController.$inject = ['$route'];
</pre>
The information in `$inject` is then used by the {@link api/angular.injector injector} to call the
function with the correct arguments.
## Related Topics
* {@link dev_guide.di About Dependency Injection}
* {@link dev_guide.di.understanding_di Understanding Dependency Injection in Angular}
* {@link dev_guide.services Angular Services}
## Related API
* {@link api/angular.injector Angular Injector API}
@@ -0,0 +1,308 @@
@workInProgress
@ngdoc overview
@name Developer Guide: E2E Testing
@description
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.
To solve this problem, we have built an Angular Scenario Runner which simulates user interactions
that will help you verify the health of your Angular application.
# Overview
You will write scenario tests in JavaScript, which describe how your application should behave,
given a certain interaction in a specific state. A scenario is comprised of one or more `it` blocks
(you can think of these as the requirements of your application), which in turn are made of
**commands** and **expectations**. Commands tell the Runner to do something with the application
(such as navigate to a page or click on a button), and expectations tell the Runner to assert
something about the state (such as the value of a field or the current URL). If any expectation
fails, the runner marks the `it` as "failed" and continues on to the next one. Scenarios may also
have **beforeEach** and **afterEach** blocks, which will be run before (or after) each `it` block,
regardless of whether they pass or fail.
<img src="img/guide/scenario_runner.png">
In addition to the above elements, scenarios may also contain helper functions to avoid duplicating
code in the `it` blocks.
Here is an example of a simple scenario:
<pre>
describe('Buzz Client', function() {
it('should filter results', function() {
input('user').enter('jacksparrow');
element(':button').click();
expect(repeater('ul li').count()).toEqual(10);
input('filterText').enter('Bees');
expect(repeater('ul li').count()).toEqual(1);
});
});
</pre>
This scenario describes the requirements of a Buzz Client, specifically, that it should be able to
filter the stream of the user. It starts by entering a value in the 'user' input field, clicking
the only button on the page, and then it verifies that there are 10 items listed. It then enters
'Bees' in the 'filterText' input field and verifies that the list is reduced to a single item.
The API section below lists the available commands and expectations for the Runner.
# API
Source: {@link https://github.com/angular/angular.js/blob/master/src/ngScenario/dsl.js}
## pause()
Pauses the execution of the tests until you call `resume()` in the console (or click the resume
link in the Runner UI).
## sleep(seconds)
Pauses the execution of the tests for the specified number of `seconds`.
## browser().navigateTo(url)
Loads the `url` into the test frame.
## browser().navigateTo(url, fn)
Loads the URL returned by `fn` into the testing frame. The given `url` is only used for the test
output. Use this when the destination URL is dynamic (that is, the destination is unknown when you
write the test).
## browser().reload()
Refreshes the currently loaded page in the test frame.
## browser().window().href()
Returns the window.location.href of the currently loaded page in the test frame.
## browser().window().path()
Returns the window.location.pathname of the currently loaded page in the test frame.
## browser().window().search()
Returns the window.location.search of the currently loaded page in the test frame.
## browser().window().hash()
Returns the window.location.hash (without `#`) of the currently loaded page in the test frame.
## browser().location().url()
Returns the {@link api/ng.$location $location.url()} of the currently loaded page in
the test frame.
## browser().location().path()
Returns the {@link api/ng.$location $location.path()} of the currently loaded page in
the test frame.
## browser().location().search()
Returns the {@link api/ng.$location $location.search()} of the currently loaded page
in the test frame.
## browser().location().hash()
Returns the {@link api/ng.$location $location.hash()} of the currently loaded page in
the test frame.
## expect(future).{matcher}
Asserts the value of the given `future` satisfies the `matcher`. All API statements return a
`future` object, which get a `value` assigned after they are executed. Matchers are defined using
`angular.scenario.matcher`, and they use the value of futures to run the expectation. For example:
`expect(browser().location().href()).toEqual('http://www.google.com')`. Available matchers
are presented further down this document.
## expect(future).not().{matcher}
Asserts the value of the given `future` satisfies the negation of the `matcher`.
## using(selector, label)
Scopes the next DSL element selection.
## binding(name)
Returns the value of the first binding matching the given `name`.
## input(name).enter(value)
Enters the given `value` in the text field with the corresponding ng-model `name`.
## input(name).check()
Checks/unchecks the checkbox with the corresponding ng-model `name`.
## input(name).select(value)
Selects the given `value` in the radio button with the corresponding ng-model `name`.
## input(name).val()
Returns the current value of an input field with the corresponding ng-model `name`.
## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
used for test output.
## repeater(selector, label).row(index)
Returns an array with the bindings in the row at the given `index` in the repeater matching the
given jQuery `selector`. The `label` is used for test output.
## repeater(selector, label).column(binding)
Returns an array with the values in the column with the given `binding` in the repeater matching
the given jQuery `selector`. The `label` is used for test output.
## select(name).option(value)
Picks the option with the given `value` on the select with the given `name`.
## select(name).options(value1, value2...)
Picks the options with the given `values` on the multi select with the given `name`.
## element(selector, label).count()
Returns the number of elements that match the given jQuery `selector`. The `label` is used for test
output.
## element(selector, label).click()
Clicks on the element matching the given jQuery `selector`. The `label` is used for test output.
## element(selector, label).query(fn)
Executes the function `fn(selectedElements, done)`, where selectedElements are the elements that
match the given jQuery `selector` and `done` is a function that is called at the end of the `fn`
function. The `label` is used for test output.
## element(selector, label).{method}()
Returns the result of calling `method` on the element matching the given jQuery `selector`, where
`method` can be any of the following jQuery methods: `val`, `text`, `html`, `height`,
`innerHeight`, `outerHeight`, `width`, `innerWidth`, `outerWidth`, `position`, `scrollLeft`,
`scrollTop`, `offset`. The `label` is used for test output.
## element(selector, label).{method}(value)
Executes the `method` passing in `value` on the element matching the given jQuery `selector`, where
`method` can be any of the following jQuery methods: `val`, `text`, `html`, `height`,
`innerHeight`, `outerHeight`, `width`, `innerWidth`, `outerWidth`, `position`, `scrollLeft`,
`scrollTop`, `offset`. The `label` is used for test output.
## element(selector, label).{method}(key)
Returns the result of calling `method` passing in `key` on the element matching the given jQuery
`selector`, where `method` can be any of the following jQuery methods: `attr`, `prop`, `css`. The
`label` is used for test output.
## element(selector, label).{method}(key, value)
Executes the `method` passing in `key` and `value` on the element matching the given jQuery
`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
be negated with `not()`. For instance: `expect(element('h1').text()).not().toEqual('Error')`.
Source: {@link https://github.com/angular/angular.js/blob/master/src/ngScenario/matchers.js}
<pre>
// value and Object comparison following the rules of angular.equals().
expect(value).toEqual(value)
// a simpler value comparison using ===
expect(value).toBe(value)
// checks that the value is defined by checking its type.
expect(value).toBeDefined()
// the following two matchers are using JavaScript's standard truthiness rules
expect(value).toBeTruthy()
expect(value).toBeFalsy()
// verify that the value matches the given regular expression. The regular
// expression may be passed in form of a string or a regular expression
// object.
expect(value).toMatch(expectedRegExp)
// a check for null using ===
expect(value).toBeNull()
// Array.indexOf(...) is used internally to check whether the element is
// contained within the array.
expect(value).toContain(expected)
// number comparison using < and >
expect(value).toBeLessThan(expected)
expect(value).toBeGreaterThan(expected)
</pre>
# Example
See the {@link https://github.com/angular/angular-seed angular-seed} project for more examples.
## Conditional actions with element(...).query(fn)
E2E testing with angular scenario is highly asynchronous and hides a lot of complexity by
queueing actions and expectations that can handle futures. From time to time, you might need
conditional assertions or element selection. Even though you should generally try to avoid this
(as it is can be sign for unstable tests), you can add conditional behavior with
`element(...).query(fn)`. The following code listing shows how this function can be used to delete
added entries (where an entry is some domain object) using the application's web interface.
Imagine the application to be structured into two views:
1. *Overview view* which lists all the added entries in a table and
2. a *detail view* which shows the entries' details and contains a delete button. When clicking the
delete button, the user is redirected back to the *overview page*.
<pre>
beforeEach(function () {
var deleteEntry = function () {
browser().navigateTo('/entries');
// we need to select the <tbody> element as it might be the case that there
// are no entries (and therefore no rows). When the selector does not
// result in a match, the test would be marked as a failure.
element('table tbody').query(function (tbody, done) {
// ngScenario gives us a jQuery lite wrapped element. We call the
// `children()` function to retrieve the table body's rows
var children = tbody.children();
if (children.length > 0) {
// if there is at least one entry in the table, click on the link to
// the entry's detail view
element('table tbody a').click();
// and, after a route change, click the delete button
element('.btn-danger').click();
}
// if there is more than one entry shown in the table, queue another
// delete action.
if (children.length > 1) {
deleteEntry();
}
// remember to call `done()` so that ngScenario can continue
// test execution.
done();
});
};
// start deleting entries
deleteEntry();
});
</pre>
In order to understand what is happening, we should emphasize that ngScenario calls are not
immediately executed, but queued (in ngScenario terms, we would be talking about adding
future actions). If we had only one entry in our table, than the following future actions
would be queued:
<pre>
// delete entry 1
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
</pre>
For two entries, ngScenario would have to work on the following queue:
<pre>
// delete entry 1
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
// delete entry 2
// indented to represent "recursion depth"
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
</pre>
# Caveats
ngScenario does not work with apps that manually bootstrap using angular.bootstrap. You must use the ng-app directive.
@@ -1,221 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Understanding Angular Expressions
@description
Expressions are {@link dev_guide.templates.databinding bindings} that you write in HTML and embed
in templates in order to create views in angular. Angular expressions are similar but not
equivalent to JavaScript expressions.
For example, these are all valid expressions in angular:
* `1+2={{1+2}}`
* `3*10|currency`
* `Hello {{name}}!`
* `Hello {{'World'}}!`
## Angular Expressions vs. JS Expressions
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
not entirely correct. Angular does not use a simple JavaScript eval of the expression text. You can
think of angular expressions as JavaScript expressions with these differences:
* **Attribute Evaluation:** evaluation of all attributes are against the current scope, not to the
global window as in JavaScript.
* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript.
* **No Control Flow Statements:** you cannot do the following from an angular expression:
conditionals, loops, or throw.
* **Type Augmentation:** the scope expression evaluator augments built-in types.
* **Filters:** you can add filters to an expression, for example to convert raw data into a
human-readable format.
* **The $:** angular reserves this prefix to differentiate its API names from others.
If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
controller method and call that. If you want to `eval()` an angular expression from JavaScript, use
the `Scope:$eval()` method.
## Example
<doc:example>
<doc:source>
1+2={{1+2}}
</doc:source>
<doc:scenario>
it('should calculate expression in binding', function(){
expect(binding('1+2')).toEqual('3');
});
</doc:scenario>
</doc:example>
You can try evaluating different expressions here:
<doc:example>
<doc:source>
<div ng:init="exprs=[]" class="expressions">
Expression:
<input type='text' name="expr" value="3*10|currency" size="80"/>
<button ng:click="exprs.$add(expr)">Evaluate</button>
<ul>
<li ng:repeat="expr in exprs">
[ <a href="" ng:click="exprs.$remove(expr)">X</a> ]
<tt>{{expr}}</tt> => <span ng:bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
</doc:source>
<doc:scenario>
it('should allow user expression testing', function(){
element('.expressions :button').click();
var li = using('.expressions ul').repeater('li');
expect(li.count()).toBe(1);
expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]);
});
</doc:scenario>
</doc:example>
# Attribute Evaluation
Evaluation of all attributes takes place against the current scope. Unlike JavaScript, where names
default to global window properties, angular expressions have to use `$window` to refer to the
global object. For example, if you want to call `alert()`, which is defined on `window`, an
expression must use `$window.alert()`. This is done intentionally to prevent accidental access to
the global state (a common source of subtle bugs).
<doc:example>
<doc:source>
<div class="example2" ng:init="$window = $service('$window')">
Name: <input name="name" type="text" value="World"/>
<button ng:click="($window.mockWindow || $window).alert('Hello ' + name)">Greet</button>
</div>
</doc:source>
<doc:scenario>
it('should calculate expression in binding', function(){
var alertText;
this.addFutureAction('set mock', function($window, $document, done) {
$window.mockWindow = {
alert: function(text){ alertText = text; }
};
done();
});
element(':button:contains(Greet)').click();
expect(this.addFuture('alert text', function(done) {
done(null, alertText);
})).toBe('Hello World');
});
</doc:scenario>
</doc:example>
## Forgiving
Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating `a.b.c` throws
an exception if `a` is not an object. While this makes sense for a general purpose language, the
expression evaluations are primarily used for data binding, which often look like this:
{{a.b.c}}
It makes more sense to show nothing than to throw an exception if `a` is undefined (perhaps we are
waiting for the server response, and it will become defined soon). If expression evaluation wasn't
forgiving we'd have to write bindings that clutter the code, for example: `{{((a||{}).b||{}).c}}`
Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined.
Assignments work the same way in reverse:
a.b.c = 10
...creates the intermediary objects even if a is undefined.
## No Control Flow Statements
You cannot write a control flow statement in an expression. The reason behind this is core to the
angular philosophy that application logic should be in controllers, not in the view. If you need a
conditional (including ternary operators), loop, or to throw from a view expression, delegate to a
JavaScript method instead.
## Type Augmentation
Built-in types have methods like `[].push()`, but the richness of these methods is limited.
Consider the example below, which allows you to do a simple search over a canned set of contacts.
The example would be much more complicated if we did not have the `Array:$filter()`. There is no
built-in method on `Array` called {@link api/angular.Array.filter $filter} and angular doesn't add
it to `Array.prototype` because that could collide with other JavaScript frameworks.
For this reason the scope expression evaluator augments the built-in types to make them act like
they have extra methods. The actual method for `$filter()` is `angular.Array.filter()`. You can
call it from JavaScript.
Extensions: You can further extend the expression vocabulary by adding new methods to
`angular.Array` or `angular.String`, etc.
<doc:example>
<doc:source>
<div ng:init="friends = [
{name:'John', phone:'555-1212'},
{name:'Mary', phone:'555-9876'},
{name:'Mike', phone:'555-4321'},
{name:'Adam', phone:'555-5678'},
{name:'Julie', phone:'555-8765'}]"></div>
Search: <input name="searchText"/>
<table class="example3">
<tr><th>Name</th><th>Phone</th><tr>
<tr ng:repeat="friend in friends.$filter(searchText)">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
</tr>
</table>
</doc:source>
<doc:scenario>
it('should filter the list', function(){
var tr = using('table.example3').repeater('tr.ng-attr-widget');
expect(tr.count()).toBe(5);
input('searchText').enter('a');
expect(tr.count()).toBe(2);
});
</doc:scenario>
</doc:example>
## 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 angular.filter.uppercase.
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.
## Related Topics
* {@link dev_guide.compiler.markup Understanding Angular Markup}
* {@link dev_guide.templates.filters Understanding Angular Filters}
## Related API
* {@link api/angular.compile Angular Compiler API}
+3 -4
View File
@@ -1,19 +1,18 @@
@workInProgress
@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
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 greatly summarized:
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 dev_guide.di dependency injection}, MVC
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
@@ -1,13 +1,9 @@
@workInProgress
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
@description
In angular, a controller is a JavaScript function (type/class) that is used to augment instances of
angular {@link dev_guide.scopes Scope}, excluding the root scope. When you or angular create a new
child scope object via the {@link api/angular.scope.$new scope.$new} API , there is an
option to pass in a controller as a method argument. This will tell angular to associate the
controller with the new scope and to augment its behavior.
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of
angular {@link scope Scope}, excluding the root scope.
Use controllers to:
@@ -16,39 +12,48 @@ Use controllers to:
# Setting up the initial state of a scope object
Typically, when you create an application you need to set up an initial state for an angular scope.
Typically, when you create an application you need to set up an initial state for an Angular scope.
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
to a new angular scope object, which sets up an initial scope state. This means that angular never
to a new Angular scope object, which sets up an initial scope state. This means that Angular never
creates instances of the controller type (by invoking the `new` operator on the controller
constructor). Constructors are always applied to an existing scope object.
You set up the initial state of a scope by creating model properties. For example:
function GreetingCtrl() {
this.greeting = 'Hola!';
}
<pre>
function GreetingCtrl($scope) {
$scope.greeting = 'Hola!';
}
</pre>
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
When a controller function is applied to an angular scope object, the `this` of the controller
function becomes the scope of the angular scope object, so any assignment to `this` within the
controller function happens on the angular scope object.
**NOTE**: Many of the examples in the documentation show the creation of functions
in the global scope. This is only for demonstration purposes - in a real
application you should use the `.controller` method of your Angular module for
your application as follows:
<pre>
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
</pre>
Note also that we use the array notation to explicitly specify the dependency
of the controller on the `$scope` service provided by Angular.
# Adding Behavior to a Scope Object
Behavior on an angular scope object is in the form of scope method properties available to the
Behavior on an Angular scope object is in the form of scope method properties available to the
template/view. This behavior interacts with and modifies the application model.
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
the scope, along with any prototype methods of the controller type, become functions available in
the template/view, and can be invoked via angular expressions and `ng:` event handlers (e.g. {@link
api/angular.directive.ng:click ng:click}). These controller methods are always evaluated within the
context of the angular scope object that the controller function was applied to (which means that
the `this` keyword of any controller method is always bound to the scope that the controller
augments). This is how the second task of adding behavior to the scope is accomplished.
the scope are available in the template/view, and can be invoked via angular expressions
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
# Using Controllers Correctly
@@ -57,7 +62,7 @@ needed for a single view.
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
controllers into services and then using these services in controllers via dependency injection.
This is discussed in the {@link dev_guide.di Dependency Injection} {@link dev_guide.services
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
Services} sections of this guide.
Do not use controllers for:
@@ -65,22 +70,20 @@ 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} for automatic DOM manipulation. If
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in {@link
dev_guide.compiler.widgets widgets} and {@link dev_guide.compiler.directives directives}.
- Input formatting — Use {@link dev_guide.templates.formatters angular formatters} instead.
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
{@link guide/directive directives}.
- Input formatting — Use {@link forms angular form controls} instead.
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
- Run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
- Sharing stateless or stateful code across controllers — Use {@link dev_guide.services angular
services} instead.
- Instantiate or manage the life-cycle of other components (for example, to create service
instances).
- Managing the life-cycle of other components (for example, to create service instances).
# Associating Controllers with Angular Scope Objects
You can associate controllers with scope objects explicitly via the {@link api/angular.scope.$new
scope.$new} api or implicitly via the {@link api/angular.directive.ng:controller ng:controller
directive} or {@link api/angular.service.$route $route service}.
You can associate controllers with scope objects implicitly via the {@link api/ng.directive:ngController ngController
directive} or {@link api/ng.$route $route service}.
## Controller Constructor and Methods Example
@@ -100,37 +103,43 @@ string "very". Depending on which button is clicked, the `spice` model is set to
## A Spicy Controller Example
<pre>
<body ng:controller="SpicyCtrl">
<button ng:click="chiliSpicy()">Chili</button>
<button ng:click="jalapenoSpicy()">Jalapeño</button>
<body ng-controller="SpicyCtrl">
<button ng-click="chiliSpicy()">Chili</button>
<button ng-click="jalapenoSpicy()">Jalapeño</button>
<p>The food is {{spice}} spicy!</p>
</body>
function SpicyCtrl() {
this.spice = 'very';
this.chiliSpicy = function() {
this.spice = 'chili';
function SpicyCtrl($scope) {
$scope.spice = 'very';
$scope.chiliSpicy = function() {
$scope.spice = 'chili';
}
$scope.jalapenoSpicy = function() {
$scope.spice = 'jalapeño';
}
}
SpicyCtrl.prototype.jalapenoSpicy = function() {
this.spice = 'jalapeño';
}
</pre>
Things to notice in the example above:
- The `ng:controller` directive is used to (implicitly) create a scope for our template, and the
- The `ngController` directive is used to (implicitly) create a scope for our template, and the
scope is augmented (managed) by the `SpicyCtrl` controller.
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
starts with capital letter and ends with "Ctrl" or "Controller".
- The JavaScript keyword `this` in the `SpicyCtrl` function is bound to the scope that the
controller augments.
- Assigning a property to `this` creates or updates the model.
- Controller methods can be created through direct assignment to scope (the `chiliSpicy` method) or
as prototype methods of the controller constructor function (the `jalapenoSpicy` method)
- Assigning a property to `$scope` creates or updates the model.
- Controller methods can be created through direct assignment to scope (the `chiliSpicy` method)
- Both controller methods are available in the template (for the `body` element and and its
children).
- NB: Previous versions of Angular (pre 1.0 RC) allowed you to use `this` interchangeably with
the $scope method, but this is no longer the case. Inside of methods defined on the scope
`this` and $scope are interchangeable (angular sets `this` to $scope), but not otherwise
inside your controller constructor.
- NB: Previous versions of Angular (pre 1.0 RC) added prototype methods into the scope
automatically, but this is no longer the case; all methods need to be added manually to
the scope.
Controller methods can also take arguments, as demonstrated in the following variation of the
previous example.
@@ -138,17 +147,17 @@ previous example.
## Controller Method Arguments Example
<pre>
<body ng:controller="SpicyCtrl">
<input name="customSpice" value="wasabi">
<button ng:click="spicy('chili')">Chili</button>
<button ng:click="spicy(customSpice)">Custom spice</button>
<body ng-controller="SpicyCtrl">
<input ng-model="customSpice" value="wasabi">
<button ng-click="spicy('chili')">Chili</button>
<button ng-click="spicy(customSpice)">Custom spice</button>
<p>The food is {{spice}} spicy!</p>
</body>
function SpicyCtrl() {
this.spice = 'very';
this.spicy = function(spice) {
this.spice = spice;
function SpicyCtrl($scope) {
$scope.spice = 'very';
$scope.spicy = function(spice) {
$scope.spice = spice;
}
}
</pre>
@@ -161,33 +170,34 @@ input box) in the second button.
## Controller Inheritance Example
Controller inheritance in angular is based on {@link api/angular.scope Scope} inheritance. Let's
Controller inheritance in Angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
have a look at an example:
<pre>
<body ng:controller="MainCtrl">
<body ng-controller="MainCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng:controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p ng:controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
</div>
</body>
function MainCtrl() {
this.timeOfDay = 'morning';
this.name = 'Nikki';
function MainCtrl($scope) {
$scope.timeOfDay = 'morning';
$scope.name = 'Nikki';
}
function ChildCtrl() {
this.name = 'Mattie';
function ChildCtrl($scope) {
$scope.name = 'Mattie';
}
function BabyCtrl() {
this.timeOfDay = 'evening';
this.name = 'Gingerbreak Baby';
function BabyCtrl($scope) {
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbreak Baby';
}
</pre>
Notice how we nested three `ng:controller` directives in our template. This template construct will
Notice how we nested three `ngController` directives in our template. This template construct will
result in 4 scopes being created for our view:
- The root scope
@@ -201,25 +211,23 @@ Inheritance works between controllers in the same way as it does with models. So
examples, all of the models could be replaced with controller methods that return string values.
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
because as we mentioned earlier, controllers are not instantiated directly by angular, but rather
because as we mentioned earlier, controllers are not instantiated directly by Angular, but rather
are applied to the scope object.
## Testing Controllers
The way to test a controller depends upon how complicated the controller is.
- If your controller doesn't use DI or scope methods — create the controller with the `new`
operator and test away. For example:
Although there are many ways to test a controller, one of the best conventions, shown below,
involves injecting the `$rootScope` and `$controller`
Controller Function:
<pre>
function myController() {
this.spices = [{"name":"pasilla", "spiciness":"mild"},
function myController($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
this.spice = "habanero";
$scope.spice = "habanero";
}
</pre>
@@ -227,28 +235,52 @@ Controller Test:
<pre>
describe('myController function', function() {
describe('myController', function(){
var ctrl;
describe('myController', function() {
var scope;
beforeEach(function() {
ctrl = new myController();
});
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
var ctrl = $controller(myController, {$scope: scope});
}));
it('should create "spices" model with 3 spices', function() {
expect(ctrl.spices.length).toBe(3);
expect(scope.spices.length).toBe(3);
});
it('should set the default value of spice', function() {
expect(ctrl.spice).toBe('habanero');
expect(scope.spice).toBe('habanero');
});
});
});
</pre>
- If your controller does use DI or scope methods — create a root scope, then create the controller
in the root scope with `scope.$new(MyController)`. Test the controller using `$eval`, if necessary.
- If you need to test a nested controller that depends on its parent's state — create a root scope,
create a parent scope, create a child scope, and test the controller using $eval if necessary.
If you need to test a nested controller you need to create the same scope hierarchy
in your test that exists in the DOM.
<pre>
describe('state', function() {
var mainScope, childScope, babyScope;
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
childScope = mainScope.$new();
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
babyScope = childScope.$new();
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
}));
it('should have over and selected', function() {
expect(mainScope.timeOfDay).toBe('morning');
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');
});
});
</pre>
## Related Topics
@@ -1,18 +1,17 @@
@workInProgress
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the Model Component
@description
Depending on the context of the discussion in angular documentation, the term _model_ can refer to
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
dev_guide.scopes Scope} object. The name of the property is the model identifier and the value is
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
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
@@ -21,43 +20,43 @@ following ways:
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
occurs in controllers:
function MyCtrl() {
function MyCtrl($scope) {
// create property 'foo' on the MyCtrl's scope
// and assign it an initial value 'bar'
this.foo = 'bar';
$scope.foo = 'bar';
}
* Use an {@link dev_guide.expressions angular expression} with an assignment operator in templates:
* Use an {@link expression angular expression} with an assignment operator in templates:
<button ng:click="{{foos='ball'}}">Click me</button>
<button ng-click="{{foo='bar'}}">Click me</button>
* Use {@link api/angular.directive.ng:init ng:init directive} in templates (for toy/example apps
* 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' ">
<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 name="query" value="fluffy cloud">
<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/angular.widget.@ng:repeat ng:repeater}:
* An iterator declaration in {@link api/ng.directive:ngRepeat ngRepeater}:
<p ng:repeat="phone in phones"></p>
<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:
In Angular, a JavaScript object stops being a model when:
* No angular scope contains a property that references the object.
* 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
* 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:
@@ -1,17 +1,16 @@
@workInProgress
@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
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.
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/angular.directive.ng:controller
ng:controller} and {@link api/angular.widget.ng:view ng:view}, and through bindings of this form:
controller through Angular directives, such as {@link api/ng.directive:ngController
ngController} and {@link api/ng.directive:ngView ngView}, and through bindings of this form:
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
controller function.
-234
View File
@@ -1,234 +0,0 @@
@ngdoc overview
@name Developer Guide: Overview
@description
# What Is Angular?
The short answer: angular is a new, powerful, client-side technology that makes it much easier for
you to create dynamic web sites and complex web apps, all without leaving the comfort of your HTML
/ JavaScript home.
The long answer: it depends on where you're coming from...
* If you're a web designer, you might perceive angular to be a sweet {@link dev_guide.templates
templating} system, that doesn't get in your way and provides you with lots of nice built-ins that
make it easier to do what you want to do.
* If you're a web developer, you might be thrilled that angular functions as an excellent web
framework, one that assists you all the way through the development cycle.
* If you want to go deeper, you can immerse yourself in angular's extensible HTML {@link
dev_guide.compiler compiler} that runs in your browser. The angular compiler teaches your browser
new tricks.
Angular is not just a templating system, but you can create fantastic templates with it. Angular is
not just a web framework, but it features a very nice framework. Angular is not just an extensible
HTML compiler, but the compiler is at the core of Angular. Angular includes all of these
components, along with others. Angular is far greater than the sum of its parts. It is a new,
better way to develop web applications!
## An Introductory Angular Example
Let's say that you are a web designer, and you've spent many thous — erm, hundreds of hours
designing web sites. But at this point, the thought of manipulating the DOM, writing listeners and
input validators, all just to implement a simple form? No. You either don't want to go there in
the first place or you've been there and the thrill is gone.
So look over the following simple example written using angular. Note that it features only the
templating aspect of angular, but this should suffice for now to quickly demonstrate how much
easier a web developer's life can if they're using angular:
<doc:example>
<doc:source>
<b>Invoice:</b>
<br />
<br />
<table>
<tr><td> </td><td> </td>
<tr><td>Quantity</td><td>Cost</td></tr>
<tr>
<td><input name="qty" value="1" ng:validate="integer:0" ng:required /></td>
<td><input name="cost" value="19.95" ng:validate="number" ng:required /></td>
</tr>
</table>
<hr />
<b>Total:</b> {{qty * cost | currency}}
</doc:source>
<!--
<doc:scenario>
it('should show of 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');
});
</doc:scenario>
-->
</doc: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 add an attribute to let the browser know about the angular namespace:
<html xmlns:ng="http://angularjs.org">
This ensures angular runs nicely in all major browsers.
In the `<script>` tag we do two angular setup tasks:
1. We load `angular.js`.
2. The angular {@link api/angular.directive.ng:autobind ng:autobind} directive tells angular to
{@link dev_guide.compiler compile} and manage the whole HTML document.
`<script src="http://code.angularjs.org/0.9.15/angular-0.9.15.min.js"
ng:autobind></script>`
From the `name` attribute of the `<input>` tags, angular automatically sets up two-way data
binding, and we also demonstrate some easy input validation:
Quantity: <input name="qty" value="1" ng:validate="integer:0" ng:required/>
Cost: <input name="cost" value="199.95" ng:validate="number" ng: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 the angular directives, {@link api/angular.widget.@ng:validate ng:validate} and {@link
api/angular.widget.@ng:required ng:required}. You may have noticed that when you enter invalid data
or leave the the input fields blank, the borders turn red color, and the display value disappears.
These `ng:` directives make it easier to implement field validators than coding them in JavaScript,
no? Yes.
And finally, the mysterious `{{ double curly braces }}`:
Total: {{qty * cost | currency}}
This notation, `{{ _expression_ }}`, is a bit of built-in angular {@link dev_guide.compiler.markup
markup}, a shortcut for displaying data to the user. The expression within curly braces gets
transformed by the angular compiler into an angular directive ({@link api/angular.directive.ng:bind
ng:bind}). 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."
# The Angular Philosophy
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.
Not to put too fine a point on it, but if you wanted to add a new label to your application, you
could do so by simply adding text to the HTML template, saving the code, and refreshing your
browser:
<pre>
<span class="label">Hello</span>
</pre>
Or, as in programmatic systems (like {@link http://code.google.com/webtoolkit/ GWT}), you would
have to write the code and then run the code like this:
<pre>
var label = new Label();
label.setText('Hello');
label.setClass('label');
parent.addChild(label);
</pre>
That's one line of markup versus four times as much code.
## More Angular Philosophy
* 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.
Now that we're homing in on what angular is, perhaps now would be a good time to list a few things
that angular is not:
* It's not a Library. You don't just call its functions, although it does provide you with some
utility APIs.
* It's not a DOM Manipulation Library. Angular uses jQuery to manipulate the DOM behind the scenes,
rather than give you functions to manipulate the DOM yourself.
* It's not a Widget Library. There are lots of existing widget libraries that you can integrate
with angular.
* It's not "Just Another Templating System". A part of angular is a templating system. The
templating subsystem of angular is different from the traditional approach for these reasons:
* It Uses HTML/CSS syntax: This makes it easy to read and can be edited with existing HTML/CSS
authoring tools.
* It Extends HTML vocabulary: Angular allows you to create new HTML tags, which expand into
dynamic UI components.
* It Executes in the browser: Removes the round trip to the server for many operations and
creates instant feedback for users as well as developers.
* It Has Bidirectional data binding: The model is the single source of truth. Programmatic
changes to the model are automatically reflected in the view. Any changes by the user to the view
are automatically reflected in the model.
# Why You Want Angular
Angular frees you from the following pain:
* **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 programatically:** 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 programatically 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 an early presentation on angular, but note that substantial development has occurred since
the talk was given in July of 2010.
<object width="480" height="385">
<param name="movie" value="http://www.youtube.com/v/elvcgVSynRg&amp;hl=en_US&amp;fs=1"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/elvcgVSynRg&amp;hl=en_US&amp;fs=1"
type="application/x-shockwave-flash" allowscriptaccess="always"
allowfullscreen="true" width="480" height="385"></embed>
</object>
{@link
https://docs.google.com/present/edit?id=0Abz6S2TvsDWSZDQ0OWdjaF8yNTRnODczazdmZg&hl=en&authkey=CO-b7oID
Presentation}
|
{@link
https://docs.google.com/document/edit?id=1ZHVhqC0apbzPRQcgnb1Ye-bAUbNJ-IlFMyPBPCZ2cYU&hl=en&authkey=CInnwLYO
Source}
@@ -1,39 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Scopes: Applying Controllers to Scopes
@description
When a controller function is applied to a scope, the scope is augmented with the behavior defined
in the controller. The end result is that the scope behaves as if it were the controller:
<pre>
var scope = angular.scope();
scope.salutation = 'Hello';
scope.name = 'World';
expect(scope.greeting).toEqual(undefined);
scope.$watch('name', function(){
this.greeting = this.salutation + ' ' + this.name + '!';
});
expect(scope.greeting).toEqual('Hello World!');
scope.name = 'Misko';
// scope.$eval() will propagate the change to listeners
expect(scope.greeting).toEqual('Hello World!');
scope.$eval();
expect(scope.greeting).toEqual('Hello Misko!');
</pre>
## Related Topics
* {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scopes}
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
* {@link dev_guide.scopes.updating_scopes Updating Angular Scopes}
## Related API
* {@link api/angular.scope Angular Scope API}
-38
View File
@@ -1,38 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Scopes
@description
An angular scope is a JavaScript type defined by angular. Instances of this type are objects that
serve as the context within which all model and controller methods live and get evaluated.
Angular links scope objects to specific points in a compiled (processed) template. This linkage
provides the contexts in which angular creates data-bindings between the model and the view. You
can think of angular scope objects as the medium through which the model, view, and controller
communicate.
In addition to providing the context in which data is evaluated, angular scope objects watch for
model changes. The scope objects also notify all components interested in any model changes (for
example, functions registered through {@link api/angular.scope.$watch $watch}, bindings created by
{@link api/angular.directive.ng:bind ng:bind}, or HTML input elements).
Angular scope objects are responsible for:
* Gluing the model, controller and view template together.
* Providing the mechanism to watch for model changes ({@link api/angular.scope.$watch}).
* Notifying interested components when the model changes ({@link api/angular.scope.$eval}).
* Providing the context in which all controller functions and angular expressions are evaluated.
## Related Topics
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
* {@link dev_guide.scopes.working_scopes Working With Scopes}
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
## Related API
* {@link api/angular.scope Angular Scope API}
@@ -1,69 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Scopes: Understanding Scopes
@description
Angular automatically creates a root scope during initialization, and attaches it to the page's
root DOM element (usually `<html>`). The root scope object, along with any of its child scope
objects, serves as the infrastructure on which your data model is built. The data model (JavaScript
objects, arrays, or primitives) is attached to angular scope properties. Angular binds the property
values to the DOM where bindings are specified in the template. Angular attaches any controller
functions you have created to their respective scope objects.
<img src="img/guide/simple_scope_final.png">
Angular scopes can be nested, so a child scope has a parent scope upstream in the DOM. When you
display an angular expression in the view, angular walks the DOM tree looking in the closest
attached scope object for the specified data. If it doesn't find the data in the closest attached
scope, it looks further up the scope hierarchy until it finds the data.
A child scope object inherits properties from its parents. For example, in the following snippet of
code, observe how the value of `name` changes, based on the HTML element it is displayed in:
<doc:example>
<doc:source>
<ul ng:init="name='Hank'; names=['Igor', 'Misko', 'Gail', 'Kai']">
<li ng:repeat="name in names">
Name = {{name}}!
</li>
</ul>
<pre>Name={{name}}</pre>
</doc:source>
<doc:scenario>
it('should override the name property', function() {
expect(using('.doc-example-live').repeater('li').row(0)).
toEqual(['Igor']);
expect(using('.doc-example-live').repeater('li').row(1)).
toEqual(['Misko']);
expect(using('.doc-example-live').repeater('li').row(2)).
toEqual(['Gail']);
expect(using('.doc-example-live').repeater('li').row(3)).
toEqual(['Kai']);
expect(using('.doc-example-live').element('pre').text()).
toBe('Name=Hank');
});
</doc:scenario>
</doc:example>
The angular {@link api/angular.widget.@ng:repeat ng:repeat} directive creates a new scope for each
element that it repeats (in this example the elements are list items). In the `<ul>` element, we
initialized `name` to "Hank", and we created an array called `names` to use as the data source for
the list items. In each `<li>` element, `name` is overridden. Outside of the `<li>` repeater, the
original value of `name` is displayed.
The following illustration shows the DOM and angular scopes for the example above:
<img src="img/guide/dom_scope_final.png">
## Related Topics
* {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.working_scopes Working With Scopes}
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
## Related API
* {@link api/angular.scope Angular Scope API}
@@ -1,38 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Scopes: Updating Scope Properties
@description
You can update a scope by calling its {@link api/angular.scope.$eval $eval()} method, but usually
you do not have to do this explicitly. In most cases, angular intercepts all external events (such
as user interactions, XHRs, and timers) and calls the `$eval()` method on the scope object for you
at the right time. The only time you might need to call `$eval()` explicitly is when you create
your own custom widget or service.
The reason it is unnecessary to call `$eval()` from within your controller functions when you use
built-in angular widgets and services is because a change in the data model triggers a call to the
`$eval()` method on the scope object where the data model changed.
When a user inputs data, angularized widgets copy the data to the appropriate scope and then call
the `$eval()` method on the root scope to update the view. It works this way because scopes are
inherited, and a child scope `$eval()` overrides its parent's `$eval()` method. Updating the whole
page requires a call to `$eval()` on the root scope as `$root.$eval()`. Similarly, when a request
to fetch data from a server is made and the response comes back, the data is written into the model
and then `$eval()` is called to push updates through to the view and any other dependents.
A widget that creates scopes (such as {@link api/angular.widget.@ng:repeat ng:repeat}) is
responsible for forwarding `$eval()` calls from the parent to those child scopes. That way, calling
`$eval()` on the root scope will update the whole page. This creates a spreadsheet-like behavior
for your app; the bound views update immediately as the user enters data.
## Related Documents
* {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects}
* {@link dev_guide.scopes.working_scopes Working With Angular Scopes}
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
## Related API
* {@link api/angular.scope Angular Scope API}
@@ -1,52 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Scopes: Working With Angular Scopes
@description
When you use {@link api/angular.directive.ng:autobind ng:autobind} to bootstrap your application,
angular creates the root scope automatically for you. If you need more control over the
bootstrapping process, or if you need to create a root scope for a test, you can do so using the
{@link api/angular.scope angular.scope()} API.
Here is a simple code snippet that demonstrates how to create a scope object, assign model
properties to it, and register listeners to watch for changes to the model properties:
<pre>
var scope = angular.scope();
scope.salutation = 'Hello';
scope.name = 'World';
// Verify that greeting is undefined
expect(scope.greeting).toEqual(undefined);
// Set up the watcher...
scope.$watch('name', function(){
// when 'name' changes, set 'greeting'...
this.greeting = this.salutation + ' ' + this.name + '!';
}
);
// verify that 'greeting' was set...
expect(scope.greeting).toEqual('Hello World!');
// 'name' changed!
scope.name = 'Misko';
// scope.$eval() will propagate the change to listeners
expect(scope.greeting).toEqual('Hello World!');
scope.$eval();
// verify that '$eval' propagated the change
expect(scope.greeting).toEqual('Hello Misko!');
</pre>
## Related Topics
* {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
* {@link dev_guide.scopes.controlling_scopes Applying Controllers to Scopes}
* {@link dev_guide.scopes.updating_scopes Updating Scopes}
## Related API
* {@link api/angular.scope Angular Scope API}
@@ -0,0 +1,647 @@
@ngdoc overview
@name Developer Guide: Angular Services: Using $location
@description
# What does it do?
The `$location` service parses the URL in the browser address bar (based on the {@link
https://developer.mozilla.org/en/window.location window.location}) and makes the URL available to
your application. Changes to the URL in the address bar are reflected into $location service and
changes to $location are reflected into the browser address bar.
**The $location service:**
- Exposes the current URL in the browser address bar, so you can
- Watch and observe the URL.
- Change the URL.
- Synchronizes the URL with the browser when the user
- Changes the address bar.
- Clicks the back or forward button (or clicks a History link).
- Clicks on a link.
- Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
## Comparing $location to window.location
<table class="table">
<thead>
<tr>
<th class="empty-corner-lt"></th>
<th>window.location</th>
<th>$location service</th>
</tr>
</thead>
<tbody>
<tr>
<td class="head">purpose</td>
<td>allow read/write access to the current browser location</td>
<td>same</td>
</tr>
<tr>
<td class="head">API</td>
<td>exposes "raw" object with properties that can be directly modified</td>
<td>exposes jQuery-style getters and setters</td>
</tr>
<tr>
<td class="head">integration with angular application life-cycle</td>
<td>none</td>
<td>knows about all internal life-cycle phases, integrates with $watch, ...</td>
</tr>
<tr>
<td class="head">seamless integration with HTML5 API</td>
<td>no</td>
<td>yes (with a fallback for legacy browsers)</td>
</tr>
<tr>
<td class="head">aware of docroot/context from which the application is loaded</td>
<td>no - window.location.path returns "/docroot/actual/path"</td>
<td>yes - $location.path() returns "/actual/path"</td>
</tr>
</tbody>
</table>
## When should I use $location?
Any time your application needs to react to a change in the current URL or if you want to change
the current URL in the browser.
## What does it not do?
It does not cause a full page reload when the browser URL is changed. To reload the page after
changing the URL, use the lower-level API, `$window.location.href`.
# General overview of the API
The `$location` service can behave differently, depending on the configuration that was provided to
it when it was instantiated. The default configuration is suitable for many applications, for
others customizing the configuration can enable new features.
Once the `$location` service is instantiated, you can interact with it via jQuery-style getter and
setter methods that allow you to get or change the current URL in the browser.
## $location service configuration
To configure the `$location` service, retrieve the
{@link api/ng.$locationProvider $locationProvider} and set the parameters as follows:
- **html5Mode(mode)**: {boolean}<br />
`true` - see HTML5 mode<br />
`false` - see Hashbang mode<br />
default: `false`
- **hashPrefix(prefix)**: {string}<br />
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)<br />
default: `""`
### Example configuration
<pre>
$locationProvider.html5Mode(true).hashPrefix('!');
</pre>
## Getter and setter methods
`$location` service provides getter methods for read-only parts of the URL (absUrl, protocol, host,
port) and getter / setter methods for url, path, search, hash:
<pre>
// get the current path
$location.path();
// change the path
$location.path('/newValue')
</pre>
All of the setter methods return the same `$location` object to allow chaining. For example, to
change multiple segments in one go, chain setters like this:
<pre>$location.path('/newValue').search({key: value});</pre>
There is a special `replace` method which can be used to tell the $location service that the next
time the $location service is synced with the browser, the last history record should be replaced
instead of creating a new one. This is useful when you want to implement redirection, which would
otherwise break the back button (navigating back would retrigger the redirection). To change the
current URL without creating a new browser history record you can call:
<pre>
$location.path('/someNewPath');
$location.replace();
// or you can chain these as: $location.path('/someNewPath').replace();
</pre>
Note that the setters don't update `window.location` immediately. Instead, the `$location` service is
aware of the {@link api/ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location`
mutations into one "commit" to the `window.location` object during the scope `$digest` phase. Since
multiple changes to the $location's state will be pushed to the browser as a single change, it's
enough to call the `replace()` method just once to make the entire "commit" a replace operation
rather than an addition to the browser history. Once the browser is updated, the $location service
resets the flag set by `replace()` method and future mutations will create new history records,
unless `replace()` is called again.
### Setters and character encoding
You can pass special characters to `$location` service and it will encode them according to rules
specified in {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}. When you access the methods:
- All values that are passed to `$location` setter methods, `path()`, `search()`, `hash()`, are
encoded.
- Getters (calls to methods without parameters) return decoded values for the following methods
`path()`, `search()`, `hash()`.
- When you call the `absUrl()` method, the returned value is a full url with its segments encoded.
- When you call the `url()` method, the returned value is path, search and hash, in the form
`/path?search=a&b=c#hash`. The segments are encoded as well.
# Hashbang and HTML5 Modes
`$location` service has two configuration modes which control the format of the URL in the browser
address bar: **Hashbang mode** (the default) and the **HTML5 mode** which is based on using the
HTML5 {@link http://www.w3.org/TR/html5/history.html History API}. Applications use the same API in
both modes and the `$location` service will work with appropriate URL segments and browser APIs to
facilitate the browser URL change and history management.
<img src="img/guide/hashbang_vs_regular_url.jpg">
<table class="table">
<thead>
<tr>
<th class="empty-corner-lt"></th>
<th>Hashbang mode</th>
<th>HTML5 mode</th>
</tr>
</thead>
<tbody>
<tr>
<td class="head">configuration</td>
<td>the default</td>
<td>{ html5Mode: true }</td>
</tr>
<tr>
<td class="head">URL format</td>
<td>hashbang URLs in all browsers</td>
<td>regular URLs in modern browser, hashbang URLs in old browser</td>
</tr>
<tr>
<td class="head">&lt;a href=""&gt; link rewriting</td>
<td>no</td>
<td>yes</td>
</tr>
<tr>
<td class="head">requires server-side configuration</td>
<td>no</td>
<td>yes</td>
</tr>
</tbody>
</table>
## Hashbang mode (default mode)
In this mode, `$location` uses Hashbang URLs in all browsers.
### Example
<pre>
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!');
},
function($location) {
// open http://host.com/base/index.html#!/a
$location.absUrl() == 'http://host.com/base/index.html#!/a'
$location.path() == '/a'
$location.path('/foo')
$location.absUrl() == 'http://host.com/base/index.html#!/foo'
$location.search() == {}
$location.search({a: 'b', c: true});
$location.absUrl() == 'http://host.com/base/index.html#!/foo?a=b&c'
$location.path('/new').search('x=y');
$location.absUrl() == 'http://host.com/base/index.html#!/new?x=y'
}
));
</pre>
### Crawling your app
To allow indexing of your AJAX application, you have to add special meta tag in the head section of
your document:
<pre><meta name="fragment" content="!" /></pre>
This will cause crawler bot to request links with `_escaped_fragment_` param so that your server
can recognize the crawler and serve a HTML snapshots. For more information about this technique,
see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX Applications
Crawlable}.
## HTML5 mode
In HTML5 mode, the `$location` service getters and setters interact with the browser URL address
through the HTML5 history API, which allows for use of regular URL path and search segments,
instead of their hashbang equivalents. If the HTML5 History API is not supported by a browser, the
`$location` service will fall back to using the hashbang URLs automatically. This frees you from
having to worry about whether the browser displaying your app supports the history API or not; the
`$location` service transparently uses the best available option.
- Opening a regular URL in a legacy browser -> redirects to a hashbang URL
- Opening hashbang URL in a modern browser -> rewrites to a regular URL
### Example
<pre>
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
},
function($location) {
// in browser with HTML5 history support:
// open http://host.com/#!/a -> rewrite to http://host.com/a
// (replacing the http://host.com/#!/a history record)
$location.path() == '/a'
$location.path('/foo');
$location.absUrl() == 'http://host.com/foo'
$location.search() == {}
$location.search({a: 'b', c: true});
$location.absUrl() == 'http://host.com/foo?a=b&c'
$location.path('/new').search('x=y');
$location.url() == 'new?x=y'
$location.absUrl() == 'http://host.com/new?x=y'
// in browser without html5 history support:
// open http://host.com/new?x=y -> redirect to http://host.com/#!/new?x=y
// (again replacing the http://host.com/new?x=y history item)
$location.path() == '/new'
$location.search() == {x: 'y'}
$location.path('/foo/bar');
$location.path() == '/foo/bar'
$location.url() == '/foo/bar?x=y'
$location.absUrl() == 'http://host.com/#!/foo/bar?x=y'
}
));
</pre>
### Fallback for legacy browsers
For browsers that support the HTML5 history API, `$location` uses the HTML5 history API to write
path and search. If the history API is not supported by a browser, `$location` supplies a Hasbang
URL. This frees you from having to worry about whether the browser viewing your app supports the
history API or not; the `$location` service makes this transparent to you.
### Html link rewriting
When you use HTML5 history API mode, you will need different links in different browsers, but all you
have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
When a user clicks on this link,
- In a legacy browser, the URL changes to `/index.html#!/some?foo=bar`
- In a modern browser, the URL changes to `/some?foo=bar`
In cases like the following, links are not rewritten; instead, the browser will perform a full page
reload to the original link.
- Links that contain `target` element<br>
Example: `<a href="/ext/link?a=b" target="_self">link</a>`
- Absolute links that go to a different domain<br>
Example: `<a href="http://angularjs.org/">link</a>`
- Links starting with '/' that lead to a different base path when base is defined<br>
Example: `<a href="/not-my-base/link">link</a>`
### Server side
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
to entry point of your application (e.g. index.html)
### Crawling your app
If you want your AJAX application to be indexed by web crawlers, you will need to add the following
meta tag to the HEAD section of your document:
<pre><meta name="fragment" content="!" /></pre>
This statement causes a crawler to request links with an empty `_escaped_fragment_` parameter so that
your server can recognize the crawler and serve it HTML snapshots. For more information about this
technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX
Applications Crawlable}.
### Relative links
Be sure to check all relative links, images, scripts etc. You must either specify the url base in
the head of your main html file (`<base href="/my-base">`) or you must use absolute urls
(starting with `/`) everywhere because relative urls will be resolved to absolute urls using the
initial absolute url of the document, which is often different from the root of the application.
Running Angular apps with the History API enabled from document root is strongly encouraged as it
takes care of all relative link issues.
### Sending links among different browsers
Because of rewriting capability in HTML5 mode, your users will be able to open regular url links in
legacy browsers and hashbang links in modern browser:
- Modern browser will rewrite hashbang URLs to regular URLs.
- Older browsers will redirect regular URLs to hashbang URLs.
### Example
Here you can see two `$location` instances, both in **Html5 mode**, but on different browsers, so
that you can see the differences. These `$location` services are connected to a fake browsers. Each
input represents address bar of the browser.
Note that when you type hashbang url into first browser (or vice versa) it doesn't rewrite /
redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL
= on page reload.
In this examples we use `<base href="/base/index.html" />`
<doc:example>
<doc:source source="false">
<div ng-non-bindable class="html5-hashbang-example">
<div id="html5-mode" ng-controller="Html5Cntl">
<h3>Browser with History API</h3>
<div ng-address-bar browser="html5"></div><br><br>
$location.protocol() = {{$location.protocol()}}<br>
$location.host() = {{$location.host()}}<br>
$location.port() = {{$location.port()}}<br>
$location.path() = {{$location.path()}}<br>
$location.search() = {{$location.search()}}<br>
$location.hash() = {{$location.hash()}}<br>
<a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
<div id="hashbang-mode" ng-controller="HashbangCntl">
<h3>Browser without History API</h3>
<div ng-address-bar browser="hashbang"></div><br><br>
$location.protocol() = {{$location.protocol()}}<br>
$location.host() = {{$location.host()}}<br>
$location.port() = {{$location.port()}}<br>
$location.path() = {{$location.path()}}<br>
$location.search() = {{$location.search()}}<br>
$location.hash() = {{$location.hash()}}<br>
<a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
</div>
<script>
function FakeBrowser(initUrl, baseHref) {
this.onUrlChange = function(fn) {
this.urlChange = fn;
};
this.url = function() {
return initUrl;
};
this.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
this.baseHref = function() {
return baseHref;
};
this.notifyWhenOutstandingRequests = angular.noop;
}
var browsers = {
html5: new FakeBrowser('http://www.host.com/base/path?a=b#h', '/base/index.html'),
hashbang: new FakeBrowser('http://www.host.com/base/index.html#!/path?a=b#h', '/base/index.html')
};
function Html5Cntl($scope, $location) {
$scope.$location = $location;
}
function HashbangCntl($scope, $location) {
$scope.$location = $location;
}
function initEnv(name) {
var root = angular.element(document.getElementById(name + '-mode'));
angular.bootstrap(root, [function($compileProvider, $locationProvider, $provide){
$locationProvider.html5Mode(true).hashPrefix('!');
$provide.value('$browser', browsers[name]);
$provide.value('$document', root);
$provide.value('$sniffer', {history: name == 'html5'});
$compileProvider.directive('ngAddressBar', function() {
return function(scope, elm, attrs) {
var browser = browsers[attrs.browser],
input = angular.element('<input type="text">').val(browser.url()),
delay;
input.bind('keypress keyup keydown', function() {
if (!delay) {
delay = setTimeout(fireUrlChange, 250);
}
});
browser.url = function(url) {
return input.val(url);
};
elm.append('Address: ').append(input);
function fireUrlChange() {
delay = null;
browser.urlChange(input.val());
}
};
});
}]);
root.bind('click', function(e) {
e.stopPropagation();
});
}
initEnv('html5');
initEnv('hashbang');
</script>
</doc:source>
</doc:example>
# Caveats
## Page reload navigation
The `$location` service allows you to change only the URL; it does not allow you to reload the
page. When you need to change the URL and reload the page or navigate to a different page, please
use a lower level API, {@link api/ng.$window $window.location.href}.
## Using $location outside of the scope life-cycle
`$location` knows about Angular's {@link api/ng.$rootScope.Scope scope} life-cycle. When a URL changes in
the browser it updates the `$location` and calls `$apply` so that all $watchers / $observers are
notified.
When you change the `$location` inside the `$digest` phase everything is ok; `$location` will
propagate this change into browser and will notify all the $watchers / $observers.
When you want to change the `$location` from outside Angular (for example, through a DOM Event or
during testing) - you must call `$apply` to propagate the changes.
## $location.path() and ! or / prefixes
A path should always begin with forward slash (`/`); the `$location.path()` setter will add the
forward slash if it is missing.
Note that the `!` prefix in the hashbang mode is not part of `$location.path()`; it is actually
hashPrefix.
# Testing with the $location service
When using `$location` service during testing, you are outside of the angular's {@link
api/ng.$rootScope.Scope scope} life-cycle. This means it's your responsibility to call `scope.$apply()`.
<pre>
describe('serviceUnderTest', function() {
beforeEach(module(function($provide) {
$provide.factory('serviceUnderTest', function($location){
// whatever it does...
});
});
it('should...', inject(function($location, $rootScope, serviceUnderTest) {
$location.path('/new/path');
$rootScope.$apply();
// test whatever the service should do...
}));
});
</pre>
# Migrating from earlier AngularJS releases
In earlier releases of Angular, `$location` used `hashPath` or `hashSearch` to process path and
search methods. With this release, the `$location` service processes path and search methods and
then uses the information it obtains to compose hashbang URLs (such as
`http://server.com/#!/path?search=a`), when necessary.
## Changes to your code
<table class="table">
<thead>
<tr class="head">
<th>Navigation inside the app</th>
<th>Change to</th>
</tr>
</thead>
<tbody>
<tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
/>$location.updateHash(value)</td>
<td>$location.path(path).search(search)</td>
</tr>
<tr>
<td>$location.hashPath = path</td>
<td>$location.path(path)</td>
</tr>
<tr>
<td>$location.hashSearch = search</td>
<td>$location.search(search)</td>
</tr>
<tr class="head">
<td>Navigation outside the app</td>
<td>Use lower level API</td>
</tr>
<tr>
<td>$location.href = value<br />$location.update(value)</td>
<td>$window.location.href = value</td>
</tr>
<tr>
<td>$location[protocol | host | port | path | search]</td>
<td>$window.location[protocol | host | port | path | search]</td>
</tr>
<tr class="head">
<td>Read access</td>
<td>Change to</td>
</tr>
<tr>
<td>$location.hashPath</td>
<td>$location.path()</td>
</tr>
<tr>
<td>$location.hashSearch</td>
<td>$location.search()</td>
</tr>
<tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
/>$location.hash</td>
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
/>$location.path() + $location.search()</td>
</tr>
<tr>
<td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.location.search</td>
</tr>
</tbody>
</table>
## Two-way binding to $location
The Angular's compiler currently does not support two-way binding for methods (see {@link
https://github.com/angular/angular.js/issues/404 issue}). If you should require two-way binding
to the $location object (using {@link api/ng.directive:input.text
ngModel} directive on an input field), you will need to specify an extra model property
(e.g. `locationPath`) with two watchers which push $location updates in both directions. For
example:
<example>
<file name="index.html">
<div ng-controller="LocationController">
<input type="text" ng-model="locationPath" />
</div>
</file>
<file name="script.js">
function LocationController($scope, $location) {
$scope.$watch('locationPath', function(path) {
$location.path(path);
});
$scope.$watch(function() {
return $location.path();
}, function(path) {
$scope.locationPath = path;
});
}
</file>
</example>
# Related API
* {@link api/ng.$location $location API}
@@ -1,59 +1,104 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services: Creating Angular Services
@name Developer Guide: Angular Services: Creating Services
@description
While angular offers several useful services, for any nontrivial application you'll find it useful
While Angular offers several useful services, for any nontrivial application you'll find it useful
to write your own custom services. To do this you begin by registering a service factory function
that angular's DI will use to create the service object when it is needed.
with a module either via the {@link api/angular.module Module#factory api} or directly
via the {@link api/AUTO.$provide $provide} api inside of module config function.
The `angular.service` method accepts three parameters:
- `{string} name` - Name of the service.
- `{function()} factory` - Factory function (called just once by DI).
- `{Object} config` - Configuration object with the following properties:
- `$inject` - {Array.<string>} - Array of service ids this service depends on. These services
will be passed as arguments into the factory function in the same order specified in the `$inject`
array. Defaults to `[]`.
- `$eager` - {boolean} - If true, the service factory will be called and the service will be
instantiated when angular boots. If false, the service will be lazily instantiated when it is first
requested during instantiation of a dependant. Defaults to `false`.
The `this` of the factory function is bound to the root scope of the angular application.
All angular services participate in {@link dev_guide.di dependency injection (DI)} by registering
themselves with angular's DI system (injector) under a `name` (id) as well as by declaring
All Angular services participate in {@link di dependency injection (DI)} by registering
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
dependencies which need to be provided for the factory function of the registered service. The
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
testable.
# Registering Services
To register a service, you must have a module that this service will be part of. Afterwards, you
can register the service with the module either via the {@link api/angular.Module Module api} or
by using the {@link api/AUTO.$provide $provide} service in the module configuration
function.The following pseudo-code shows both approaches:
Using the angular.Module api:
<pre>
var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
</pre>
Using the $provide service:
<pre>
angular.module('myModule', [], function($provide) {
$provide.factory('serviceId', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
});
</pre>
Note that you are not registering a service instance, but rather a factory function that will
create this instance when called.
# Dependencies
Services can not only be depended upon, but can also have their own dependencies. These can be specified
as arguments of the factory function. {@link di Read more} about dependency injection (DI)
in Angular and the use of array notation and the $inject property to make DI annotation
minification-proof.
Following is an example of a very simple service. This service depends on the `$window` service
(which is passed as a parameter to the factory function) and is just a function. The service simply
stores all notifications; after the third one, the service displays all of the notifications by
window alert.
<pre>
angular.service('notify', function(win) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}, {$inject: ['$window']});
angular.module('myModule', [], function($provide) {
$provide.factory('notify', ['$window', function(win) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}]);
});
</pre>
# Instantiating Angular Services
All services in Angular are instantiated lazily. This means that a service will be created
only when it is needed for instantiation of a service or an application component that depends on it.
In other words, Angular won't instantiate services unless they are requested directly or
indirectly by the application.
# Services as singletons
Lastly, it is important to realize that all Angular services are application singletons. This means
that there is only one instance of a given service per injector. Since Angular is lethally allergic
to global state, it is possible to create multiple injectors, each with its own instance of a
given service, but that is rarely needed, except in tests where this property is crucially
important.
## Related Topics
* {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.registering_services Registering Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
* {@link dev_guide.services.testing_services Testing Angular Services}
## Related API
* {@link api/angular.service Angular Service API}
* {@link api/ng Angular Service API}
@@ -1,4 +1,3 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services: Injecting Services Into Controllers
@description
@@ -7,12 +6,12 @@ Using services as dependencies for controllers is very similar to using services
for another service.
Since JavaScript is a dynamic language, DI can't figure out which services to inject by static
types (like in static typed languages). Therefore, you must specify the service name by using the
types (like in static typed languages). Therefore, you can specify the service name by using the
`$inject` property, which is an array containing strings with names of services to be injected.
The name must match the corresponding service ID registered with angular. The order of the service
IDs matters: the order of the services in the array will be used when calling the factory function
with injected parameters. The names of parameters in factory function don't matter, but by
convention they match the service IDs.
convention they match the service IDs, which has added benefits discussed below.
<pre>
function myController($loc, $log) {
@@ -29,51 +28,93 @@ this.secondMethod = function() {
myController.$inject = ['$location', '$log'];
</pre>
<doc:example>
<doc:example module="MyServiceModule">
<doc:source>
<script type="text/javascript">
angular.service('notify', function(win) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}, {$inject: ['$window']});
<script>
angular.
module('MyServiceModule', []).
factory('notify', ['$window', function(win) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}]);
function myController(notifyService) {
this.callNotify = function(msg) {
function myController(scope, notifyService) {
scope.callNotify = function(msg) {
notifyService(msg);
};
}
myController.$inject = ['notify'];
myController.$inject = ['$scope','notify'];
</script>
<div ng:controller="myController">
<p>Let's try this simple notify service, injected into the controller...</p>
<input ng:init="message='test'" type="text" name="message" />
<button ng:click="callNotify(message);">NOTIFY</button>
<div ng-controller="myController">
<p>Let's try this simple notify service, injected into the controller...</p>
<input ng-init="message='test'" ng-model="message" >
<button ng-click="callNotify(message);">NOTIFY</button>
<p>(you have to click 3 times to see an alert)</p>
</div>
</doc:source>
<doc:scenario>
it('should test service', function(){
expect(element(':input[name=message]').val()).toEqual('test');
});
it('should test service', function() {
expect(element(':input[ng\\:model="message"]').val()).toEqual('test');
});
</doc:scenario>
</doc:example>
## Implicit Dependency Injection
A new feature of Angular DI allows it to determine the dependency from the name of the parameter.
Let's rewrite the above example to show the use of this implicit dependency injection of
`$window`, `$scope`, and our `notify` service:
<doc:example module="MyServiceModuleDI">
<doc:source>
<script>
angular.
module('MyServiceModuleDI', []).
factory('notify', function($window) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
$window.alert(msgs.join("\n"));
msgs = [];
}
};
});
function myController($scope, notify) {
$scope.callNotify = function(msg) {
notify(msg);
};
}
</script>
<div ng-controller="myController">
<p>Let's try the notify service, that is implicitly injected into the controller...</p>
<input ng-init="message='test'" ng-model="message">
<button ng-click="callNotify(message);">NOTIFY</button>
<p>(you have to click 3 times to see an alert)</p>
</div>
</doc:source>
</doc:example>
However, if you plan to {@link http://en.wikipedia.org/wiki/Minification_(programming) minify} your
code, your variable names will get renamed in which case you will still need to explicitly specify
dependencies with the `$inject` property.
## Related Topics
{@link dev_guide.services.understanding_services Understanding Angular Services}
{@link dev_guide.services.creating_services Creating Angular Services}
{@link dev_guide.services.registering_services Registering Angular Services}
{@link dev_guide.services.managing_dependencies Managing Service Dependencies}
{@link dev_guide.services.testing_services Testing Angular Services}
## Related API
{@link api/angular.service Angular Service API}
{@link api/ng Angular Service API}
@@ -1,4 +1,3 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services: Managing Service Dependencies
@description
@@ -6,80 +5,110 @@
Angular allows services to declare other services as dependencies needed for construction of their
instances.
To declare dependencies, you specify them in the factory function signature and via the `$inject`
property, as an array of string identifiers. Optionally the `$inject` property declaration can be
To declare dependencies, you specify them in the factory function signature and annotate the
function with the inject annotations either using by setting the `$inject` property, as an array of
string identifiers or using the array notation. Optionally the `$inject` property declaration can be
dropped (see "Inferring `$inject`" but note that that is currently an experimental feature).
Here is an example of two services that depend on each other, as well as on other services that are
provided by angular's web framework:
Using the array notation:
<pre>
function myModuleCfgFn($provide) {
$provide.factory('myService', ['dep1', 'dep2', function(dep1, dep2) {}]);
}
</pre>
Using the $inject property:
<pre>
function myModuleCfgFn($provide) {
var myServiceFactory = function(dep1, dep2) {};
myServiceFactory.$inject = ['dep1', 'dep2'];
$provide.factory('myService', myServiceFactory);
}
</pre>
Using DI inference (incompatible with minifiers):
<pre>
function myModuleCfgFn($provide) {
$provide.factory('myService', function(dep1, dep2) {});
}
</pre>
Here is an example of two services, one of which depends on the other and both
of which depend on other services that are provided by the Angular framework:
<pre>
/**
* batchLog service allows for messages to be queued in memory and flushed
* to the console.log every 50 seconds.
*
* @param {*} message Message to be logged.
*/
angular.service('batchLog', function($defer, $log) {
var messageQueue = [];
* batchLog service allows for messages to be queued in memory and flushed
* to the console.log every 50 seconds.
*
* @param {*} message Message to be logged.
*/
function batchLogModule($provide){
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
var messageQueue = [];
function log() {
if (messageQueue.length) {
$log('batchLog messages: ', messageQueue);
messageQueue = [];
}
$defer(log, 50000);
function log() {
if (messageQueue.length) {
$log('batchLog messages: ', messageQueue);
messageQueue = [];
}
$timeout(log, 50000);
}
// start periodic checking
log();
return function(message) {
messageQueue.push(message);
}
}]);
/**
* routeTemplateMonitor monitors each $route change and logs the current
* template via the batchLog service.
*/
$provide.factory('routeTemplateMonitor',
['$route', 'batchLog', '$rootScope',
function($route, batchLog, $rootScope) {
$rootScope.$on('$routeChangeSuccess', function() {
batchLog($route.current ? $route.current.template : null);
});
}]);
}
// start periodic checking
log();
return function(message) {
messageQueue.push(message);
}
}, {$inject: ['$defer', '$log']});
// note how we declared dependency on built-in $defer and $log services above
/**
* routeTemplateMonitor monitors each $route change and logs the current
* template via the batchLog service.
*/
angular.service('routeTemplateMonitor', function($route, batchLog) {
$route.onChange(function() {
batchLog($route.current ? $route.current.template : null);
});
}, {$inject: ['$route', 'batchLog'], $eager: true});
// get the main service to kick of the application
angular.injector([batchLogModule]).get('routeTemplateMonitor');
</pre>
Things to notice in this example:
* The `batchLog` service depends on the built-in {@link api/angular.service.$defer $defer} and
{@link api/angular.service.$log $log} services, and allows messages to be logged into the
* The `batchLog` service depends on the built-in {@link api/ng.$timeout $timeout} and
{@link api/ng.$log $log} services, and allows messages to be logged into the
`console.log` in batches.
* The `routeTemplateMonitor` service depends on the built-in {@link api/angular.service.$route
* The `routeTemplateMonitor` service depends on the built-in {@link api/ng.$route
$route} service as well as our custom `batchLog` service.
* The `routeTemplateMonitor` service is declared to be eager, so that it is started as soon as the
application starts.
* To underline the need for the eager instantiation of the `routeTemplateMonitor` service, nothing
else in the application depends on this service, and in this particular case the factory function
of this service doesn't return anything at all.
* Both of our services use the factory function signature as well as the `$inject` property to
declare their dependencies. It is important that the order of the string identifiers in the array
associated with the `$inject` property is the same as the order of argument names in the signature
of the factory function. Unless the dependencies are inferred from the function signature, it is
this array with IDs and their order that the injector uses to determine which services and in which
order to inject.
* Both of our services use the factory function signature and array notation for inject annotations
to declare their dependencies. It is important that the order of the string identifiers in the array
is the same as the order of argument names in the signature of the factory function. Unless the
dependencies are inferred from the function signature, it is this array with IDs and their order
that the injector uses to determine which services and in which order to inject.
## Related Topics
* {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.registering_services Registering Services}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
* {@link dev_guide.services.testing_services Testing Angular Services}
## Related API
* {@link api/angular.service Angular Service API}
* {@link api/ng Angular Service API}
* {@link api/angular.injector Angular Injector API}
+5 -8
View File
@@ -1,23 +1,20 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services
@description
Services are a feature that angular brings to client-side web apps from the server side, where
services have been commonly used for a long time. Services in angular apps are substitutable
objects that are wired together using {@link dev_guide.di dependency injection (DI)}. Services are
most often used with {@link dev_guide.di dependency injection}, also a key feature of angular apps.
Services are a feature that Angular brings to client-side web apps from the server side, where
services have been commonly used for a long time. Services in Angular apps are substitutable
objects that are wired together using {@link di dependency injection (DI)}.
## Related Topics
* {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.registering_services Registering Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
* {@link dev_guide.services.testing_services Testing Angular Services}
## Related API
* {@link api/angular.service Angular Service API}
* {@link api/ng Angular Service API}
@@ -1,70 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services: Registering Angular Services
@description
To register a service, register a factory function that creates the service with angular's
Injector. The Injector is exposed as {@link api/angular.scope.$service scope.$service}. The
following pseudo-code shows a simple service registration:
<pre>
angular.service('service id', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
</pre>
Note that you are not registering a service instance, but rather a factory function that will
create this instance when called.
# Instantiating Angular Services
A service can be instantiated eagerly or lazily. By default angular instantiates services lazily,
which means that a service will be created only when it is needed for instantiation of a service or
an application component that depends on it. In other words, angular won't instantiate lazy
services unless they are requested directly or indirectly by the application.
Eager services on the other hand, are instantiated right after the injector itself is created,
which happens when the angular {@link dev_guide.bootstrap application initializes}.
To override the default, you can request that a service is eagerly instantiated as follows:
<pre>
angular.service('service id', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
}, {$eager: true});
</pre>
While it is tempting to declare services as eager, only in few cases it is actually useful. If you
are unsure whether to make a service eager, it likely doesn't need to be. To be more specific, a
service should be declared as eager only if it fits one of these scenarios:
* Nothing in your application declares this service as its dependency, and this service affects the
state or configuration of the application (e.g. a service that configures `$route` or `$resource`
services)
* A guarantee is needed that the service will be instantiated at application boot time, usually
because the service passively observes the application and it is optional for other application
components to depend on it. An example of this scenario is a service that monitors and logs
application memory usage.
Lastly, it is important to realize that all angular services are applicaiton singletons. This means
that there is only one instance of a given service per injector. Since angular is lethally allergic
to the global state, it is possible to create multiple injectors, each with its own instance of a
given service, but that is rarely needed, except in tests where this property is crucially
important.
## Related Topics
* {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers }
* {@link dev_guide.services.testing_services Testing Angular Services}
## Related API
* {@link api/angular.service Angular Service API}
@@ -1,9 +1,8 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services: Testing Angular Services
@description
Following is a unit test for the service in the example in {@link
The following is a unit test for the 'notify' service in the 'Dependencies' example in {@link
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine
spy (mock) instead of a real browser alert.
@@ -12,7 +11,14 @@ var mock, notify;
beforeEach(function() {
mock = {alert: jasmine.createSpy()};
notify = angular.service('notify')(mock);
module(function($provide) {
$provide.value('$window', mock);
});
inject(function($injector) {
notify = $injector.get('notify');
});
});
it('should not alert first two notifications', function() {
@@ -48,12 +54,9 @@ it('should clear messages after alert', function() {
* {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.registering_services Registering Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
## Related API
* {@link api/angular.service Angular Service API}
* {@link api/ng Angular Service API}
@@ -1,38 +1,36 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Angular Services: Understanding Angular Services
@description
Angular services are singletons that carry out specific tasks common to web apps, such as the
{@link api/angular.service.$xhr $xhr service} that provides low level access to the browser's
{@link api/ng.$http $http service} that provides low level access to the browser's
`XMLHttpRequest` object.
To use an angular service, you identify it as a dependency for the dependent (a controller, or
To use an Angular service, you identify it as a dependency for the dependent (a controller, or
another service) that depends on the service. Angular's dependency injection subsystem takes care
of the rest. The angular injector subsystem is in charge of service instantiation, resolution of
of the rest. The Angular injector subsystem is in charge of service instantiation, resolution of
dependencies, and provision of dependencies to factory functions as requested.
Angular injects dependencies using "constructor" injection (the service is passed in via a factory
function). Because JavaScript is a dynamically typed language, angular's dependency injection
function). Because JavaScript is a dynamically typed language, Angular's dependency injection
subsystem cannot use static types to identify service dependencies. For this reason a dependent
must explicitly define its dependencies by using the `$inject` property. For example:
myController.$inject = ['$location'];
The angular web framework provides a set of services for common operations. Like other core angular
variables and identifiers, the built-in services always start with `$` (such as `$xhr` mentioned
The Angular web framework provides a set of services for common operations. Like other core Angular
variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned
above). You can also create your own custom services.
## Related Topics
* {@link dev_guide.di About Angular Dependency Injection}
* {@link di About Angular Dependency Injection}
* {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.registering_services Registering Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.testing_services Testing Angular Services}
## Related API
* {@link api/angular.service Angular Service API}
* {@link api/ng Angular Service API}
* {@link api/angular.injector Injector API}
@@ -0,0 +1,23 @@
@ngdoc overview
@name Developer Guide: Templates: Working With CSS in Angular
@description
Angular sets these CSS classes. It is up to your application to provide useful styling.
# CSS classes used by angular
* `ng-invalid`, `ng-valid`
- **Usage:** angular applies this class to an input widget element if that element's input does
not pass validation. (see {@link api/ng.directive:input input} directive).
* `ng-pristine`, `ng-dirty`
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
to a new input widget element which did not have user interaction. Once the user interacts with
the input widget the class is changed to `ng-dirty`.
## Related Topics
* {@link dev_guide.templates Angular Templates}
* {@link forms Angular Forms}
@@ -1,52 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Working With CSS in Angular
@description
Angular includes built-in CSS classes, which in turn have predefined CSS styles.
# Built-in CSS classes
* `ng-exception`
**Usage:** angular applies this class to a DOM element if that element contains an Expression that
threw an exception when evaluated.
**Styling:** The built-in styling of the ng-exception class displays an error message surrounded
by a solid red border, for example:
<div class="ng-exception">Error message</div>
You can try to evaluate malformed expressions in {@link dev_guide.expressions expressions} to see
the `ng-exception` class' styling.
* `ng-validation-error`
**Usage:** angular applies this class to an input widget element if that element's input does not
pass validation. Note that you set the validation criteria on the input widget element using the
Ng:validate or Ng:required directives.
**Styling:** The built-in styling of the ng-validation-error class turns the border of the input
box red and includes a hovering UI element that includes more details of the validation error. You
can see an example in {@link api/angular.widget.@ng:validate ng:validate example}.
## Overriding Styles for Angular CSS Classes
To override the styles for angular's built-in CSS classes, you can do any of the following:
* Download the source code, edit angular.css, and host the source on your own server.
* Create a local CSS file, overriding any styles that you'd like, and link to it from your HTML file
as you normally would:
<pre>
<link href="yourfile.css" rel="stylesheet" type="text/css">
</pre>
## Related Topics
* {@link dev_guide.templates Angular Templates}
* {@link dev_guide.templates.css Working With CSS in Angular}
* {@link dev_guide.templates.formatters Angular Formatters}
* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters}
@@ -1,10 +1,9 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Data Binding in Angular
@description
Data-binding in angular web apps is the automatic syncing of data between the model and view
components. The way that angular implements data-binding lets you treat the model as the
Data-binding in Angular web apps is the automatic syncronization of data between the model and view
components. The way that Angular implements data-binding lets you treat the model as the
single-source-of-truth in your application. The view is a projection of the model at all times.
When the model changes, the view reflects the change, and vice versa.
@@ -20,12 +19,12 @@ to write code that constantly syncs the view with the model and the model with t
## Data Binding in Angular Templates
<img class="right" src="img/Two_Way_Data_Binding.png"/>
The way angular templates works is different, as illustrated in the diagram. They are different
The way Angular templates works is different, as illustrated in the diagram. They are different
because first the template (which is the uncompiled HTML along with any additional markup or
directives) is compiled on the browser, and second, the compilation step produces a live view. We
say live because any changes to the view are immediately reflected in the model, and any changes in
the model are propagated to the view. This makes the model always the single-source-of-truth for
the application state, greatly simplifying the programing model for the developer. You can think of
the application state, greatly simplifying the programming model for the developer. You can think of
the view as simply an instant projection of your model.
Because the view is just a projection of the model, the controller is completely separated from the
@@ -35,5 +34,5 @@ isolation without the view and the related DOM/browser dependency.
## Related Topics
* {@link dev_guide.scopes Angular Scopes}
* {@link scope Angular Scopes}
* {@link dev_guide.templates Angular Templates}
@@ -1,54 +1,51 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Filters: Creating Angular Filters
@description
Writing your own filter is very easy: just define a JavaScript function on the `angular.filter`
object.
The framework passes in the input value as the first argument to your function. Any filter
arguments are passed in as additional function arguments.
You can use these variables in the function:
* `this` — The current scope.
* `this.$element` — The DOM element containing the binding. The `$element` variable allows the
filter to manipulate the DOM.
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 and assigns color.
text upper-case.
<doc:example>
<doc:example module="MyReverseModule">
<doc:source>
<script type="text/javascript">
angular.filter('reverse', function(input, uppercase, color) {
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();
}
// DOM manipulation using $element
if (color) {
this.$element.css('color', color);
}
return out;
});
<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>
<input name="text" type="text" value="hello" /><br>
No filter: {{text}}<br>
Reverse: {{text|reverse}}<br>
Reverse + uppercase: {{text|reverse:true}}<br>
Reverse + uppercase + blue: {{text|reverse:true:"blue"}}
<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 text', function(){
expect(binding('text|reverse')).toEqual('olleh');
input('text').enter('ABC');
expect(binding('text|reverse')).toEqual('CBA');
});
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>
@@ -56,8 +53,8 @@ expect(binding('text|reverse')).toEqual('CBA');
## Related Topics
* {@link dev_guide.templates.filters Understanding Angular Filters}
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link compiler Angular HTML Compiler}
## Related API
* {@link api/angular.filter Angular Filter API}
* {@link api/ng.$filter Angular Filter API}
@@ -1,21 +1,16 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Understanding Angular Filters
@description
Angular filters format data for display to the user. In addition to formatting data, filters can
also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles
to filtered output.
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 `angular.filter.uppercase()`.
In addition to formatting data, filters can also modify the DOM. This allows filters to handle
tasks such as conditionally applying CSS styles to filtered output.
The expression evaluator simply passes the value of name to
{@link api/ng.filter:uppercase uppercase filter}.
## Related Topics
@@ -25,4 +20,4 @@ tasks such as conditionally applying CSS styles to filtered output.
## Related API
* {@link api/angular.filter Angular Filter API}
* {@link api/ng.$filter Angular Filter API}
@@ -1,9 +1,8 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Filters: Using Angular Filters
@description
Filters can be part of any {@link api/angular.scope} evaluation but are typically used to format
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 }}
@@ -20,6 +19,10 @@ You can also pass colon-delimited arguments to filters, for example, to display
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:
@@ -38,4 +41,4 @@ argument that specifies how many digits to display to the right of the decimal p
## Related API
* {@link api/angular.filter Angular Filter API}
* {@link api/ng.$filter Angular Filter API}
@@ -1,55 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Angular Formatters: Creating Angular Formatters
@description
To create your own formatter, you can simply register a pair of JavaScript functions with
`angular.formatter`. One of your functions is used to parse text from the input widget into the
data storage format; the other function is used to format stored data into user-readable text.
The following example demonstrates a "reverse" formatter. Data is stored in uppercase and in
reverse, but it is displayed in lower case and non-reversed. When a user edits the data model via
the input widget, the input is automatically parsed into the internal data storage format, and when
the data changes in the model, it is automatically formatted to the user-readable form for display
in the view.
<pre>
function reverse(text) {
var reversed = [];
for (var i = 0; i < text.length; i++) {
reversed.unshift(text.charAt(i));
}
return reversed.join('');
}
angular.formatter('reverse', {
parse: function(value){
return reverse(value||'').toUpperCase();
},
format: function(value){
return reverse(value||'').toLowerCase();
}
});
</pre>
<doc:example>
<doc:source>
<script type="text/javascript">
function reverse(text) {
var reversed = [];
for (var i = 0; i < text.length; i++) {
reversed.unshift(text.charAt(i));
}
return reversed.join('');
}
angular.formatter('reverse', {
parse: function(value){
return reverse(value||'').toUpperCase();
},
format: function(value){
return reverse(value||'').toLowerCase();
}
});
</script>
@@ -1,20 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Angular Formatters
@description
In angular, formatters are responsible for translating user-readable text entered in an {@link
api/angular.widget.HTML input widget} to a JavaScript object in the data model that the application
can manipulate.
You can use formatters in a template, and also in JavaScript. Angular provides built-in
formatters, and of course you can create your own formatters.
## Related Topics
* {@link dev_guide.templates.formatters.using_formatters Using Angular Formatters}
* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters}
## Related API
* {@link api/angular.formatter Angular Formatter API}
@@ -1,9 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Angular Formatters: Using Angular Formatters
@description
The following snippet shows how to use a formatter in a template. The formatter below is
`ng:format="reverse"`, added as an attribute to an `<input>` tag.
<pre>
+20 -26
View File
@@ -1,44 +1,39 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Understanding Angular Templates
@description
An angular template is the declarative specification that, along with information from the model
An Angular template is the declarative specification that, along with information from the model
and controller, becomes the rendered view that a user sees in the browser. It is the static DOM,
containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The
angular elements and attributes direct angular to add behavior and transform the template DOM into
Angular elements and attributes direct angular to add behavior and transform the template DOM into
the dynamic view DOM.
These are the types of angular elements and element attributes you can use in a template:
These are the types of Angular elements and element attributes you can use in a template:
* {@link dev_guide.compiler.directives Directive} — An attribute that augments an existing DOM
element.
* {@link dev_guide.compiler.widgets Widget} — A custom DOM element. An example of a built-in widget
is {@link api/angular.widget.@ng:repeat ng:repeat}.
* {@link dev_guide.compiler.markup Markup} — Shorthand for a widget or a directive. The double
* {@link guide/directive Directive} — An attribute or element that
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 dev_guide.templates.validators Validator} — Lets you validate user input.
* {@link dev_guide.templates.formatters Formatter} — Lets you format the input object into a user
readable view.
* {@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
in JavaScript code.
The following code snippet shows a simple angular template made up of standard HTML tags along with
angular {@link dev_guide.compiler.directives directives}, {@link dev_guide.compiler.markup markup},
and {@link dev_guide.expressions expressions}:
The following code snippet shows a simple Angular template made up of standard HTML tags along with
Angular {@link guide/directive directives} and curly-brace bindings
with {@link expression expressions}:
<pre>
<html>
<!-- Body tag augmented with ng:controller directive -->
<body ng:controller="MyController">
<input name="foo" value="bar">
<!-- Button tag with ng:click directive, and
<html ng-app>
<!-- Body tag augmented with ngController directive -->
<body ng-controller="MyController">
<input ng-model="foo" value="bar">
<!-- Button tag with ng-click directive, and
string expression 'buttonText'
wrapped in "{{ }}" markup -->
<button ng:click="changeFoo()">{{buttonText}}</button>
<script src="angular.js" ng:autobind>
<button ng-click="changeFoo()">{{buttonText}}</button>
<script src="angular.js">
</body>
</html>
</pre>
@@ -46,8 +41,8 @@ and {@link dev_guide.expressions expressions}:
In a simple single-page app, the template consists of HTML, CSS, and angular directives contained
in just one HTML file (usually `index.html`). In a more complex app, you can display multiple views
within one main page using "partials", which are segments of template located in separate HTML
files. You "include" the partials in the main page using the {@link api/angular.service.$route
$route} service in conjunction with the {@link api/angular.widget.ng:view ng:view} directive. An
files. You "include" the partials in the main page using the {@link api/ng.$route
$route} service in conjunction with the {@link api/ng.directive:ngView ngView} directive. An
example of this technique is shown in the {@link tutorial/ angular tutorial}, in steps seven and
eight.
@@ -55,8 +50,7 @@ eight.
## Related Topics
* {@link dev_guide.templates.filters Angular Filters}
* {@link dev_guide.templates.formatters Angular Formatters}
* {@link dev_guide.templates.validators Angular Validators}
* {@link forms Angular Forms}
## Related API
@@ -1,82 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Validators: Creating Angular Validators
@description
To create a custom validator, you simply add your validator code as a method onto the
`angular.validator` object and provide input(s) for the validator function. Each input provided is
treated as an argument to the validator function. Any additional inputs should be separated by
commas.
The following bit of pseudo-code shows how to set up a custom validator:
<pre>
angular.validator('your_validator', function(input [,additional params]) {
[your validation code];
if ( [validation succeeds] ) {
return false;
} else {
return true; // No error message specified
}
}
</pre>
Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true,
there was a problem with that input". If you prefer to provide more information when a validator
detects a problem with input, you can specify an error message in the validator that angular will
display when the user hovers over the input widget.
To specify an error message, replace "`return true;`" with an error string, for example:
return "Must be a value between 1 and 5!";
Following is a sample UPS Tracking Number validator:
<doc:example>
<doc:source>
<script>
angular.validator('upsTrackingNo', function(input, format) {
var regexp = new RegExp("^" + format.replace(/9/g, '\\d') + "$");
return input.match(regexp)?"":"The format must match " + format;
});
</script>
<input type="text" name="trackNo" size="40"
ng:validate="upsTrackingNo:'1Z 999 999 99 9999 999 9'"
value="1Z 123 456 78 9012 345 6"/>
</doc:source>
<doc:scenario>
it('should validate correct UPS tracking number', function() {
expect(element('input[name=trackNo]').attr('class')).
not().toMatch(/ng-validation-error/);
});
it('should not validate in correct UPS tracking number', function() {
input('trackNo').enter('foo');
expect(element('input[name=trackNo]').attr('class')).
toMatch(/ng-validation-error/);
});
</doc:scenario>
</doc:example>
In this sample validator, we specify a regular expression against which to test the user's input.
Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it
returns the specified error message ("true").
Note: you can also access the current angular scope and DOM element objects in your validator
functions as follows:
* `this` === The current angular scope.
* `this.$element` === The DOM element that contains the binding. This allows the filter to
manipulate the DOM in addition to transforming the input.
## Related Topics
* {@link dev_guide.templates Angular Templates}
* {@link dev_guide.templates.filters Angular Filters}
* {@link dev_guide.templates.formatters Angular Formatters}
## Related API
* {@link api/angular.validator API Validator Reference}
@@ -1,131 +0,0 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Templates: Understanding Angular Validators
@description
Angular validators are attributes that test the validity of different types of user input. Angular
provides a set of built-in input validators:
* {@link api/angular.validator.phone phone number}
* {@link api/angular.validator.number number}
* {@link api/angular.validator.integer integer}
* {@link api/angular.validator.date date}
* {@link api/angular.validator.email email address}
* {@link api/angular.validator.json JSON}
* {@link api/angular.validator.regexp regular expressions}
* {@link api/angular.validator.url URLs}
* {@link api/angular.validator.asynchronous asynchronous}
You can also create your own custom validators.
# Using Angular Validators
You can use angular validators in HTML template bindings, and in JavaScript:
* Validators in HTML Template Bindings
<pre>
<input ng:validator="validator_type:parameters" [...]>
</pre>
* Validators in JavaScript
<pre>
angular.validator.[validator_type](parameters)
</pre>
The following example shows how to use the built-in angular integer validator:
<doc:example>
<doc:source>
Change me: <input type="text" name="number" ng:validate="integer" value="123">
</doc:source>
<doc:scenario>
it('should validate the default number string', function() {
expect(element('input[name=number]').attr('class')).
not().toMatch(/ng-validation-error/);
});
it('should not validate "foo"', function() {
input('number').enter('foo');
expect(element('input[name=number]').attr('class')).
toMatch(/ng-validation-error/);
});
</doc:scenario>
</doc:example>
# Creating an Angular Validator
To create a custom validator, you simply add your validator code as a method onto the
`angular.validator` object and provide input(s) for the validator function. Each input provided is
treated as an argument to the validator function. Any additional inputs should be separated by
commas.
The following bit of pseudo-code shows how to set up a custom validator:
<pre>
angular.validator('your_validator', function(input [,additional params]) {
[your validation code];
if ( [validation succeeds] ) {
return false;
} else {
return true; // No error message specified
}
}
</pre>
Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true,
there was a problem with that input". If you prefer to provide more information when a validator
detects a problem with input, you can specify an error message in the validator that angular will
display when the user hovers over the input widget.
To specify an error message, replace "`return true;`" with an error string, for example:
return "Must be a value between 1 and 5!";
Following is a sample UPS Tracking Number validator:
<doc:example>
<doc:source>
<script>
angular.validator('upsTrackingNo', function(input, format) {
var regexp = new RegExp("^" + format.replace(/9/g, '\\d') + "$");
return input.match(regexp)?"":"The format must match " + format;
});
</script>
<input type="text" name="trackNo" size="40"
ng:validate="upsTrackingNo:'1Z 999 999 99 9999 999 9'"
value="1Z 123 456 78 9012 345 6"/>
</doc:source>
<doc:scenario>
it('should validate correct UPS tracking number', function() {
expect(element('input[name=trackNo]').attr('class')).
not().toMatch(/ng-validation-error/);
});
it('should not validate in correct UPS tracking number', function() {
input('trackNo').enter('foo');
expect(element('input[name=trackNo]').attr('class')).
toMatch(/ng-validation-error/);
});
</doc:scenario>
</doc:example>
In this sample validator, we specify a regular expression against which to test the user's input.
Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it
returns the specified error message ("true").
Note: you can also access the current angular scope and DOM element objects in your validator
functions as follows:
* `this` === The current angular scope.
* `this.$element` === The DOM element that contains the binding. This allows the filter to
manipulate the DOM in addition to transforming the input.
## Related Topics
* {@link dev_guide.templates Angular Templates}
## Related API
* {@link api/angular.validator Validator API}
+133 -72
View File
@@ -1,40 +1,51 @@
@workInProgress
@ngdoc overview
@name Developer Guide: Unit Testing
@description
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
comes 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 do it.
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
# It is all about NOT mixing concerns
Unit testing as the name implies is about testing individual units of code. Unit tests try to
answer the question: Did I think about the logic correctly. 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 it.
That is because when we are testing the sort function we don't want to be forced into crating
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort. While
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.
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 time mix concerns, and they end up with 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
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 crated abstraction which
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
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. 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, you may very well end up with an untestable application.
DOM in the right way.
## Dependency Inject
## 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.
## 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 know place, also known as global singleton.
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? Must likely by looking it up in a well know place. See #2)
4. You could expect that the it be handed to you.
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.
Out of the list above only the last of is testable. Lets look at why:
Out of the four options in the list above, only the last one is testable. Let's look at why:
### Using the `new` operator
@@ -43,25 +54,25 @@ on a constructor permanently binds the call site to the type. For example lets s
trying to instantiate an `XHR` so that we can get some data from the server.
<pre>
function MyClass(){
this.doWork = function(){
function MyClass() {
this.doWork = function() {
var xhr = new XHR();
xhr.open(method, url, true);
xhr.onreadystatechange = function(){...}
xhr.onreadystatechange = function() {...}
xhr.send();
}
}
</pre>
The issue becomes, that in tests, we would very much like to instantiate a `MockXHR` which would
The issue becomes that in tests, we would very much like to instantiate a `MockXHR` which would
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
permanently bound to the actual one, and there is no good way to replace it. Yes there is monkey
patching, that is a bad idea for many reasons, which is outside the scope of this document.
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.
The class above is hard to test since we have to resort to monkey patching:
<pre>
var oldXHR = XHR;
XHR = function MockXHR(){};
XHR = function MockXHR() {};
var myClass = new MyClass();
myClass.doWork();
// assert that MockXHR got called with the right arguments
@@ -70,11 +81,11 @@ XHR = oldXHR; // if you forget this bad things will happen
### Global look-up:
Another way to approach the problem is 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(){
this.doWork = function(){
function MyClass() {
this.doWork = function() {
global.xhr({
method:'...',
url:'...',
@@ -84,17 +95,17 @@ function MyClass(){
}
</pre>
While no new instance of dependency is being created, it is fundamentally the same as `new`, in
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
through monkey patching. The basic issue for testing is that global variable needs to be mutated in
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
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:
<pre>
var oldXHR = glabal.xhr;
glabal.xhr = function mockXHR(){};
var oldXHR = global.xhr;
global.xhr = function mockXHR() {};
var myClass = new MyClass();
myClass.doWork();
// assert that mockXHR got called with the right arguments
@@ -110,7 +121,7 @@ having the tests replace the services as needed.
<pre>
function MyClass() {
var serviceRegistry = ????;
this.doWork = function(){
this.doWork = function() {
var xhr = serviceRegistry.get('xhr');
xhr({
method:'...',
@@ -120,19 +131,19 @@ function MyClass() {
}
</pre>
However, where dose the serviceRegistry come from? if it is:
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).
The class above is hard to test since we have to change global state:
<pre>
var oldServiceLocator = glabal.serviceLocator;
glabal.serviceLocator.set('xhr', function mockXHR(){});
var oldServiceLocator = global.serviceLocator;
global.serviceLocator.set('xhr', function mockXHR() {});
var myClass = new MyClass();
myClass.doWork();
// assert that mockXHR got called with the right arguments
glabal.serviceLocator = oldServiceLocator; // if you forget this bad things will happen
global.serviceLocator = oldServiceLocator; // if you forget this bad things will happen
</pre>
@@ -141,7 +152,7 @@ Lastly the dependency can be passed in.
<pre>
function MyClass(xhr) {
this.doWork = function(){
this.doWork = function() {
xhr({
method:'...',
url:'...',
@@ -165,7 +176,7 @@ myClass.doWork();
Notice that no global variables were harmed in the writing of this test.
Angular comes with {@link dev_guide.di dependency-injection} built in which makes the right thing
Angular comes with {@link di dependency injection} built in which makes the right thing
easy to do, but you still need to do it if you wish to take advantage of the testability story.
## Controllers
@@ -174,13 +185,13 @@ for your application is mixed in with DOM manipulation, it will be hard to test
below:
<pre>
function PasswordController(){
function PasswordCtrl() {
// get references to DOM elements
var msg = $('.ex1 span');
var input = $('.ex1 input');
var strength;
this.grade = function(){
this.grade = function() {
msg.removeClass(strength);
var pwd = input.val();
password.text(pwd);
@@ -198,7 +209,7 @@ function PasswordController(){
}
</pre>
The code above is problematic from testability, 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>
@@ -208,7 +219,7 @@ $('body').html('<div class="ex1">')
.find('div')
.append(input)
.append(span);
var pc = new PasswordController();
var pc = new PasswordCtrl();
input.val('abc');
pc.grade();
expect(span.text()).toEqual('weak');
@@ -219,62 +230,112 @@ In angular the controllers are strictly separated from the DOM manipulation logi
a much easier testability story as can be seen in this example:
<pre>
function PasswordCntrl(){
this.password = '';
this.grade = function(){
var size = this.password.length;
function PasswordCtrl($scope) {
$scope.password = '';
$scope.grade = function() {
var size = $scope.password.length;
if (size > 8) {
this.strength = 'strong';
$scope.strength = 'strong';
} else if (size > 3) {
this.strength = 'medium';
$scope.strength = 'medium';
} else {
this.strength = 'weak';
$scope.strength = 'weak';
}
};
}
</pre>
and the tests is straight forward
and the test is straight forward
<pre>
var pc = new PasswordController();
pc.password('abc');
pc.grade();
expect(span.strength).toEqual('weak');
var $scope = {};
var pc = $controller('PasswordCtrl', { $scope: $scope });
$scope.password = 'abc';
$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
that such a test tells a story, rather then asserting random bits which don't seem to be related.
## Filters
{@link api/angular.filter Filters} are functions which transform the data into user readable
{@link api/ng.$filter Filters} are functions which transform the data into user readable
format. They are important because they remove the formatting responsibility from the application
logic, further simplifying the application logic.
<pre>
angular.filter('length', function(text){
return (''+(text||'')).length;
myModule.filter('length', function() {
return function(text){
return (''+(text||'')).length;
}
});
var length = angular.filter('length');
var length = $filter('length');
expect(length(null)).toEqual(0);
expect(length('abc')).toEqual(3);
</pre>
## Directives
Directives in angular are responsible for updating the DOM when the state of the model changes.
Directives in angular are responsible for encapsulating complex functionality within custom HTML tags,
attributes, classes or comments. Unit tests are very important for directives because the components
you create with directives may be used throughout your application and in many different contexts.
### Simple HTML Element Directive
Lets start with an angular app with no dependencies.
<pre>
var app = angular.module('myApp', []);
</pre>
Now we can add a directive to our app.
<pre>
app.directive('aGreatEye', function () {
return {
restrict: 'E',
replace: true,
template: '<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>'
};
});
</pre>
This directive is used as a tag `<a-great-eye></a-great-eye>`. It replaces the entire tag with the
template `<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>`. Now we are going to write a jasmine unit test to
verify this functionality. Note that the expression `{{1 + 1}}` times will also be evaluated in the rendered content.
<pre>
describe('Unit testing great quotes', function() {
var $compile;
var $rootScope;
// Load the myApp module, which contains the directive
beforeEach(module('myApp'));
// Store references to $rootScope and $compile
// so they are available to all tests in this describe block
beforeEach(inject(function(_$compile_, _$rootScope_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
it('Replaces the element with the appropriate content', function() {
// Compile a piece of HTML containing the directive
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
$rootScope.$digest();
// Check that the compiled element contains the templated content
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
});
});
</pre>
We inject the $compile service and $rootScope before each jasmine test. The $compile service is used
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
replaced the content and "lidless, wreathed in flame, 2 times" is present.
## Mocks
oue
## Global State Isolation
oue
# Preferred way of Testing
uo
## JavaScriptTestDriver
ou
## Jasmine
ou
## Sample project
uoe
See the {@link https://github.com/angular/angular-seed angular-seed} project for an example.
+237
View File
@@ -0,0 +1,237 @@
@ngdoc overview
@name Developer Guide: Dependency Injection
@description
# Dependency Injection
Dependency Injection (DI) is a software design pattern that deals with how code gets hold of its
dependencies.
For in-depth discussion about DI, see {@link http://en.wikipedia.org/wiki/Dependency_injection
Dependency Injection} at Wikipedia, {@link http://martinfowler.com/articles/injection.html
Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
book.
## DI in a nutshell
There are only three ways an object or a function can get a hold of its dependencies:
1. The dependency can be created, typically using the `new` operator.
2. The dependency can be looked up by referring to a global variable.
3. The dependency can be passed in to where it is needed.
The first two options of creating or looking up dependencies are not optimal because they hard
code the dependency. This makes it difficult, if not impossible, to modify the dependencies.
This is especially problematic in tests, where it is often desirable to provide mock dependencies
for test isolation.
The third option is the most viable, since it removes the responsibility of locating the
dependency from the component. The dependency is simply handed to the component.
<pre>
function SomeClass(greeter) {
this.greeter = greeter;
}
SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}
</pre>
In the above example `SomeClass` is not concerned with locating the `greeter` dependency, it
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`.
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.
Here is an example of using the injector service:
<pre>
// Provide the wiring information in a module
angular.module('myModule', []).
// Teach the injector how to build a 'greeter'
// Notice that greeter itself is dependent on '$window'
factory('greeter', function($window) {
// This is a factory function, and is responsible for
// creating the 'greet' service.
return {
greet: function(text) {
$window.alert(text);
}
};
});
// New injector is created from the module.
// (This is usually done automatically by angular bootstrap)
var injector = angular.injector(['myModule', 'ng']);
// Request any dependency from the injector
var greeter = injector.get('greeter');
</pre>
Asking for dependencies solves the issue of hard coding, but it also means that the injector needs
to be passed throughout the application. Passing the injector breaks the {@link
http://en.wikipedia.org/wiki/Law_of_Demeter Law of Demeter}. To remedy this, we turn the
dependency lookup responsibility to the injector by declaring the dependencies as in this example:
<pre>
<!-- Given this HTML -->
<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
</pre>
<pre>
// And this controller definition
function MyController($scope, greeter) {
$scope.sayHello = function() {
greeter.greet('Hello World');
};
}
// The 'ng-controller' directive does this behind the scenes
injector.instantiate(MyController);
</pre>
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
dependencies of `MyController` without the controller ever knowing about the injector. This is
the best outcome. The application code simply asks for the dependencies it needs, without having to
deal with the injector. This setup does not break the Law of Demeter.
## Dependency Annotation
How does the injector know what service needs to be injected?
The application developer needs to provide annotation information that the injector uses in order
to resolve the dependencies. Throughout Angular, certain API functions are invoked using the
injector, as per the API documentation. The injector needs to know what services to inject into
the function. Below are three equivalent ways of annotating your code with service name
information. These can be used interchangeably as you see fit and are equivalent.
### Inferring Dependencies
The simplest way to get hold of the dependencies, is to assume that the function parameter names
are the names of the dependencies.
<pre>
function MyController($scope, greeter) {
...
}
</pre>
Given a function the injector can infer the names of the service to inject by examining the
function declaration and extracting the parameter names. In the above example `$scope`, and
`greeter` are two services which need to be injected into the function.
While straightforward, this method will not work with JavaScript minifiers/obfuscators as they
rename the method parameter names. This makes this way of annotating only useful for {@link
http://www.pretotyping.org/ pretotyping}, and demo applications.
### `$inject` Annotation
To allow the minifers to rename the function parameters and still be able to inject right services
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
of service names to inject.
<pre>
var MyController = function(renamed$scope, renamedGreeter) {
...
}
MyController.$inject = ['$scope', 'greeter'];
</pre>
Care must be taken that the `$inject` annotation is kept in sync with the actual arguments in the
function declaration.
This method of annotation is useful for controller declarations since it assigns the annotation
information with the function.
### Inline Annotation
Sometimes using the `$inject` annotation style is not convenient such as when annotating
directives.
For example:
<pre>
someModule.factory('greeter', function($window) {
...
});
</pre>
Results in code bloat due to needing a temporary variable:
<pre>
var greeterFactory = function(renamed$window) {
...
};
greeterFactory.$inject = ['$window'];
someModule.factory('greeter', greeterFactory);
</pre>
For this reason the third annotation style is provided as well.
<pre>
someModule.factory('greeter', ['$window', function(renamed$window) {
...
}]);
</pre>
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
where injection is supported.
## Where can I use DI?
DI is pervasive throughout Angular. It is typically used in controllers and factory methods.
### DI in controllers
Controllers are classes which are responsible for application behavior. The recommended way of
declaring controllers is using the array notation:
<pre>
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
...
}]);
</pre>
This avoids the creation of global functions for controllers and also protects against minification.
### Factory methods
Factory methods are responsible for creating most objects in Angular. Examples are directives,
services, and filters. The factory methods are registered with the module, and the recommended way
of declaring factories is:
<pre>
angular.module('myModule', []).
config(['depProvider', function(depProvider){
...
}]).
factory('serviceId', ['depService', function(depService) {
...
}]).
directive('directiveName', ['depService', function(depService) {
...
}]).
filter('filterName', ['depService', function(depService) {
...
}]).
run(['depService', function(depService) {
...
}]);
</pre>
+710
View File
@@ -0,0 +1,710 @@
@ngdoc overview
@name Directives
@description
Directives are a way to teach HTML new tricks. During DOM compilation directives are matched
against the HTML and executed. This allows directives to register behavior, or transform the DOM.
Angular comes with a built in set of directives which are useful for building web applications but
can be extended such that HTML can be turned into a declarative domain specific language (DSL).
# Invoking directives from HTML
Directives have camel cased names such as `ngBind`. The directive can be invoked by translating
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
`data-ng-bind`.
The directives can be placed in element names, attributes, class names, as well as comments. Here
are some equivalent examples of invoking `myDir`. (However, most directives are restricted to
attribute only.)
<pre>
<span my-dir="exp"></span>
<span class="my-dir: exp;"></span>
<my-dir></my-dir>
<!-- directive: my-dir exp -->
</pre>
Directives can be invoked in many different ways, but are equivalent in the end result as shown in
the following example.
<doc:example>
<doc:source >
<script>
function Ctrl1($scope) {
$scope.name = 'angular';
}
</script>
<div ng-controller="Ctrl1">
Hello <input ng-model='name'> <hr/>
&lt;span ng:bind="name"&gt; <span ng:bind="name"></span> <br/>
&lt;span ng_bind="name"&gt; <span ng_bind="name"></span> <br/>
&lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
&lt;span data-ng-bind="name"&gt; <span data-ng-bind="name"></span> <br/>
&lt;span x-ng-bind="name"&gt; <span x-ng-bind="name"></span> <br/>
</div>
</doc:source>
<doc:scenario>
it('should show off bindings', function() {
expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular');
});
</doc:scenario>
</doc:example>
# String interpolation
During the compilation process the {@link api/ng.$compile compiler} matches text and
attributes using the {@link api/ng.$interpolate $interpolate} service to see if they
contain embedded expressions. These expressions are registered as {@link
api/ng.$rootScope.Scope#$watch watches} and will update as part of normal {@link
api/ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is shown
here:
<pre>
<a href="img/{{username}}.jpg">Hello {{username}}!</a>
</pre>
# Compilation process, and directive matching
Compilation of HTML happens in three phases:
1. First the HTML is parsed into DOM using the standard browser API. This is important to
realize because the templates must be parsable HTML. This is in contrast to most templating
systems that operate on strings, rather than on DOM elements.
2. The compilation of the DOM is performed by the call to the {@link api/ng.$compile
$compile()} method. The method traverses the DOM and matches the directives. If a match is found
it is added to the list of directives associated with the given DOM element. Once all directives
for a given DOM element have been identified they are sorted by priority and their `compile()`
functions are executed. The directive compile function has a chance to modify the DOM structure
and is responsible for producing a `link()` function explained next. The {@link
api/ng.$compile $compile()} method returns a combined linking function, which is a
collection of all of the linking functions returned from the individual directive compile
functions.
3. Link the template with scope by calling the linking function returned from the previous step.
This in turn will call the linking function of the individual directives allowing them to
register any listeners on the elements and set up any {@link
api/ng.$rootScope.Scope#$watch watches} with the {@link
api/ng.$rootScope.Scope scope}. The result of this is a live binding between the
scope and the DOM. A change in the scope is reflected in the DOM.
<pre>
var $compile = ...; // injected into your code
var scope = ...;
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.
linkFn(scope);
</pre>
## Reasons behind the compile/link separation
At this point you may wonder why the compile process is broken down to a compile and link phase.
To understand this, let's look at a real world example with a repeater:
<pre>
Hello {{user}}, you have these actions:
<ul>
<li ng-repeat="action in user.actions">
{{action.description}}
</li>
</ul>
</pre>
The short answer is that compile and link separation is needed any time a change in model causes
a change in DOM structure such as in repeaters.
When the above example is compiled, the compiler visits every node and looks for directives. The
`{{user}}` is an example of an {@link api/ng.$interpolate interpolation} directive. {@link
api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link
api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
to save a clean copy of the `li` element for cloning purposes and 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 such as
`{{action.description}}` evaluate against the right {@link api/ng.$rootScope.Scope
scope}. A naive method would be to simply insert a copy of the `li` element and then compile it.
But compiling on every `li` element clone would be slow, since the compilation requires that we
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
repeater which needs to unroll 100 items we would quickly run into performance problems.
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.
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
compilation process from descending into the `li` element. 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`.
Summary:
* *compile function* - The compile function is relatively rare in directives, since most
directives are concerned with working with a specific DOM element instance rather than
transforming the template DOM element. Any operation which can be shared among the instance of
directives should be moved to the compile function for performance reasons.
* *link function* - It is rare for the directive not to 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.
# Writing directives (short version)
In this example we will build a directive that displays the current time.
<doc:example module="time">
<doc:source>
<script>
function Ctrl2($scope) {
$scope.format = 'M/d/yy h:mm:ss a';
}
angular.module('time', [])
// Register the 'myCurrentTime' directive factory method.
// We inject $timeout and dateFilter service since the factory method is DI.
.directive('myCurrentTime', function($timeout, dateFilter) {
// return the directive link function. (compile function not needed)
return function(scope, element, attrs) {
var format, // date format
timeoutId; // timeoutId, so that we can cancel the time updates
// used to update the UI
function updateTime() {
element.text(dateFilter(new Date(), format));
}
// watch the expression, and update the UI on change.
scope.$watch(attrs.myCurrentTime, function(value) {
format = value;
updateTime();
});
// schedule update in one second
function updateLater() {
// save the timeoutId for canceling
timeoutId = $timeout(function() {
updateTime(); // update DOM
updateLater(); // schedule another update
}, 1000);
}
// listen on DOM destroy (removal) event, and cancel the next UI update
// to prevent updating time after the DOM element was removed.
element.bind('$destroy', function() {
$timeout.cancel(timeoutId);
});
updateLater(); // kick off the UI update process.
}
});
</script>
<div ng-controller="Ctrl2">
Date format: <input ng-model="format"> <hr/>
Current time is: <span my-current-time="format"></span>
</div>
</doc:source>
</doc:example>
# Writing directives (long version)
There are different ways to declare a directive. The difference resides in the return
value of the factory function. You can either return a Directive Definition Object
(see below) that defines the directive properties, or just the postLink function
of such an object (all other properties will have the default values).
Here's an example directive declared with a Directive Definition Object:
<pre>
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
priority: 0,
template: '<div></div>',
templateUrl: 'directive.html',
replace: false,
transclude: false,
restrict: 'A',
scope: false,
controller: ["$scope", "$element", "$attrs", "$transclude", "otherInjectables",
function($scope, $element, $attrs, $transclude, otherInjectables) { ... }],
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
},
link: function postLink(scope, iElement, iAttrs) { ... }
};
return directiveDefinitionObject;
});
</pre>
In most cases you will not need such fine control and so the above can be simplified. You can still
return a Directive Definition Object, but only setting the 'compile' function property of the Object,
and rely on the default values for other properties.
Therefore the above can be simplified as:
<pre>
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
compile: function compile(tElement, tAttrs) {
return function postLink(scope, iElement, iAttrs) { ... }
}
};
return directiveDefinitionObject;
});
</pre>
Finally, most directives concern themselves only with instances, not with template transformations, allowing
further simplification.
Here we only define the postLink function:
<pre>
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
return function postLink(scope, iElement, iAttrs) { ... }
});
</pre>
## Factory method
The factory method is responsible for creating the directive. It is invoked only once, when the
{@link api/ng.$compile compiler} matches the directive for the first time. You can
perform any initialization work here. The method is invoked using the {@link
api/AUTO.$injector#invoke $injector.invoke} which
makes it injectable following all of the rules of injection annotation.
## Directive Definition Object
The directive definition object provides instructions to the {@link api/ng.$compile
compiler}. The attributes are:
* `name` - Name of the current scope. Optional and defaults to the name at registration.
* `priority` - When there are multiple directives defined on a single DOM element, sometimes it
is necessary to specify the order in which the directives are applied. The `priority` is used
to sort the directives before their `compile` functions get called. Priority is defined as a
number. Directives with greater numerical `priority` are compiled first. The order of directives with
the same priority is undefined. The default priority is `0`.
* `terminal` - If set to true then the current `priority` will be the last set of directives
which will execute (any directives at the current priority will still execute
as the order of execution on same `priority` is undefined).
* `scope` - If set to:
* `true` - then a new scope will be created for this directive. If multiple directives on the
same element request a new scope, only one new scope is created. The new scope rule does not
apply for the root of the template since the root of the template always gets a new scope.
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
normal scope in that it does not prototypically inherit from the parent scope. This is useful
when creating reusable components, which should not accidentally read or modify data in the
parent scope. <br/>
The 'isolate' scope takes an object hash which defines a set of local scope properties
derived from the parent scope. These local properties are useful for aliasing values for
templates. Locals definition is a hash of local scope property to its source:
* `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
always a string since DOM attributes are strings. If no `attr` name is specified then the
attribute name is assumed to be the same as the local name.
Given `<widget my-attr="hello {{name}}">` and widget definition
of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
`localName` property on the widget scope. The `name` is read from the parent scope (not
component scope).
* `=` or `=attr` - set up bi-directional binding between a local scope property and the
parent scope property of name defined via the value of the `attr` attribute. If no `attr`
name is specified then the attribute name is assumed to be the same as the local name.
Given `<widget my-attr="parentModel">` and widget definition of
`scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
in `localModel` and any changes in `localModel` will reflect in `parentModel`.
* `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
If no `attr` name is specified then the attribute name is assumed to be the same as the
local name. Given `<widget my-attr="count = count + value">` and widget definition of
`scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
a function wrapper for the `count = count + value` expression. Often it's desirable to
pass data from the isolated scope via an expression and to the parent scope, this can be
done by passing a map of local variable names and values into the expression wrapper fn.
For example, if the expression is `increment(amount)` then we can specify the amount value
by calling the `localFn` as `localFn({amount: 22})`.
* `controller` - Controller constructor function. The controller is instantiated before the
pre-linking phase and it is shared with other directives if they request it by name (see
`require` attribute). This allows the directives to communicate with each other and augment
each other's behavior. The controller is injectable with the following locals:
* `$scope` - Current scope associated with the element
* `$element` - Current element
* `$attrs` - Current attributes object for the element
* `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
`function(cloneLinkingFn)`.
To avoid errors after minification the bracket notation should be used:
<pre>
controller: ['$scope', '$element', '$attrs', '$transclude', function($scope, $element, $attrs, $transclude) { ... }]
</pre>
* `require` - Require another controller be passed into current directive linking function. The
`require` takes a name of the directive controller to pass in. If no such controller can be
found an error is raised. The name can be prefixed with:
* `?` - Don't raise an error. This makes the require dependency optional.
* `^` - Look for the controller on parent elements as well.
* `restrict` - String of subset of `EACM` which restricts the directive to a specific directive
declaration style. If omitted directives are allowed on attributes only.
* `E` - Element name: `<my-directive></my-directive>`
* `A` - Attribute: `<div my-directive="exp"></div>`
* `C` - Class: `<div class="my-directive: exp;"></div>`
* `M` - Comment: `<!-- directive: my-directive exp -->`
* `template` - replace the current element with the contents of the HTML. The replacement process
migrates all of the attributes / classes from the old element to the new one. See the
{@link guide/directive#Components Creating Components} section below for more information.
* `templateUrl` - Same as `template` but the template is loaded from the specified URL. Because
the template loading is asynchronous the compilation/linking is suspended until the template
is loaded.
* `replace` - if set to `true` then the template will replace the current element, rather than
append the template to the element.
* `transclude` - compile the content of the element and make it available to the directive.
Typically used with {@link api/ng.directive:ngTransclude
ngTransclude}. The advantage of transclusion is that the linking function receives a
transclusion function which is pre-bound to the correct scope. In a typical setup the widget
creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
scope. This makes it possible for the widget to have private state, and the transclusion to
be bound to the parent (pre-`isolate`) scope.
* `true` - transclude the content of the directive.
* `'element'` - transclude the whole element including any directives defined at lower priority.
* `compile`: This is the compile function described in the section below.
* `link`: This is the link function described in the section below. This property is used only
if the `compile` property is not defined.
## Compile function
<pre>
function compile(tElement, tAttrs, transclude) { ... }
</pre>
The compile function deals with transforming the template DOM. Since most directives do not do
template transformation, it is not used often. Examples that require compile functions are
directives that transform template DOM, such as {@link
api/ng.directive:ngRepeat ngRepeat}, or load the contents
asynchronously, such as {@link api/ng.directive:ngView ngView}. The
compile function takes the following arguments.
* `tElement` - template element - The element where the directive has been declared. It is
safe to do template transformation on the element and child elements only.
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
between all directive compile functions. See {@link
guide/directive#Attributes Attributes}.
* `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
NOTE: The template instance and the link instance may not be the same objects if the template has
been cloned. For this reason it is not safe in the compile function to do anything other than DOM
transformation that applies to all DOM clones. Specifically, DOM listener registration should be
done in a linking function rather than in a compile function.
A compile function can have a return value which can be either a function or an object.
* returning a (post-link) function - is equivalent to registering the linking function via the
`link` property of the config object when the compile function is empty.
* returning an object with function(s) registered via `pre` and `post` properties - allows you to
control when a linking function should be called during the linking phase. See info about
pre-linking and post-linking functions below.
## Linking function
<pre>
function link(scope, iElement, iAttrs, controller) { ... }
</pre>
The link function is responsible for registering DOM listeners as well as updating the DOM. It is
executed after the template has been cloned. This is where most of the directive logic will be
put.
* `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the
directive for registering {@link api/ng.$rootScope.Scope#$watch watches}.
* `iElement` - instance element - The element where the directive is to be used. It is safe to
manipulate the children of the element only in `postLink` function since the children have
already been linked.
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
between all directive linking functions. See {@link
guide/directive#Attributes Attributes}.
* `controller` - a controller instance - A controller instance if at least one directive on the
element defines a controller. The controller is shared among all the directives, which allows
the directives to use the controllers as a communication channel.
### Pre-linking function
Executed before the child elements are linked. Not safe to do DOM transformation since the
compiler linking function will fail to locate the correct elements for linking.
### Post-linking function
Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
<a name="Attributes"></a>
## Attributes
The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
link() or compile() functions - is a way of accessing:
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized access to
the attributes.
* *directive inter-communication:* All directives share the same instance of the attributes
object which allows the directives to use the attributes object as inter directive
communication.
* *supports interpolation:* Interpolation attributes are assigned to the attribute object
allowing other directives to read the interpolated value.
* *observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
the only way to easily get the actual value because during the linking phase the interpolation
hasn't been evaluated yet and so the value is at this time set to `undefined`.
<pre>
function linkingFn(scope, elm, attrs, ctrl) {
// get the attribute value
console.log(attrs.ngModel);
// change the attribute
attrs.$set('ngModel', 'new value');
// observe changes to interpolated attribute
attrs.$observe('ngModel', function(value) {
console.log('ngModel has changed value to ' + value);
});
}
</pre>
# Understanding Transclusion and Scopes
It is often desirable to have 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
the place of instantiation would like to bind to `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 child 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>
<a name="Components"></a>
# Creating Components
It is often desirable to replace a single directive with a more complex DOM structure. This
allows the directives to become a short hand for reusable components from which applications
can be built.
Following is an example of building a reusable widget.
<doc:example module="zippyModule">
<doc:source>
<script>
function Ctrl3($scope) {
$scope.title = 'Lorem Ipsum';
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
}
angular.module('zippyModule', [])
.directive('zippy', function(){
return {
restrict: 'C',
// This HTML will replace the zippy directive.
replace: true,
transclude: true,
scope: { title:'@zippyTitle' },
template: '<div>' +
'<div class="title">{{title}}</div>' +
'<div class="body" ng-transclude></div>' +
'</div>',
// The linking function will add behavior to the template
link: function(scope, element, attrs) {
// Title element
var title = angular.element(element.children()[0]),
// Opened / closed state
opened = true;
// Clicking on title should open/close the zippy
title.bind('click', toggle);
// Toggle the closed/opened state
function toggle() {
opened = !opened;
element.removeClass(opened ? 'closed' : 'opened');
element.addClass(opened ? 'opened' : 'closed');
}
// initialize the zippy
toggle();
}
}
});
</script>
<style>
.zippy {
border: 1px solid black;
display: inline-block;
width: 250px;
}
.zippy.opened > .title:before { content: '▼ '; }
.zippy.opened > .body { display: block; }
.zippy.closed > .title:before { content: '► '; }
.zippy.closed > .body { display: none; }
.zippy > .title {
background-color: black;
color: white;
padding: .1em .3em;
cursor: pointer;
}
.zippy > .body {
padding: .1em .3em;
}
</style>
<div ng-controller="Ctrl3">
Title: <input ng-model="title"> <br>
Text: <textarea ng-model="text"></textarea>
<hr>
<div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>
</div>
</doc:source>
<doc:scenario>
it('should bind and open / close', function() {
input('title').enter('TITLE');
input('text').enter('TEXT');
expect(element('.title').text()).toEqual('Details: TITLE...');
expect(binding('text')).toEqual('TEXT');
expect(element('.zippy').prop('className')).toMatch(/closed/);
element('.zippy > .title').click();
expect(element('.zippy').prop('className')).toMatch(/opened/);
});
</doc:scenario>
</doc:example>
+186
View File
@@ -0,0 +1,186 @@
@ngdoc overview
@name Developer Guide: Expressions
@description
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.
For example, these are all valid expressions in angular:
* `1+2`
* `3*10 | currency`
* `user.name`
## Angular Expressions vs. JS Expressions
It might be tempting to think of Angular view expressions as JavaScript expressions, but that is
not entirely correct, since Angular does not use a JavaScript `eval()` to evaluate expressions.
You can think of Angular expressions as JavaScript expressions with following differences:
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
evaluation, unlike in JavaScript where the expressions are evaluated against the global
`window`.
* **Forgiving:** expression evaluation is forgiving to `undefined` and `null`, unlike in JavaScript,
where trying to evaluate undefined properties can generate `ReferenceError` or `TypeError`.
* **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.
## Example
<doc:example>
<doc:source>
1+2={{1+2}}
</doc:source>
<doc:scenario>
it('should calculate expression in binding', function() {
expect(binding('1+2')).toEqual('3');
});
</doc:scenario>
</doc:example>
You can try evaluating different expressions here:
<doc:example>
<doc:source>
<script>
function Cntl2($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}
</script>
<div ng-controller="Cntl2" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
<ul>
<li ng-repeat="expr in exprs">
[ <a href="" ng-click="removeExp($index)">X</a> ]
<tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
</li>
</ul>
</div>
</doc:source>
<doc:scenario>
it('should allow user expression testing', function() {
element('.expressions :button').click();
var li = using('.expressions ul').repeater('li');
expect(li.count()).toBe(1);
expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]);
});
</doc:scenario>
</doc:example>
# Property Evaluation
Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
to global window properties, Angular expressions have to use {@link api/ng.$window
`$window`} to refer to the global `window` object. For example, if you want to call `alert()`, which is
defined on `window`, in an expression you must use `$window.alert()`. This is done intentionally to
prevent accidental access to the global state (a common source of subtle bugs).
<doc:example>
<doc:source>
<script>
function Cntl1($window, $scope){
$scope.name = 'World';
$scope.greet = function() {
($window.mockWindow || $window).alert('Hello ' + $scope.name);
}
}
</script>
<div class="example2" ng-controller="Cntl1">
Name: <input ng-model="name" type="text"/>
<button ng-click="greet()">Greet</button>
</div>
</doc:source>
<doc:scenario>
it('should calculate expression in binding', function() {
var alertText;
this.addFutureAction('set mock', function($window, $document, done) {
$window.mockWindow = {
alert: function(text){ alertText = text; }
};
done();
});
element(':button:contains(Greet)').click();
expect(this.addFuture('alert text', function(done) {
done(null, alertText);
})).toBe('Hello World');
});
</doc:scenario>
</doc:example>
## Forgiving
Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating `a.b.c` throws
an exception if `a` is not an object. While this makes sense for a general purpose language, the
expression evaluations are primarily used for data binding, which often look like this:
{{a.b.c}}
It makes more sense to show nothing than to throw an exception if `a` is undefined (perhaps we are
waiting for the server response, and it will become defined soon). If expression evaluation wasn't
forgiving we'd have to write bindings that clutter the code, for example: `{{((a||{}).b||{}).c}}`
Similarly, invoking a function `a.b.c()` on undefined or null simply returns undefined.
## No Control Flow Statements
You cannot write a control flow statement in an expression. The reason behind this is core to the
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.

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