Compare commits

...

740 Commits

Author SHA1 Message Date
Igor Minar 9a7035e815 chore(release): cut the 1.1.5 triangle-squarification release 2013-05-22 01:05:11 -07:00
Igor Minar 5cc9837d93 docs(CHANGELOG.md): release notes for 1.1.5 and 1.0.7 releases 2013-05-22 01:02:59 -07:00
Joakim Blomskøld 59eb50204a docs(Angular.js): add missing @returns to extend() 2013-05-21 21:33:32 +01:00
Matias Niemelä 5bc2836a0d docs(tutorial): fix the float issue with the improve docs button 2013-05-21 14:02:19 +01:00
Ben Ripkens cdf75b302f 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:17 +01:00
Jens Rantil 7f597a7509 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:17:51 +01:00
Jens Rantil 907d2f521e docs(guide/type): remove empty "Type" page in guide
Closes #1316
2013-05-21 13:12:41 +01:00
Igor Minar 0f7949c62a chore(version.js): remove unused/obsolete script 2013-05-21 03:42:57 -07:00
Igor Minar d458d7350b 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-21 03:39:36 -07:00
Dan Kohn eb21eb5a06 chore(package.json): use devDependencies instead of dependencies 2013-05-21 03:39:36 -07:00
Matias Niemelä 5a34464198 fix(ngdocs): fix gen_docs.sh 2013-05-20 14:39:02 -07:00
Matias Niemelä 5f92d4144e fix(ngdocs): provide test code for syntax links in docs and fix the syntax directive for IE8 2013-05-20 14:33:11 -07:00
Matias Niemelä 2f571a9c83 chore(ngdocs): move angular-bootstrap.js to be generated only inside the docs and remove from the build process 2013-05-20 14:27:34 -07:00
David Bennett 9f4f593711 feat($http): add support for aborting via timeout promises
If the timeout argument is a promise, abort the request when it is resolved.
Implemented by adding support to $httpBackend service and $httpBackend mock
service.

This api can also be used to explicitly abort requests while keeping the
communication between the deffered and promise unidirectional.

Closes #1159
2013-05-20 14:15:04 -07:00
Daniel Tse 27a8824b50 docs(filters): fix minor typographical error
Fix a typographical error "it's" -> "its" in the dateFilter
documentation
2013-05-20 15:36:10 +01:00
David Holmes 518a92651f 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:12 +01:00
Misha Moroshko 5c203240d4 doc(filter): remove invalid character 2013-05-20 10:19:18 +01:00
Pete Bacon Darwin be993528a3 docs(guide::testing): fix link to angular-seed 2013-05-18 22:17:15 +01:00
Chris M 3b69eaebcd 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:13:58 +01:00
Joakim Blomskøld 782a82d461 doc(ngModel): $setViewValue calls all parsers, not formatters 2013-05-18 21:17:51 +01:00
Ben Ripkens 2ab4fde817 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:00:45 +01:00
Andrew Vida 1c7741329f docs(tutorial): update test config file name 2013-05-18 20:29:17 +01:00
Jeremy Wilken a7ba27b92c 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:16:55 +01:00
Zach Snow 2a7043fa23 test($parse): improve clarity of ternary tests 2013-05-17 06:46:09 +01:00
Igor Minar 8f69ffce47 chore(docs): fix syntax error in docs.css 2013-05-16 16:39:13 -07:00
Matias Niemelä c53d4c9430 feat($animator): provide support for custom animation events 2013-05-16 16:17:46 -07:00
Matias Niemelä 24ed61cf5c test($animator): ensure invalid $sniffer.transitions and $sniffer.animations flags are caught in animation spec code 2013-05-16 16:17:46 -07:00
Matias Niemelä 3a49b7eec4 feat(ngdocs): Add FullText search to replace Google search in docs 2013-05-16 16:17:46 -07:00
Julie 0401a7f598 fix(jqLite): pass a dummy event into triggerHandler
Previously, anchor elements could not be used with triggerHandler because
triggerHandler passes null as the event, and any anchor element with an empty
href automatically calls event.preventDefault(). Instead, pass a dummy event
when using triggerHandler, similar to what full jQuery does. Modified from
PR #2379.
2013-05-16 16:15:31 -07:00
Zach Snow 6798fec439 feat($parse): add support for ternary operators to parser
Add '?' token to lexer, add ternary rule to parser at
(hopefully) proper precedence and associativity (based
on https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence).
Since (exp1 && exp2 || exp3) is supported by the parser,
and (exp1 ? exp2 : exp3) works the same way, it seems
reasonable to add this minor form of control to templates
(see #719).
2013-05-16 22:30:37 +01:00
Ryan Schumacher cefbcd470d fix($resource): null default param results in TypeError
Fixes issue when setting a default param as `null` error
`TypeError: Cannot read property 'charAt' of null`
2013-05-16 14:26:08 -07:00
Daniel Stockton f9b897de4b feat($http): add a default content type for PATH requests
The default header is now application/json which while not perfect
in all cases is better than the browser default application/xml.

The new headers also makes for better compatibility with Rails 4
2013-05-16 14:05:05 -07:00
Matt Haggard 1f99c3a521 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:02:16 +01:00
Dean Sofer a380fc4624 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:22:07 +01:00
jamesBrennan 99cd86a96e 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:32:15 +01:00
Samuel Santos d551d72924 feat(ngSrcset): add new ngSrcset directive
In line with ngSrc and ngHref, this new directive ensures that the
`srcset` HTML5 attribute does not include a pre-interpolated string.
Without it the browser will fetch from the URL with the literal text
`{{hash}}` until AngularJS replaces the expression inside `{{hash}}`.

Closes #2601
2013-05-14 21:29:21 +01:00
Andreas Marek 629fb37351 feat(scenario): adds mousedown and mouseup event triggers to scenario
Added mousedown and mouseup event triggers to scenadio dsl 'element' expression.
Added mousedown and mouseup to the custom jquery trigger method to generate real events.
2013-05-14 20:50:36 +01:00
Siddique Hameed 908821e20a 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 20:47:39 +01:00
Glenn Goodrich 53061363c7 feat($resource): collapse empty suffix parameters correctly
Previously only repeated `/` delimiters were collapsed into a
single `/`.  Now, the sequence `/.` at the end of the template, i.e.
only followed by a sequence of word characters, is collapsed into a single
`.`. This makes it easier to support suffixes on resource URLs.
For example, given a resource template of `/some/path/:id.:format`, if
the `:id` is `""` but format `"json"` then the URL is now
`/some/path.json`, rather than `/some/path/.json`.

BREAKING CHANGE: A `/` followed by a `.`, in the last segment of the
URL template is now collapsed into a single `.` delimiter. For example:
`users/.json` will become `users.json`. If your server relied upon this
sequence then it will no longer work. In this case you can now escape the
`/.` sequence with `/\.`
2013-05-14 20:01:15 +01:00
quazzie c32a859bdb feat(select): match options by expression other than object identity
Extend ng-options with a new clause, "track by [trackByExpression]", which can be used when
working with objects.  The `trackByExpression` should uniquely identify select options objects.
This solves the problem of previously having to match ng-options objects by identity.
You can now write: `ng-options="obj as obj.name for obj in objects track by obj.id"`
The "track by" expression will be used when checking for equality of objects.

Examples:
<select
    ng-model="user.favMovieStub"
    ng-options="movie as movie.name for movie in movies track by movie.id">
</select>

scope: {
  user: { name: 'Test user', favMovieStub: { id: 1, name: 'Starwars' } }
  movies: [{ id: 1, name: 'Starwars', rating: 5, ... }, { id: 13, ... }]
}

The select input will match user favMovieStub to the first movie in the movies array, and show
"Star Wars" as the selected item.
2013-05-14 19:58:05 +01:00
Matias Niemelä 4acc28a310 feat(ngAnimate): cancel previous incomplete animations when new animations take place 2013-05-13 21:09:43 -07:00
Matias Niemelä c8197b44eb feat(ngdocs): external links to github, plunkr and jsfiddle available for code examples 2013-05-13 16:55:14 -07:00
Matias Niemelä b6e5972eb3 chore(ngdocs): update to new version of FontAwesome 2013-05-13 16:55:14 -07:00
Matias Niemelä 0930d9dfe7 chore($sniffer): replace remaining supportsTransitions/supportsAnimations flags inside tests 2013-05-13 18:12:25 -04:00
Matias Niemelä 3e4d43b42c docs(animation): fix code example to work with most recent ngAnimate
ngAnimate: Rename CSS classes in example code to work with new ngAnimate naming conventions
ngInclude: Include animations toggle in ngInclude example code
ngAnimate: Remove ms- prefix and fix up CSS animation example code
2013-05-13 14:09:03 +01:00
Chirayu Krishnappa 3952d35abe 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 bffe6fa8a6 docs($scope): clarify documentation for $broadcast 2013-05-10 21:24:08 +01:00
veselinn ac8ba104d4 docs(guide): fix a typo 2013-05-10 20:52:18 +01:00
Lucas Galfasó 67a4a25b89 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:03:24 +01:00
Alfred Nutile f6caab598f docs(guide): fix typo on model name 2013-05-10 14:58:00 +01:00
Alex Pods 04d4c738b5 docs(Angular.js) move forEach docs to correct place 2013-05-09 22:04:13 +01:00
Anatoly Shikolay 4ae4f1edd2 style(*): fix up semicolon and var usage 2013-05-09 15:01:22 +01:00
Pete Bacon Darwin 40c36ee7fe docs(tutorial): add comment about injection annotation
Closes: #1163
2013-05-09 13:56:36 +01:00
Pete Bacon Darwin 02ad012e7f docs($window): fix example 2013-05-09 12:47:41 +01:00
Misko Hevery 29efd39745 fix(scenario): update to use our angular-scenario.js rather then karma 2013-05-08 16:40:35 -07:00
Matias Niemelä 11f712bc3e chore(ngAnimate): CSS classes X-setup/X-start -> X/X-active
BREAKING CHANGE: css classes foo-setup/foo-start become foo/foo-active

The CSS transition classes have changed suffixes. To migrate rename
.foo-setup {...} to .foo {...}
.foo-start {...} to .foo-active {...}

or for type: enter, leave, move, show, hide

.foo-type-setup {...} to .foo-type {...}
.foo-type-start {...} to .foo-type-active {...}
2013-05-08 16:03:31 -07:00
Matias Niemelä 14757874a7 feat(ngAnimate): Add support for CSS3 Animations with working delays and multiple durations 2013-05-08 15:56:53 -07:00
Matias Niemelä 88c3480aff feat($sniffer): Add support for supportsAnimations flag for detecting CSS Animations browser support 2013-05-08 15:40:37 -07:00
Matias Niemelä 0cb04e2e91 chore(ngIf): Add animation code to ngIf example and docs text to ngAnimate docs 2013-05-08 15:34:35 -07:00
Matias Niemelä 404c9a653a feat(ngdocs): add variable type hinting with colors 2013-05-08 15:25:56 -07:00
Igor Minar ee2689051b refactor($resource): simplify url template expansion 2013-05-08 15:08:49 -07:00
Igor Minar 5137a15417 chore(docs): use done() in gen-docs.js 2013-05-08 07:57:34 -07:00
Igor Minar 35adade6ac test(sortedHtml): ignore bogus rowspan=1 and colspan=1 in IE 2013-05-08 07:57:34 -07:00
Igor Minar 86b33eb3f1 test(sortedHtml): fix comment support in sortedHtml helper 2013-05-08 07:57:34 -07:00
Igor Minar 202087f03d style($compile): clarify argument name 2013-05-08 07:57:33 -07:00
R. Merkert 6d0b325f7f 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 12:45:32 +01:00
Illniyar cf4729faa3 feat($cookieStore): $cookieStore.get now parses blank string as blank string
closes #1918
2013-05-08 10:04:07 +01:00
Kevin Wells 4f2e360685 fix(date): correctly format dates with more than 3 sub-second digits
This date {{2003-09-10T13:02:03.123456Z | date: yyyy-mm-dd ss} is now
treated as having 123.45ms. Previously it had 123456ms so 123 seconds
were added to the formatted date.
Use local date in unit tests so they work in any time zone
2013-05-07 22:59:46 +01:00
Chad Smith 4622af3f07 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:27:42 +01:00
Pete Bacon Darwin f046f6f73c 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:43:25 +01:00
Hamish Macpherson 52c1498e25 doc(input): fix small typo in code example 2013-05-07 09:48:40 +01:00
Misko Hevery 2c69a6735e fix($location): prevent navigation when event isDefaultPrevented 2013-05-06 21:52:53 -07:00
Misko Hevery c575a56fc5 docs(injector): add docs for $injector.has 2013-05-06 21:52:53 -07:00
Matthieu Larcher af0eaa3047 feat(ngInclude): $includeContentRequested event
Adding a $includeContentRequested event in order to better keep track of
how many includes are sent and be able to compare it with how many have
finished.
2013-05-03 19:55:47 +01:00
Misko Hevery a348e90aa1 fix($location): compare against actual instead of current URL 2013-05-02 18:22:03 -04:00
Misko Hevery 4bd7bedf48 fix($location): prevent navigation if already on the URL 2013-05-02 15:22:17 -04:00
Misko Hevery fd21c7502f fix(ngAnamite): eval ng-animate expression on each animation 2013-05-02 15:22:16 -04:00
Misko Hevery 80341cb9ba feat(injector): add has method for querying
Closes #2556
2013-05-02 15:22:16 -04:00
Misko Hevery 9956baedd7 fix(ngView): accidentally compiling leaving content
closes: #2304
2013-05-02 15:22:16 -04:00
Gonzalo Ruiz de Villa 1d8e11ddfb fix(ngRepeat): correctly iterate over array-like objects
Check if the object is array-like to iterate over it like it's done with arrays.

Closes #2546
2013-05-02 15:12:37 +01:00
Gonzalo Ruiz de Villa 6452707d40 fix($rootScope) ensure $watchCollection correctly handles arrayLike objects 2013-05-02 15:12:37 +01:00
quazzie dc9a580617 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:42:10 +01:00
Pete Bacon Darwin 660605bdb8 test(ngAnimate): also provide W3C transition property to work on IE10
Closes: #2492
2013-05-01 13:57:44 +01:00
Siddique Hameed 89c0b5d096 docs(injector): fix typo
Closes: #2551
2013-05-01 13:14:54 +01:00
Braden Shepherdson 52a55ec618 feat(ngTap): Add a CSS class while the element is held down. 2013-04-30 16:56:24 -07:00
Vojta Jina e295eeefaa test(controller): instantiate controller defined on window
Just adding a missing spec.
2013-04-30 14:38:14 -07:00
Vojta Jina de2cdb0658 fix(ngController): allow dots in a controller name
The issue was introduced in cd38cbf975
2013-04-30 14:38:14 -07:00
David Bennett cda7b71146 feat($httpBackend): add timeout support for JSONP requests
Documentation implies that timeout works for all requests, though it
only works with XHR. To implement:
- Change $httpBackend to set a timeout for JSONP requests which will
immediately resolve the request when fired.
- Cancel the timeout when requests are completed.
2013-04-30 20:42:34 +01:00
Chris Nicola fc25a443f8 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:47:14 +01:00
Robin Böhm d6984db4d5 style($injector): add a comment to explain the distinction with isArray 2013-04-30 10:39:33 +01:00
Eugene Wolfson ef7ba7b212 docs($provide): fix parentheses in example 2013-04-30 10:16:24 +01:00
Matias Niemelä b3a62b2e19 feat(ngdocs): support for HTML table generation from docs code 2013-04-29 17:43:14 -04:00
Misko Hevery 400f9360bb fix(ngController): change controllerAlias to controllerAs. 2013-04-29 14:28:54 -04:00
Lucas Galfasó 7812ae75d5 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 19:16:21 +01:00
Lucas Galfasó da8c320bde test(parse): Test for the parsing not invoking twice to get self
New tests to not call twice a function to get self
2013-04-29 19:12:19 +01:00
gockxml 06f2b2a8cf 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:26:32 +01:00
Oren Avissar 0985a37376 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:56:35 +01:00
Robin Böhm cb62a57d43 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:07 +01:00
Jamie R. Rytlewski 61c0adedc3 docs($q): fix typo 2013-04-28 18:44:07 +01:00
Anton 8a59d8668c 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:24 +01:00
Andreas Pelme 32719c7976 docs(route): fix typo in route documentation 2013-04-26 13:16:19 +01:00
Pete Bacon Darwin 77ff108555 fix(location): correctly rewrite Html5 urls 2013-04-25 19:08:41 +01:00
Pete Bacon Darwin 0fbf584643 test(location): should not rewrite Html5 deep urls 2013-04-25 19:08:41 +01:00
Paulo Ávila 5a8ae94f9c docs(filter): improve syntax for usage in templates 2013-04-24 21:55:58 +01:00
Laurent Cozic 6605adf6d9 feat($q): add $q.always() method
Add $q.always(callback) method that is always called whether the promise is successful or fails; includes unit tests and updates
documentation.
2013-04-24 20:56:18 +01:00
Jeff Pickelman b1157aafd7 docs(di): fix typos and grammar 2013-04-24 20:52:25 +02:00
Timothy Ahong 2d5297e665 docs(guide:unit-testing): add an example unit test for directives 2013-04-23 14:00:14 +01:00
Misko Hevery cd38cbf975 feat(controller): support as instance syntax
Support ng-controller="MyController as my" syntax
which publishes the controller instance to the
current scope.

Also supports exporting a controller defined with route:
````javascript
angular.module('routes', [], function($routeProvider) {
  $routeProvider.when('/home', {controller: 'Ctrl as home', templateUrl: '...'});
});
````
2013-04-22 23:28:41 -07:00
Misko Hevery 021bdf3922 fix($animator): remove dependency on window.setTimeout. 2013-04-22 23:13:26 -07:00
Pete Bacon Darwin de296f1b52 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:18 +01:00
Keir Mierle 8c75b5f55a 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:08 +01:00
Keir Mierle 2d66ccd593 docs(forms): fix formatting 2013-04-22 12:38:26 +01:00
Ron Yang af9c20c07d docs(forms): fix typo 2013-04-22 12:34:38 +01:00
Paulo Ávila 2c34596b32 docs(guide): minor grammatical change 2013-04-21 19:53:52 +02:00
Tyler Akins 59c29e320a chore(ngDoc): fix a typo with IE warning 2013-04-19 21:56:39 +01:00
Oren Avissar 2f96fbd175 feat(ngIf): add directive to remove and recreate DOM elements
This directive is adapted from ui-if in the AngularUI project and provides a complement
to the ngShow/ngHide directives that only change the visibility of the DOM element and
ngSwitch which does change the DOM but is more verbose.
2013-04-19 21:45:38 +01:00
Merrick Christensen 8a2bfd7a78 docs(concepts): fix spelling error 2013-04-19 14:44:14 +01:00
Jared Beck 1d3e79e24e 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:39:58 +01:00
leesei 120b9190ea docs(input): fix typo on max attribute 2013-04-19 13:43:09 +01:00
Shyam Seshadri f77b906d67 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:36:22 +01:00
Michal Reichert 4c7baf970f docs(ngBind): fix typo 2013-04-19 11:55:16 +01:00
Igor Minar 5da6b125a7 test(modules): fix module tests which got disabled by ngMobile
When ngMobile was merged in, we accidentaly included angular-scenario.js
in the test file set for modules. Loading this file overrode jasmine's
`it` and `describe` global functions which essentially disabled all of
~200 unit tests for wrapped modules.

This change refactors the code to run the wrapped module tests.

I had to extract browserTrigger from scenario runner in order to achieve
this without code duplication.
2013-04-18 14:34:53 -07:00
Pete Bacon Darwin 695c54c17b 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:13:49 +01:00
Mark Dalgleish 363e4cbf64 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:20:08 +01:00
es128 c4d5631f1a doc(ngClassEven): make consistent with ngClassOdd 2013-04-17 14:51:41 +01:00
@fbiville fd91d86f0c 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:50:19 +01:00
@fbiville 9f2aaca65b 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:13 +01:00
austingreco 12b6deb1ce fix(ngPattern): allow modifiers on inline ng-pattern
Add support for regex modifiers on inline `ng-pattern`.
`ng-pattern="/regex/i"` now validates correctly.

Closes #1437
2013-04-16 14:49:17 -07:00
Timothy Ahong a91405889f docs(guide.unit-testing): fix typo 2013-04-16 21:04:09 +01:00
Francesc Rosàs b8f0b432fd docs($q): fix incorrect @returns tag for $q.when() 2013-04-16 13:37:07 +01:00
Pete Bacon Darwin 0ac969a5ee 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:15:49 +01:00
Pete Bacon Darwin 465238613b fix(Grunt): also remove \r chars when joining files 2013-04-16 12:13:55 +01:00
Misko Hevery 58ef32308f fix($location): fix URL interception in hash-bang mode
Closes #1051
2013-04-15 12:05:27 -07:00
Pete Bacon Darwin 59bfe8e5a9 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:28:31 +01:00
Pete Bacon Darwin a748410f52 docs(rootScope): fix typo 2013-04-15 11:44:49 +01:00
Laurent c25343f8be docs(rootScope): Fix various typos 2013-04-15 11:42:57 +01:00
Laurent cc1e4225b7 docs(Angular.js): fix typo 2013-04-15 11:42:34 +01:00
Pete Bacon Darwin 5d1f37b535 doc(overview): add link to angular demo slides to overview 2013-04-15 11:20:46 +01:00
brandonjp c746d65857 docs(ngController): fix docs link to api/ng.$route 2013-04-13 18:24:40 +02:00
Seunghoon Yeon 0d8a95af6f docs(module): fix typo 2013-04-13 17:19:11 +02:00
Igor Minar ab755a25f9 fix(Scenario): correct bootstrap issue on IE
we need to set the deferred bootstrap flag via window.name after the iframe's
src has been set, otherwise IE will reset it to empty string
2013-04-13 00:42:51 -07:00
uberspeck b7b08eed02 docs(faq): added note to FAQ re: legacy IE support 2013-04-12 15:58:29 -07:00
Misko Hevery 570463a465 fix(ngAnimate): prevent animation on initial page load 2013-04-11 23:06:07 -07:00
Matias Niemelä 3c3247fe17 fix(ngdocs): improve the animations used in the docs menu 2013-04-11 23:06:07 -07:00
Misko Hevery a0bc71e271 fix(ngRepeat): prevent initial duplicates 2013-04-11 23:06:07 -07:00
Dave Geddes a491ea3791 chore(Grunt) update grunt-contrib-copy
grunt-contrib-copy@0.4.1 has the cleaner summary output by default
2013-04-11 16:28:10 -07:00
Lee Leathers fe1696f688 style(exceptionHandler): add ws 2013-04-11 15:32:20 -07:00
Lee Leathers c3a87c6849 chore(NPM): Add license info 2013-04-11 15:32:19 -07:00
Prathan Thananart 6b63afe2f7 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:27:46 -07:00
kamagatos b86815fb5b docs(guide/i18n): fix a typo 2013-04-11 15:21:33 -07:00
winkler1 aa3acc5229 docs(animator): fix typo 2013-04-11 15:14:46 -07:00
Christoph Burgdorf 15d80af53c docs(jqLite): clarified that children/parent do not support selectors 2013-04-11 15:11:28 -07:00
Matt Haggard a92bb2e025 docs: fix typos 2013-04-11 15:03:59 -07:00
Brent Morrow d521ad3ff6 docs(ngApp): fixed typo
Use this directive to auto-bootstrap **an** application.
2013-04-11 14:58:39 -07:00
Brent Morrow ebf7cf9ed3 docs(guide/concepts): fix typo
An event is a user **interaction**, timer event, or network event (response from a server).
2013-04-11 14:56:30 -07:00
玉黍 719d844a94 docs(examples): set ng-app to "personalLog" (example/personalLog) 2013-04-11 14:53:40 -07:00
{Qingping,Dave} Hou db547e63ee docs(guide): Added $ sign to controller example 2013-04-11 14:32:44 -07:00
urenmj 63c25fd875 docs(dev-guide): Fixed a typo. 2013-04-11 14:25:50 -07:00
Matias Niemelä 1351ba2632 fix(ngAnimate): skip animation on first render 2013-04-11 14:15:20 -07:00
Matias Niemelä 5476cb6e9b feat($animator): allow to globally disable and enable animations 2013-04-11 14:15:20 -07:00
Artur Ostrega d9d53472ec docs(http): spelling, grammar, capitalization, etc. 2013-04-11 14:10:57 -07:00
Brent Morrow 38dffe7e91 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:08:43 -07:00
Brent Morrow 941633a911 docs(guide/concepts): wording change 2013-04-11 14:07:31 -07:00
Brent Morrow 3ec7b87483 docs(guide/expression): wording changes 2013-04-11 14:03:52 -07:00
Luc Morin 63ce1f6265 docs(guide/directives): give more details about directive declaration 2013-04-11 14:00:09 -07:00
Colin Kahn 59eb96b9e4 docs(guide/filters): document multiple arguments syntax
Add example of using a filter with that accepts multiple arguments.
2013-04-11 13:55:03 -07:00
Brent Morrow e142687bcb docs(angular-mocks): fix wording 2013-04-11 13:51:40 -07:00
Brent Morrow 16bfb7eea0 docs($inject): wording change 2013-04-11 13:48:04 -07:00
David Sanders 48308913bb docs($compile): improve docs 2013-04-11 13:05:27 -07:00
Braden Shepherdson 5e0f876c39 feat(ngSwipe): Add ngSwipeRight/Left directives to ngMobile
These directives fire an event handler on a touch-and-drag or
click-and-drag to the left or right. Includes unit tests and docs
update. Manually tested on Chrome 26, IE8, Android Chrome and iOS
Safari.
2013-04-11 13:01:24 -07:00
Brian Campbell f24cf4b58f 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:10 -07:00
Igor Minar a752e5763e chore(release): start 1.1.5 triangle-squarification iteration 2013-04-11 12:51:47 -07:00
Chad Whitacre 725028b07d docs($http): fix a typo 2013-04-11 12:39:00 -07:00
Patrick f9b63f8657 docs(animator): Fixed a typo 2013-04-11 12:15:25 -07:00
Matias Niemelä be08c075bd fix($sniffer): $sniffer to support non-vendor prefixes 2013-04-08 21:26:19 -07:00
Heath Matlock d90a79632d docs(concespts): correct spelling and remove unnecessary word 2013-04-06 22:56:54 +02:00
Igor Minar cc042c42bc docs(changelog): fix the 1.0.6 header 2013-04-04 15:24:15 -07:00
Igor Minar 7729b58eda docs(changelog): add release notes for 1.1.4 and 1.0.6 2013-04-04 12:15:37 -07:00
Igor Minar 2ce74e547a docs($resource): improve installation section 2013-04-04 08:57:25 -07:00
Igor Minar 5e3ee0a99b chore(release): cutting angular 1.1.4 quantum-manipulation 2013-04-03 18:54:52 -07:00
William Bagayoko 308a59bf44 fix(ngAnimator): correct polyfillSetup activation and memento generation 2013-04-03 18:42:17 -07:00
Matias Niemelä 19f1801379 docs: add animations into docs and directive examples 2013-04-03 17:40:15 -07:00
Igor Minar 303df9dafe 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 17:40:15 -07:00
Igor Minar fec4ef3881 feat(Scenario): autodisable animations when running e2e tests
animations cause the dom to contain elements that have been removed
from the model but are being animated out.

we could teach the e2e runner to wait for animations but that would
make all tests slower. it should be quite safe to just disable
animations automatically when the app is running via the e2e test
runner.

this change disables only css animations. we should make additional
change that disables js animations as well, but since we don't need
this right now I'm punting on it.
2013-04-03 17:40:15 -07:00
Misko Hevery ecdf119a76 fix(ngShow/ngHide): revert to display:'' for show
Regression introduced by ngAnimation
SHA: 0b6f1ce5f8
2013-04-03 15:20:53 -07:00
Misko Hevery 820253f670 chore(revert): accidental inclusion of nonexistent test.
Offending SHA: 0b6f1ce5f8
2013-04-03 14:54:16 -07:00
Misko Hevery 6bca948323 chore(revert): Revert accidental change to showdown
Offending SHA: 0b6f1ce5f8
2013-04-03 14:35:09 -07:00
Igor Minar 556f9cc35e style(animator): style cleanup 2013-04-03 02:15:03 -07:00
Matias Niemelä 2845dd1590 feat(ngdocs): added functionality to import and extract contents of external files inside docs comment code 2013-04-02 15:52:32 -07:00
Misko Hevery 0b6f1ce5f8 feat(ngAnimate): add support for animation 2013-04-02 14:05:06 -07:00
Misko Hevery 4bfb66ce0b chore(docs): correct few unclosed elements 2013-04-02 13:36:12 -07:00
Igor Minar 85c31e0688 docs(ngSwitch): improve the @usage example 2013-04-01 21:33:31 -07:00
Vojta Jina c2e215fab6 chore: use Karma 2013-04-01 12:24:27 -07:00
Misko Hevery 61f2767ce6 feat(ngRepeat): add support for custom tracking of items
BREAKING CHANGE:

It is considered an error to have two items produce
the same track by key. (This was tolerated before.)
2013-03-29 23:01:52 -07:00
Matias Niemelä 5eb968553a feat(Scope): add $watchCollection method for observing collections
The new method allows to shallow watch collections (Arrays/Maps).
2013-03-29 22:00:25 -07:00
Felipe Lahti 04cc1d2890 docs(guide): add missing closing div tag 2013-03-29 23:30:37 +01:00
Felipe Lahti 7d4a3210f0 docs(guide): fix typo in DI. angualar -> angular 2013-03-29 23:25:58 +01:00
Gert Goet 8dca0561e8 docs(mocks): fix typos 2013-03-29 23:24:12 +01:00
Srinivas Kusunam 53abd3fba7 docs(directive): fix typo 2013-03-29 23:22:02 +01:00
Matthew McComb 06ada222c2 docs(controller): improve $controller function doc readability
Improved $controller function doc readability.
2013-03-29 23:18:01 +01:00
Pascal Borreli 9480136d9f docs(*): fixed typos 2013-03-29 23:14:55 +01:00
Sylvester Keil 4ae46814ff feat(http): support request/response promise chaining
myApp.factory('myAroundInterceptor', function($rootScope, $timeout) {
    return function(configPromise, responsePromise) {
        return {
            request: configPromise.then(function(config) {
                return config
            });
            response: responsePromise.then(function(response) {
                return 'ha!';
            }
        });
}

myApp.config(function($httpProvider){
    $httpProvider.aroundInterceptors.push('myAroundInterceptor');
});
2013-03-27 13:13:59 -07:00
Misko Hevery 5c735eb4ab fix(mock): prevent NPE when module definition outside of it. 2013-03-27 08:56:06 -07:00
James deBoer 364e597499 Update forms.ngdoc
docs(forms): Fixed a typo. render -> $render
2013-03-24 23:11:36 -07:00
Chirayu Krishnappa 23abb990f1 chore($ngLocale): refactor i18n closure slurper logic and parse extended datetime symbols 2013-03-20 16:19:46 -07:00
Chirayu Krishnappa 0c72708a2b chore($ngLocale): generate ngLocale files from the Closure code (includes datetimesymbolsext.js) 2013-03-20 15:50:07 -07:00
Jason Als fec2909f3a fix(ngMobile): Use bracket notation to fix minified version
Added aliases for minification
2013-03-20 14:21:26 -07:00
Mark Chapman 4efda14b49 refactor(ngRepeat): make use of declared variable
Rename unused arrayLength variable to arrayBound and use it inside loop
2013-03-20 14:16:41 -07:00
Arlen Christian Mart Cuss 821d2fddb7 chore(select): Fix ngOptions regexp capture comment.
Off-by-one error.
2013-03-20 11:44:17 -07:00
Javier Mendiara Cañardo ef76afdf80 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-19 11:00:42 -07:00
Bruno Coelho 564963dc27 docs(filter): Using indefinite article
This doc was using both definite article and indefinite article at the same time.
2013-03-19 10:56:48 -07:00
Arlen Christian Mart Cuss fe4f0ea262 docs(directive): Fix entity confusion in example. 2013-03-19 10:53:46 -07:00
Manuel Braun 3a81dd8bdd 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:31 -07:00
Jamie Mason df9bff13b2 $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:21 -07:00
Shyam Seshadri f197e391c1 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:13 -07:00
Sujeet Pillai 1c1cd4fdf6 fix(timezone): correct timezone date filter for 1/2 hour offsets 2013-03-14 22:16:54 -07:00
Shyam Seshadri 79049b9fee Fix failing test in IE 10 2013-03-14 22:03:37 -07:00
Igor Minar 9428338e97 chore(docs): add angular-mobile.js to index.html 2013-03-13 23:01:16 -07:00
Braden Shepherdson 707c65d5a2 feat(ngMobile): add ngMobile module with mobile-specific ngClick
Add a new module ngMobile, with mobile/touch-specific directives.
Add ngClick, which overrides the default ngClick. This ngClick uses touch
events, which are much faster on mobile. On desktop browsers, ngClick
responds to click events, so it can be used for portable sites.
2013-03-13 22:59:06 -07:00
Arlen Christian Mart Cuss d1b49e25f1 docs($injector): correct misuse of $inject
$inject was used where $injector was appropriate; confusing and
misleading.
2013-03-12 13:00:03 -07:00
Igor Minar 5fd39e050b 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:26:50 -07:00
Thibault Leruitte 9befe37014 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:26:38 -07:00
Lucas Galfasó e88d6179c3 feat(ng:switch): Preserve the order of the elements not in the ng-switch
Preserve the order of the elements that are not part of a case nor default in
a ng-switch directive

BREAKING CHANGE: elements not in the ng-switch were rendered after the
    ng-switch elements.  Now they are rendered in-place.

    Ng-switch directives should be updated with non ng-switch elements
    in render-order.  e.g.

    The following was previously rendered with <li>1</li> after "2":

    <ul ng-switch="select">
        <li>1</li>
        <li ng-switch-when="option">2</li>
    </ul>

    To keep the old behaviour, say:

    <ul ng-switch="select">
        <li ng-switch-when="1">2</li>
        <li>1</li>
    </ul>

Closes #1074
2013-03-11 11:31:04 -07:00
Christian Vuerings 90ba9aadc6 docs(ngCloak): update the CSS rule with data-ng-cloak 2013-03-08 17:23:04 -08:00
Chirayu Krishnappa 96b13bbee1 chore($ngLocale): Generate ngLocale files from the Closure code. 2013-03-08 15:46:59 -08:00
Jason Morrison a248d5a32d docs($injector): remove extranneous 'the' from injector docs 2013-03-08 23:44:44 +01:00
Niel de la Rouviere 69ef17cce9 docs(directive): minor typo fix
Changed "obeject" to "object"
2013-03-08 23:26:41 +01:00
Mark Nadig f20646bce5 feat(directive): add ngKeypress directive for handling keypress event 2013-03-08 21:56:32 +01:00
Igor Minar 65e57a7c3d test($route): add tests for matching 'otherwise' routes 2013-03-08 12:00:34 -08:00
Igor Minar 6f71e80914 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:00:34 -08:00
Ciro Nunes cb5ce981fb docs($resource): Added an installation section. 2013-03-08 11:04:32 -08:00
Alexander Shtuchkin 99f3b70b2d feat(http): set custom default cache in $http.defaults.cache
When we need more control over http caching, we may want to provide
a custom cache to be used in all http requests by default.

To skip default cache, set {cache: false} in request configuration.
To use other cache, set {cache: cache} as before.

See #2079
2013-03-08 10:19:18 -08:00
Julie 603fe0d196 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.
2013-03-06 16:19:35 -08:00
Dave Geddes 485f104099 docs(contribute): add note about running command line as admin on win 2013-03-06 14:54:35 -08:00
Igor Minar d38d8448e8 chore(Grunt): include dot files in the final zip 2013-03-06 14:51:21 -08:00
Dave Geddes 8a96393179 chore(Grunt): don't remove root dir from zip 2013-03-06 14:51:16 -08:00
Igor Minar 49128cc100 docs($http): add more info about transform function 2013-03-06 11:20:30 -08:00
Dave Geddes 79b51d5b57 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
2013-03-05 23:00:33 -08:00
Thibault Leruitte fe8d893b83 feat($compile): allow directives to modify interpolated attributes
A directive can now set/update/remove attribute values even those containing
interpolation during the compile phase and have the new value be picked up
during the compilation.

For example in template:

<div replace-directive some-attr-or-directive="{{originalInterpolationValue}}"></div>

the replace-directive can now replace the value of some-attr-or-directive during compilation
which produces this intermitent template:

<div replace-directive some-attr-or-directive="{{replacedInterpolationValue}}"></div>

or even

<div replace-directive some-attr-or-directive="replacedStaticValue"></div>

as well as

<div replace-directive some-attr-or-directive></div>
2013-02-28 17:27:27 -08:00
Luis Ramón López eb53423a41 feat($compile): support for dynamic template generation
`template` and `templateUrl` properties can now be optionally defined
via a function. This allows templates to be dynamically generated on
the fly.
2013-02-27 17:57:59 -08:00
David Chang 5e18a15fb0 feat($route): add caseInsensitiveMatch option for url matching
with this property urls can be matched case-insensitively which
enables some new use cases.
2013-02-27 12:45:30 -08:00
zeflasher 60f1f099fc feat($resource): ability to override url in resource actions
Resources now can defined per action url override. The url is treated
as a template rather than a literal string, so fancy interpolations
are possible.

See attached tests for example usage.
2013-02-27 10:52:30 -08:00
Luis Ramón López cf17c6af47 feat($compile): add attribute binding support via ngAttr*
Sometimes is not desirable to use interpolation on attributes because
the user agent parses them before the interpolation takes place. I.e:

<svg>
  <circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle>
</svg>

The snippet throws three browser errors, one for each attribute.

For some attributes, AngularJS fixes that behaviour introducing special
directives like ng-href or ng-src.

This commit is a more general solution that allows prefixing any
attribute with "ng-attr-", "ng:attr:" or "ng_attr_"  so it will
be set only when the binding is done. The prefix is then removed.

Example usage:

<svg>
  <circle ng-attr-cx="{{cx}}" ng-attr-cy="{{cy}}" ng:attr-r="{{r}}"></circle>
</svg>

Closes #1050
Closes #1925
2013-02-27 00:55:40 -08:00
Andrew McLeod 86d191ed4a 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:25:15 -08:00
Matt Ginzton c38c1c5030 docs(ngMock): fix minor typo in comment
Change "constroctor" to "constructor".
2013-02-25 23:54:44 -08:00
Matt Ginzton d4fe383b7b docs(ngMock): remove Jasmine-only comments now that Mocha works
Remove comments about angular.mock.inject and angular.mock.module
being available for jasmine only. Since 1.1.1 the intent is that
they be available for mocha as well; now they even work!
2013-02-25 23:54:29 -08:00
Matt Ginzton 6397860831 fix(ngMock): fix isSpecRunning to work for Mocha
When running inside Mocha, don't look in Jasmine's spec.queue.running.
It's not there. This is documented as issue #1467; I think this issue was
also responsible for #1589 and recent complaints in #1253.

Closes #1467.
2013-02-25 23:52:12 -08:00
danilsomsikov 398691beb3 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:44:00 -08:00
Igor Minar 7ddbde8c1c 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:38:29 -08:00
Jørgen Borgesen 753fc9e58d feat(JQLite): ready() now supports document.readyState=='complete'
JQLite.ready() used for automatic bootstrapping (when jQuery is not present)
now checks if document already is ready when first called. This simplifies
bootstrapping when the angular script is loaded asynchronously.

However if other scripts with angular app code are being loaded as well
it is developers responsibility to ensure that these scripts are loaded
after angular-loader.js is evaluated and before angular.js script is
evaluated.
2013-02-25 15:32:14 -08:00
Vineet Kumar 6a612df7de 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:52 -08:00
Luis Ramón López ac899d0da5 feat($compile): '=?' makes '=' binding optional
If you bind using '=' to a non-existant parent property, the compiler
will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception, which is right
because the model doesn't exist.

This enhancement allow to specify that a binding is optional so it
won't complain if the parent property is not defined. In order to mantain
backward compability, the new behaviour must be specified using '=?' instead
of '='. The local property will be undefined is these cases.

Closes #909
Closes #1435
2013-02-25 14:30:54 -08:00
Pawel Kozlowski 30162b769c docs(dateFilter): properly specify range for the Z format modifier
Closes #1533
2013-02-25 13:51:13 -08:00
Alexander Shtuchkin 7d18d0ae26 refactor($route): use $q#all hash signature 2 simplify 'resolve' impl 2013-02-25 10:58:10 -08:00
Alexander Shtuchkin e27bb6eb13 feat($q): $q.all() now accepts hash
When waiting for several promises at once, it is often desirable to
have them by name, not just by index in array.

Example of this kind of interface already implemented would be a
$routeProvider.when(url, {resolve: <hash of promises>}), where
resources/promises are given by names, and then results accessed
by names in controller.
2013-02-25 10:58:05 -08:00
Igor Minar 7b236b29aa fix($compile): whitelist file:// in url sanitization 2013-02-25 10:02:28 -08:00
Steven Davidson c36933d38f chore(nodeserver): fix log message for 301 response 2013-02-23 23:44:40 -08:00
Igor Minar bec614fd90 fix($compile): handle elements with no childNodes property
see the test for more details
2013-02-23 23:22:14 -08:00
Igor Minar 509ec745fd fix($httpBackend): prevent DOM err due to dereferencing .responseText
If responseType is defined and the request fails for one reason or another
the .response property returned falsy value which caused dereferencing of
.responseText. If the responseType was a blob or document then an error
was thrown.

To prevent this, I'm checking for responseType first and based on that
dereferencing .response or .responseText.

We need to keep on checking .responseText because that's the original XHR
response api that is still needed for IE8 and 9.

Closes #1922
2013-02-23 22:16:41 -08:00
Igor Minar d44ca19da7 chore(release): start 1.1.4 quantum-manipulation iteration 2013-02-23 21:11:51 -08:00
Igor Minar 2508b47c1a docs(changelog): fix release notes 2013-02-20 15:44:19 -08:00
Igor Minar de6d4ca1da chore(release): cut 1.1.3 radioactive-gargle release 2013-02-20 12:54:44 -08:00
Igor Minar 776dfc678b docs(changelog): add release notes for 1.0.5 and 1.1.3 2013-02-20 11:16:19 -08:00
Igor Minar 9532234bf1 fix($compile): sanitize values bound to a[href] 2013-02-20 00:06:26 -08:00
Per Rovegård 5f5d4feadb 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:25:43 -08:00
Pete Bacon Darwin 791804bdbf 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 12:05:16 +00:00
Luis Ramón López 7eafbb98c6 feat(routeProvider): Add support to catch-all parameters in routes
This allows routeProvider to accept parameters that matches
substrings even when they contain slashes if they are prefixed
with an asterisk instead of a colon.
For example, routes like edit/color/:color/largecode/*largecode
will match with something like this
http://appdomain.com/edit/color/brown/largecode/code/with/slashs.
2013-02-14 21:36:59 -08:00
Pete Bacon Darwin bb8448c011 fix(compile): Initialize interpolated attributes before directive linking 2013-02-14 21:36:59 -08:00
Pete Bacon Darwin 2ed53087d7 fix(compile): Interpolate @ locals before the link function runs
Do a one-off interpolation of @ locals to ensure that the link fn receives attributes that are already interpolated.
2013-02-14 21:36:59 -08:00
Lucas Galfasó 0af172040e feat(ngSwitch): support multiple matches on ngSwitchWhen and ngSwitchDefault
Closes #1074
2013-02-14 19:55:05 -08:00
Will Moore e19b04c9ec 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
2013-02-14 16:45:30 -08:00
Igor Minar 37e8b12265 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:42:58 -08:00
Igor Minar 1ace5eb396 style(filter): remove ws 2013-02-14 16:38:43 -08:00
Igor Minar 3c2aee01b0 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:37:00 -08:00
Cedric Soulas 37bdcc984a docs($resource): fix bad indentation producing a code block 2013-02-14 15:47:16 -08:00
Ewen Cumming 027f20be1f docs($rootScope): rearrange event listener docs 2013-02-14 15:47:16 -08:00
deboer 9b7c1d0f7c 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:36:03 -08:00
Vineet Kumar 5548328b67 docs($q): fix a few typos 2013-02-14 15:18:58 -08:00
Dylan Pyle 7c6b1e06e8 docs(guide): fix some invalid javascript in directive documentation
Use double quotes to maintain consistency with other HTML
2013-02-14 15:11:04 -08:00
Vojta Jina 288b69a314 fix($http): do not encode special characters @$:, in params
encodeURIComponent is too aggressive and doesn't follow http://www.ietf.org/rfc/rfc3986.txt
with regards to the character set (pchar) allowed in path segments so we need
this test to make sure that we don't over-encode the params and break stuff
like buzz api which uses @self.

This is has already been fixed in `$resource`. This commit fixes it in a same way
for `$http` as well.

BREAKING CHANGE: $http does follow RFC3986 and does not encode special characters
like `$@,:` in params. If your application needs to encode these characters, encode
them manually, before sending the request.
2013-02-14 14:52:46 -08:00
Mark Nadig 2a2123441c fix($resource): params should expand array values properly
Today, calling e.g. var R = $resource('/Path/:a'); R.get({a: 'foo', bar: ['baz1', 'baz2']}); results in a query
string like "/Path/doh?bar=baz1,baz2" which is undesirable. This commit enhances resource to use
$http to encode any non-url parameters resulting in a query string like "/Path/doh?bar=baz1&bar=baz2".

BREAKING CHANGE: if the server relied on the buggy behavior then either the
backend should be fixed or a simple serialization of the array should be done
on the client before calling the resource service.
2013-02-14 14:52:46 -08:00
Daniel Luz 1d7a95df56 feat(scope): only evaluate constant $watch expressions once 2013-02-14 14:43:56 -08:00
Daniel Luz 1ed638582d feat($parse): added constant and literal properties
* `literal` is set to true if the expression's top-level is a JavaScript
  literal (number, string, boolean, null/undefined, array, object), even
  if it contains non-literals inside.

* `constant` is set to true if the expression is known to be made
  entirely of constant values, i.e., evaluating it will always yield the
  same result.

A consequence is that a JSON expression is guaranteed to be both literal
and constant.
2013-02-14 14:43:56 -08:00
Daniel Luz 3b14092135 docs($parse): document function argument types, fix minor typo 2013-02-14 14:43:56 -08:00
Daniel Luz ef268196b9 fix($rootScope): minor typo fixes 2013-02-14 14:43:56 -08:00
James Morrin 12ba6cec4f feat(noConflict): restore previous angular namespace reference 2013-02-14 14:43:55 -08:00
Fredrik Bonander b7e1fb0515 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:55 -08:00
Shyam Seshadri 755beb2b66 fix(compiler): Allow startingTag method to handle text / comment nodes 2013-02-14 14:43:55 -08:00
Trotter Cashion 6d70ff5c8d chore(reakefile): auto install npm packages 2013-02-14 14:43:55 -08:00
Rosina Bignall ace54ff08c feat(filter): Add comparison function to filter
Add optional comparator function argument to $filter('filter')(array,
expression, comparator) such that the comparator function is used to
compare the values and predicates.  When true, defaults to equality.
When missing defaults to substring matching.
2013-02-14 14:43:55 -08:00
Kury Kruitbosch f5835963d5 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:15:50 -08:00
Jesse Cooke f3231b9447 docs(guide): Fix typos in concepts/model,view. 2013-02-14 13:05:25 -08:00
Igor Minar a8a3efb5f0 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:46:19 -08:00
Cedric Soulas e47f8d2b96 docs($resource): fix missing punctuation 2013-02-14 11:57:33 -08:00
Igor Minar dba6bc73e8 feat($resource): expose promise based api via $then and $resolved
Expose $then and $resolved properties on resource action return values which
allow checking if a promise has been resolved already as well as registering
listeners at any time of the resource object life-cycle.

This commit replaces unreleased commit f3bff27460
which exposed unintuitive $q api instead and didn't expose important stuff
like http headers.
2013-02-11 22:24:21 -08:00
Igor Minar c0a0781425 chore(matchers): fix hasBeenCalledOnceWith matcher
the error message was wrong and misleading
2013-02-11 22:13:15 -08:00
Igor Minar 035e0130f3 test(angular.copy): add tests for scenarios when target is missing 2013-02-11 22:11:07 -08:00
Igor Minar 9e57ce0c7a revert: refactor(angular.copy): use slice(0) to clone arrays
This reverts commit 28273b7f1ef52e46d5bc23c41bc7a1492cf23014o.

slice(0) doesn't perform deep copy of the array so its unsuitable
for our purposes.
2013-02-11 21:58:00 -08:00
Igor Minar 42a5033c56 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:16 -08:00
Igor Minar 6b19e7d527 refactor(angular.copy): use array.length=0 to empty arrays 2013-02-11 14:07:49 -08:00
Igor Minar 28273b7f1e refactor(angular.copy): use slice(0) to clone arrays
slice(0) is way faster on most browsers
2013-02-11 14:07:03 -08:00
Igor Minar ec54712ff3 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:29:55 -08:00
radu 23dd78f8a4 docs($q): fix typos 2013-02-07 04:16:16 -08:00
Julie d46fe3c23f 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:09:52 -08:00
Enrique Paredes 92ca7efaa4 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:12 -08:00
Fredrik Bonander 7090924515 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:25 -08:00
Maxim Grach df744f3af4 feat(dateFilter): add [.,]sss formatter for milliseconds
Also Implement getMilliseconds() method of TzDate and
add test for this in ngMock.
2013-02-07 02:28:33 -08:00
Sam McCall 8155c3a29e feat($http): allow overriding the XSRF header and cookie name
Add 'xsrfCookieName' and 'xsrfHeaderName' property to $httpProvider.defaults and
http config object, which give the name of the cookie the XSRF token is found
in, and the name of the header it is sent in, respectively.
This allows interop with servers with built-in XSRF support that use different
names.
The defaults match the current hard-coded values of 'XSRF-TOKEN' and
'X-XSRF-TOKEN'.
2013-02-07 01:48:01 -08:00
Philip Roberts b001c8ece5 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:32:04 -08:00
Igor Minar bec4435945 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:14:49 -08:00
Thomas Schultz 6fb1054ce6 docs(tutorial): remove extra back-tick character 2013-02-06 21:51:42 +01:00
theotheo a83eced974 docs(module): fix code example 2013-02-06 20:40:06 +01:00
radu 7cc4063303 docs(ngApp): fix typo 2013-02-05 21:29:11 +01:00
Igor Minar d8e242418d docs(contributing): add CLA anchor for deeplinking 2013-02-04 09:38:01 -08:00
PowerKiKi 6518369f25 docs(ngClass): fix typo in description 2013-02-04 10:36:29 +00:00
Brian Ford 649b892205 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:42:56 -05:00
Dean Sofer e0295cfec4 docs($cookies): added example to $cookies api docs
Better than nothing.
2013-01-29 16:16:17 -08:00
radu 17fc6a70fe docs(nextUid): fix typo
Update src/Angular.js

removed redundant 'the' from nextUid()'s ngdoc
2013-01-29 15:49:10 -08:00
radu 5d0f9ce4c7 docs(tutorial): fix typo
Update docs/content/tutorial/step_00.ngdoc

removed redundant verb
2013-01-29 15:46:32 -08:00
Fred Sauer 250aec71f3 docs(Scope): fix argument docs for $on 2013-01-29 15:38:19 -08:00
metaweta 3b317c5dcb 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 13:26:06 -08:00
metaweta e4cfb9d938 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 13:24:33 -08:00
Igor Minar 87ba8221ec chore(release): start 1.1.3 radioactive-gargle iteration 2013-01-29 13:20:43 -08:00
Fred Sauer e34519e93b docs(a): escape sample code in ng a directive 2013-01-26 22:52:16 +01:00
Igor Minar 69be39fccf fix(docs): properly generate angular.js urls in doc examples 2013-01-24 11:36:03 -08:00
Igor Minar deac80a6e8 docs(date): add missing doc about TZ behavior 2013-01-24 10:51:03 -08:00
Igor Minar 0539611bac docs(changelog): correct 1.0.4 release notes 2013-01-24 09:50:27 -08:00
Vineet Kumar d2177ae312 docs($injector): clarify $inject property description
Section heading about `$inject` property refers to it as `$injector` property.
2013-01-24 00:15:32 -05:00
Partap Davis f3bff27460 feat(resource): add $q/$resorved property to Resource 2013-01-23 20:57:26 -08:00
Igor Minar 4df45b20d4 chore(release): update the CDN version 2013-01-23 12:06:40 -08:00
Igor Minar 5745734991 chore(release): cut 1.1.2 tofu-animation release 2013-01-23 10:54:35 -08:00
Igor Minar 0551aa95f0 docs(changelog): release notes for 1.1.2 and 1.0.4 2013-01-22 22:58:55 -08:00
Igor Minar b62327ec2d docs(ngOpen): fix typo in api docs 2013-01-22 22:58:55 -08:00
Igor Minar 07a58dd766 chore(changelog.js): improve the changelog script 2013-01-22 22:49:00 -08:00
Igor Minar ffe5e01584 revert: fix($resource): Route constructor, updated RegExp
This reverts commit 06ed8ef012.

The reverted commit causes regressions. See comments in the PR:
https://github.com/angular/angular.js/pull/1402#issuecomment-12575399
2013-01-22 16:32:02 -08:00
Igor Minar 3c2e1c5e4d 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:21 -08:00
Igor Minar cdf7781878 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:16 -08:00
sergiopantoja 7e8d3c1736 docs(jqLite): fix typo 2013-01-20 18:39:21 +01:00
Will Moore d30845a757 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:10 -08:00
Fredrik Bonander 06ed8ef012 fix($resource): Route constructor, updated RegExp
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-01-18 21:28:15 -08:00
Pedro Del Gallego 2f437e8978 feat(scenario): add mouseover method to the ngScenario dsl 2013-01-18 21:24:57 -08:00
Luis Ramón López faf02f0c4d feat(route): Allow using functions as template params in 'when' 2013-01-18 21:20:49 -08:00
David Chang b8bd4d5460 feat(directive): added ng-open boolean directive
Closes# 1797 add ng-open attribute
2013-01-18 21:16:16 -08:00
pavelgj b2f46251ac 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-18 20:52:57 -08:00
danilsomsikov a26234f718 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:28 -08:00
Misko Hevery 61315211da fix(git-validator): support fixup and better errors 2013-01-17 23:52:46 -08:00
Misko Hevery af89daf464 feat(ngResource): support all $http.config actions
This allows the transformation of the $http request in both directions,
headers, caching, and timeout.
2013-01-17 23:08:39 -08:00
Fred Sauer 224d7d6e90 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:08:39 -08:00
Jeremy Tymes a179a9a96e feat($parse): allow strict equality in angular expressions
Allows the parser to parse strict equality and inequality
in angular expressions.

Closes #908
2013-01-17 23:08:38 -08:00
Matthew Browne 610a5a0c14 docs(rootScope): correct code examples 2013-01-17 23:08:38 -08:00
Amir H. Hajizamani 4f5583465a 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:49:41 -05:00
Amir H. Hajizamani 75487ec933 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:49:41 -05:00
Fred Sauer dddb1221fa docs(ngMock.$httpBackend): fix variable declaration 2013-01-18 00:13:39 -05:00
Shai Reznik 69e4d40a76 doc(guide): Fixed typos at the unit tests guide 2013-01-17 23:43:13 -05:00
Shai Reznik d521619c58 doc(guide): Fix examples of $location.html5mode 2013-01-17 23:43:13 -05:00
Igor Minar 5ae63fd385 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:48:51 -08:00
Daniel Demmel 8b44324814 docs: recommend using Google CDN 2013-01-17 16:52:05 -08:00
nlaplante 9e991ddb1d feat($log): add $log.debug()
New debug() method with suppressable output via
$logProvider.debugEnabled()

Closes #1592
2013-01-17 16:47:39 -08:00
Matt Rohrer 93070f1488 docs(guide): minor grammar fixes 2013-01-17 19:10:46 -05:00
Gergely Imreh 3c8583e5dd 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 01:34:01 -08:00
Igor Minar 78699c62ea chore(docs): use done() instead of end() in gen-docs.js 2013-01-17 00:51:56 -08:00
Pete Bacon Darwin 49f9e4cef1 fix($compile): do not wrap empty root text nodes in spans
Closes #1059
2013-01-17 00:28:44 -08:00
Pete Bacon Darwin 7e746015ea 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:30 -08:00
James deBoer 8c269883fd chore(Rakefile): remove a duplicate file in angularFiles.js 2013-01-16 23:45:09 -08:00
James deBoer a69674b36d 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:45 -08:00
Igor Minar 8b9e6c3501 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:26:36 -08:00
Kanwei Li c97c53dbd4 docs(CHANGELOG): fix typo 2013-01-16 21:55:06 +01:00
Martin Probst c6392616ea 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:41:02 -08:00
Igor Minar 74dd2f7980 fix($compile): safely create transclude comment nodes
Closes #1740
2013-01-14 21:57:23 -08:00
Lucas Galfasó c0cb9f8c14 doc(directive): Fix typos in dialog widget
Fixes #1799
2013-01-13 10:08:19 +00:00
Igor Minar 7dff7bb696 chore(*): remove obsolete files 2013-01-09 21:28:53 -08:00
Martin Probst cdf6fb19c8 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-09 20:06:22 -08:00
Igor Minar c909f49112 style($compile): fix indentation 2013-01-09 16:54:29 -08:00
Igor Minar cc821502bc fix(date): parse string input as local time unless TZ is specified
previously we were always parsing the string input as UTC which cased issues like:

{{ '2012-04-01' | date:'d MMM yyyy' }} renders as 31 Mar 2012

BREAKING CHANGE: string input without timezone info is now parsed as local time/date

Closes #847
2013-01-09 09:50:43 -08:00
naomiblack 037aefae47 Update docs/content/misc/faq.ngdoc
Updated the canonical video to a recent one. Fixed a typo.
2013-01-09 09:49:44 +00:00
Pete Bacon Darwin febb4c1c35 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:22:35 +00:00
Keyamoon 76a6047af6 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:15 -08:00
Igor Minar b6b7c5a1d6 fix($injector): remove bogus fn arg
getService fn takes only one argument, removing the second one.

Closes #1711
2013-01-08 14:36:03 -08:00
Igor Minar 5b5f35d5e4 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:23:50 -08:00
Igor Minar 14948cf5d9 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:47:22 -08:00
kim lokoy 2b0978b07c docs(guide): fix typos in unit test guide 2013-01-07 21:01:01 +01:00
Pawel Kozlowski 1122dc7a5b docs(forms): fix code example for a custom form control
Closes #1021
2013-01-05 22:47:36 +01:00
naomiblack a3a9d4af05 docs(faq): add info on logo reuse and how to get t-shirts and stickers 2013-01-04 18:59:11 +01:00
Jonathan Card 36089931a5 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 09:28:35 +01:00
Per Rovegård 74db36ee94 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:49:43 +01:00
Matt Hardy 8d42ce8563 docs(guide): change example controller to properly call greet method on greeter 2012-12-31 12:49:51 +01:00
petrovalex f0c6ebc076 feat($timeout-mock): add verifyNoPendingTasks method
added verifyNoPendingTasks method, which throws error if not all
deferred tasks have been flushed

Closes #1245
2012-12-20 20:39:40 +01:00
Murilo da Silva 59d9b89852 docs(anchorScroll): correct word "location" 2012-12-19 21:01:41 +01:00
John Fletcher 6aac69039e docs(guide): minor English corrections to the Directive guide 2012-12-19 20:35:31 +01:00
Jeremy Tymes 9e96d98345 feat(limitTo): limitTo filter accepts strings
This allows strings to be filtered by limitTo, using the same methods

Closes #653
2012-12-19 20:13:36 +01:00
Miško Hevery 1e13544da8 docs(directive): old syntax 2012-12-18 20:38:43 -08:00
Mark Nadig e03182f018 feat(directive): ng:keydown, ng:keyup
New directives for binding to keydown and keyup events.

Closes #1035
2012-12-18 22:57:58 +01:00
Pawel Kozlowski f2d526190a docs(ngView): fix code example (change template to templateUrl)
Closes #1715
2012-12-17 23:18:12 +01:00
Miško Hevery 039b138042 docs(q): added testing information 2012-12-14 05:49:22 -08:00
Gonzalo Ruiz de Villa 30a9da5dc1 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:15:15 +01:00
ggoodman 25e1ad9a94 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-11 19:04:46 +00:00
Peter Evjan 37cced6296 docs(README.md): add missing 'you' and a comma 2012-12-11 19:20:30 +01:00
Romain Neutron a66c968df2 docs(guide): fix injector service code example
Fix syntax and update code to the latest API
2012-12-10 23:19:20 +01:00
Juha Syrjälä c398d7d370 docs($resource): document port number escaping and fix typo
Closes #1243
2012-12-09 17:13:29 +01:00
Eric Case d93533812b docs(tutorial): typo fix commandx -> command 2012-12-08 11:33:07 +01:00
Eric Case ff11061a8f docs($q): typo fix - programing -> programming 2012-12-07 20:45:33 +01:00
János Rusiczki c52bfd37ee doc(concepts): Fix typo in $render() function 2012-12-07 10:03:58 +00:00
Jeremy Tymes f8b755982a docs($http): fix link typo in $http doc
Should be $httpBackend instead of $httpBacked

Closes #1516
2012-12-06 21:25:47 +01:00
Fred Sauer bcc7089b3c docs(mocks): update src/ngMock/angular-mocks.js documentation
Clarify how to use `$exceptionHandlerProvider.mode('log')` in tests
2012-12-06 21:18:49 +01:00
Fred Sauer d43cc3f893 docs(mocks): fix documentation bug: angular.mock.debug 2012-12-06 21:13:51 +01:00
Igor Minar c9d937082c chore(bootstrap-prettify): update urls to code.angularjs.org
Closes #1599
2012-12-05 02:55:43 +01:00
_pants 26adeb119b fix(select): support optgroup + select[multiple] combo
Closes #1553
2012-12-05 02:20:11 +01:00
Stephane Bisson 15183f3e1f feat(e2eRunner): fail when an option to select does not exist 2012-12-01 20:05:42 +01:00
Sudhir Jonathan 2c405f4171 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 18:41:59 +01:00
Sudhir Jonathan 8991680d8a fix($resource): HTTP method should be case-insensitive
Perform call `angular.uppercase` on all given action methods.

Closes #1403
2012-11-30 22:58:11 +01:00
Cezar Berea ec801ac137 refactor($resource): fix indentation and move a method definition
Moved Resource.bind out of the actions forEach
2012-11-30 22:35:57 +01:00
Igor Minar d6da505f4e 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:10:00 +01:00
Daniel Luz 5f7054bf5d docs(directive): correct expression, fix typo and re-wrap lines 2012-11-29 19:40:33 +01:00
Johannes Hansen cf4ed8a145 fix(docs): add missing </div> tag to sourceEdit directive template 2012-11-29 19:40:30 +01:00
Igor Minar d1e48fcbf3 docs(menu): fix the navbar drop down links 2012-11-28 23:56:09 +01:00
Pascal Corpet cc42c99bec feat($resource): allow dynamic default parameters
Default resource params can now be calculated at runtime if defined
via a function.
2012-11-28 16:01:57 +01:00
Igor Minar 3c7bfa77aa chore(release): start 1.1.2 tofu-animation iteration 2012-11-28 14:21:33 +01:00
Igor Minar 2ee0f56c54 chore(release): cutting the 1.1.1 pathological-kerning release 2012-11-27 01:45:35 +01:00
Igor Minar 9b18644f30 docs(CHANGELOG): release notes for 1.0.3 and 1.1.1 releases 2012-11-27 01:43:05 +01:00
Rado Kirov fce100a46c fix($http): only set X-XSFR-TOKEN header for same-domain request
This is needed to prevent CORS preflight checks. The XSFR token
is quite useless for CORS requests anyway.

BREAKING CHANGE: X-XSFR-TOKEN is no longer send for cross domain
requests. This shouldn't affect any known production service.

Closes #1096
2012-11-26 23:58:59 +01:00
Rado Kirov 3a75b1124d fix($http): remove 'X-Requested-With' from header defaults
X-Requested-With header is rarely used in practice and by using
it all the time we are triggering preflight checks for crossdomain
requests.

We could try detecting if we are doing CORS requests or not, but
it doesn't look like it's worth the trouble.

BREAKING CHANGE: X-Requested-With header is not set by $http service
any more. If anyone actually uses this header it's quite easy to add
it back via:

```
myAppModule.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
```

Closes #1004
2012-11-26 23:36:40 +01:00
Rado Kirov a32bc40fd7 fix($location): reset $location.$$replace with every watch call
Closes #1111
2012-11-26 23:21:02 +01:00
Igor Minar cfe13b5dac chore(validate-commit-msg): recognize 'revert' as valid commit type 2012-11-26 21:05:38 +01:00
Igor Minar d859dcecea 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 20:36:53 +01:00
Igor Minar d3b32a7c94 style(jqLite): better variable names
selector => cssClasses
2012-11-26 20:36:53 +01:00
Igor Minar 1b17dfa693 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 20:36:53 +01:00
Igor Minar e6d9bea4f3 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 20:36:53 +01:00
Igor Minar c8e9105fe6 test(ngRepeat): clean up and improve tests 2012-11-26 20:36:52 +01:00
Igor Minar d644dcfa52 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:31:54 +01:00
Igor Minar e7d37ee45a test(ngRepeat): add test for issue #1076 2012-11-26 20:17:11 +01:00
Pawel Kozlowski 733a97adf8 feat(form): add ability to reset a form to pristine state
Retting a form to pristine state will cause all of the nested
form and form controls to be recursively reset as well.

Closes #856
2012-11-26 16:44:34 +01:00
Igor Minar 96ed9ff59a fix(jqLite): support append on document fragment
previously jquery didn't support append on this node type, now it does
(since 1.8.x) so I'm adding this to jqlite as well.
2012-11-26 15:45:04 +01:00
Igor Minar b9a9f91fbf 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 15:45:04 +01:00
Igor Minar 650fd933df 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 15:45:04 +01:00
Igor Minar e249502880 chore(jquery): upgrade to jquery 1.8.2 2012-11-26 15:45:04 +01:00
Iristyle ca3e0e7374 docs(CONTRIBUTING.md): add contrib info file for GitHub 2012-11-25 21:00:14 +01:00
Vojta Jina e6966e05f5 fix(Scope): allow removing a listener during event 2012-11-25 11:39:54 +01:00
Kevin Western 682418f029 docs(README.md): fix "API Docs" link
use direct link to api docs
2012-11-25 01:21:52 +01:00
Dean Sofer c8fd7fd0e2 docs(api): add ngRequired to input/select/textarea directives
Closes #1202
2012-11-25 01:18:10 +01:00
JP Sugarbroad 168db33985 feat($cacheFactory): cache.put now returns the added value
This allows common programming patterns to be expressed with more
concise code.

See #1583 for code examples.
2012-11-25 00:01:34 +01:00
Tom Davis 79af2badcb fix($http): config.param should expand array values properly
Today, calling e.g. $http(url, { params: { a: [1,2,3] } }) results in a query
string like "?a=%5B1%2C2%2C3%5D" which is undesirable. This commit enhances
buildURL to createa query string like "?a=1&a=2&a=3".

BREAKING CHANGE: if the server relied on the buggy behavior then either the
backend should be fixed or a simple serialization of the array should be done
on the client before calling the $http service.

Closes #1363
2012-11-24 22:26:23 +01:00
Zach Dexter 610927d77b feat(linky): allow optional 'target' argument
Closes #1443
2012-11-24 22:21:50 +01:00
Jeremy Tymes 55d15806fb 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:56:28 +01:00
Adrian Gheorghe 94e1c0391c 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:27:24 +01:00
Kris Jenkins b21f4a376d docs(): Fix a couple of typos in the documentation 2012-11-21 23:06:59 +01:00
Dave Clayton f28f283fcf docs(guide/concepts): some typo/grammar fixes 2012-11-17 23:55:32 +01:00
John Hume e362a510e3 docs(guide/directive): fix typo 2012-11-17 23:49:19 +01:00
Uri Goldshtein 8a7f752a80 docs($q): fix missing bracket in the example 2012-11-17 23:45:08 +01:00
Igor Minar af7e0bd0a7 fix(CSP): update to the latest CSP api
window.SecurityPolicy.isActive() is now window.securityPolicy.isActive

since this is available only in Chrome Canary which has already been
updated, we can safely make this change without worrying about
backwards compatilibty.

Closes #1577
2012-11-15 01:46:58 +01:00
Igor Minar bd524fc4e5 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:56:28 +01:00
Haralan Dobrev 19a324ce11 docs(angular.module): improve angular.Module#run docs 2012-11-11 11:40:18 +01:00
Jamison Dance cd8b78ebfd docs(guide): fix run-on sentence in modules guide 2012-11-11 11:34:06 +01:00
Jamison Dance 8891757891 docs(tutorial): change module name in step-7 2012-11-11 11:34:06 +01:00
Wes Alvaro 5c5193946d 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:31:51 +01:00
Josh Adams ffa6c5195f docs(ngList): fix typo 2012-11-11 11:24:59 +01:00
Josh Adams a758799c7f docs(encodeUriSegment): fix typo 2012-11-11 11:22:43 +01:00
Tim Macfarlane e9253a88b9 docs(guide/directive): fix names in scope '='; easier to grok 2012-11-11 11:20:24 +01:00
Christian Vuerings f3e053cb6f docs(ngHide): Fix typo and make it more in line with ngShow 2012-11-11 10:36:28 +01:00
Anna Vester 04450c48df feat($sanitize): support telephone links
Per http://www.ietf.org/rfc/rfc3966.txt support tel: links
2012-11-11 10:31:27 +01:00
Igor Minar 8650843603 chore(docs): fix docs-scenario.html 2012-11-11 10:31:27 +01:00
Igor Minar e034fa08a8 chore(docs): remove obsolete gae files 2012-11-11 10:31:27 +01:00
Miško Hevery c6b4ab3548 Update docs/content/guide/directive.ngdoc
docs(directive): fix typo
2012-11-05 19:34:20 -08:00
Sudhir Jonathan b429f538a3 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 16:47:28 -07:00
Sudhir Jonathan b3cae4f457 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:13 -07:00
Igor Minar 7b52a976e1 chore(validate-commit-msg): allow '/' in scope 2012-10-31 14:47:59 -07:00
Fred Sauer 3a624a7ff5 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:47:53 -07:00
Tim Macfarlane b32adb7dea docs(module): fix typo in example
fixed example app, `simpleAppModule` should have been `myAppModule`.
2012-10-31 14:21:28 -07:00
sqwishy trick 271d2bed3a chore(injector): fix typo in injector documentation 2012-10-31 14:19:05 -07:00
Adam Macejak 249a1d84e7 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 13:58:13 -07:00
Daniel Luz fdf85bfd86 docs(contribute): fix task name for continuous testing 2012-10-31 13:12:49 -07:00
Igor Minar 090e5426ac 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:03:50 -07:00
Shyam Seshadri 7c67b2fb6a feat(docs): add plunkr support
Add option to edit source in Angular Docs in Plunkr in addition to JsFiddle
2012-10-31 12:54:52 -07:00
Daniel Luz 3c9b39ff52 fix(doc): typo on FAQ
Closes #1493
2012-10-31 10:24:12 -07:00
Igor Minar 54b3875ba5 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 17:49:56 -07:00
Igor Minar 008a782bc8 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 17:49:36 -07:00
Igor Minar 524c5c8b5d style($compile): better fn names for debugging 2012-10-29 17:46:44 -07:00
Igor Minar b936236fbc refactor(): simplify nodeLinkFn 2012-10-29 17:46:44 -07:00
Igor Minar fc115bfd0d 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 17:46:44 -07:00
Braden Shepherdson bca1604c12 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-26 08:51:28 -07:00
Braden Shepherdson f4517b500c doc(faq): Add Common Pitfalls section
Describes several common pitfalls new users of Angular fall into that
I've observed in #angularjs.
2012-10-26 08:49:44 -07:00
Braden Shepherdson f54edbbdd4 doc(faq): Fix minor spelling and wording errors 2012-10-26 08:49:44 -07:00
Igor Minar be50e0769a chore(check-size.sh): fix rake target 2012-10-22 12:39:37 -07:00
Igor Minar cf78fb5661 docs(contribute): add CLA note to code submission section 2012-10-19 09:14:05 -07:00
Igor Minar 5c9eb75867 docs(contribute): add visible link to github project 2012-10-19 09:02:06 -07:00
Igor Minar f43cf3b816 chore(jstd-scenario-adapter): remove from our repo
since we don't need the adapter for JsTD (testacular contains its own),
I'm removing this dead code.
2012-10-18 03:26:51 -07:00
Igor Minar 175e727f05 chore(validate-commit-msg): allow * and - in scope string 2012-10-18 03:26:08 -07:00
Igor Minar d938983c06 chore(jasmine): remove Jasmine from our repo
it's bundled with Testacular, so we don't need it here
2012-10-18 03:14:27 -07:00
Igor Minar 8d69f4b93a chore(jstd): remove JsTestDriver from our repo
Testacular FTW!
2012-10-18 03:13:04 -07:00
Igor Minar ca96ec32f9 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:33:45 -07:00
Igor Minar 4f59022582 chore(Rakefile): remove test_out dir when cleaning 2012-10-17 15:44:18 -07:00
Igor Minar 3bd95dbb1a 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 15:36:51 -07:00
Igor Minar c959fa4fe8 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 14:38:15 -07:00
Vojta Jina a5d434d857 chore(test): add junit config for testacular 2012-10-17 13:17:16 -07:00
Igor Minar 0ae0591f42 chore(Rakefile): misc_options should support + -> , conversion 2012-10-17 12:48:08 -07:00
Igor Minar 43ac783d35 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:45:10 -07:00
Misko Hevery c96dc60594 fix(doc): disable directory listing in docs.angularjs.org 2012-10-05 16:43:01 -07:00
Igor Minar b440ad36f3 docs(downloading): update the downloading docs 2012-10-05 03:13:51 -07:00
Vojta Jina 8b2532cec7 chore: add travis config 2012-09-24 23:39:33 -07:00
Vojta Jina 8db47ca7d4 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-20 18:32:01 -07:00
Vojta Jina bcaa3bb373 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-09-17 18:08:16 -07:00
Igor Minar 6fc4fdb438 docs(README): update README.md with new rake tasks 2012-09-17 14:51:21 -07:00
Igor Minar 6a5f8c0483 chore(Rakefile): fix test:jquery task 2012-09-17 14:50:51 -07:00
Igor Minar 20c116d9d5 docs(contribute): update contribute docs 2012-09-16 10:40:44 -07:00
Igor Minar 4a04c2ec0c chore(): remove unused files 2012-09-16 10:39:43 -07:00
Igor Minar 89dd566277 docs(contribute): update misc/contribute docs with Testacular info 2012-09-15 08:11:53 -07:00
Igor Minar 9d168f058f 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-13 16:23:18 -07:00
Miško Hevery 5418564f04 docs(directive): remove reference to old isolation syntax 2012-09-13 11:31:06 -07:00
Misko Hevery b0a05a7531 fix($route): support inline annotation on .resolve 2012-09-11 22:10:26 -07:00
Tom Hughes 209b67df6a feat($http): Allow setting withCredentials on defaults
Closes #1095.
2012-09-11 21:59:31 -07:00
Vojta Jina 2e1539356a chore(scripts): add init-repo script 2012-09-11 17:27:57 -07:00
Misko Hevery 331cd5a8cb fix($evalAsync): have only one global async queue
Having one async queue per scope complicates the matters when users wish to do
partial scope updates, since many services put events on the rootScope. By
having single queue the programing model is simplified.
2012-09-11 16:12:41 -07:00
Brian Ford f2ebfa16b0 docs(guide): fix directive interpolation example code
Closes #1339
2012-09-11 16:12:41 -07:00
Shyam Seshadri 95276a7e10 fix(scenario): emit RunnerBegin event 2012-09-11 16:12:41 -07:00
Vojta Jina 5dbd942bac chore(scripts): add commit-msg hook (validation) 2012-09-11 16:12:40 -07:00
Jimmy Zhuo 84c13d96ff fix(scenario): NPE when no angular loaded in test page 2012-09-11 16:12:40 -07:00
Daniel Luz 79941d2527 docs($rootScope): fix iteration limit described by $watch, it's actually 10 as of now 2012-09-11 15:11:02 -07:00
Daniel Luz 03ebecd5eb docs($rootScope): fix typos and minor wording tweaks on $watch 2012-09-11 15:11:02 -07:00
Daniel Luz 62bb728d07 docs($rootScope): fix quoting on expression 2012-09-11 15:11:02 -07:00
Daniel Luz b8eb843b25 docs($rootScope): standardize on present, third-person actions for descriptions 2012-09-11 15:11:02 -07:00
Daniel Luz 053247e412 docs($rootScope): backquote attribute types too on $on 2012-09-11 15:11:02 -07:00
Daniel Luz 7fa391c979 docs($cacheFactory): fix backquotes on method descriptions 2012-09-11 15:11:01 -07:00
Daniel Luz b01c28c900 docs($rootScope): fix typos on $new 2012-09-11 15:11:01 -07:00
Daniel Luz c0b9e94dec docs($rootScope): fix typo on $eval 2012-09-11 15:11:01 -07:00
Daniel Luz 83fbdd1097 docs($rootScope): fix typos on $watch 2012-09-11 15:11:01 -07:00
Jay Zeng 03042c52b9 docs(ngResource): Spelling typo (agressive => aggressive) 2012-09-11 15:08:55 -07:00
Igor Minar 2a4a8226d1 fix($resource): fix isDefined -> angular.isDefined 2012-09-10 14:49:22 -07:00
sgtpep c81d8176cc 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 16:06:27 -07:00
Kai Groner 04329151d2 fix(FormController): propagate dirty state to parent forms 2012-09-06 16:06:26 -07:00
Jonathan Zacsh a9be003fce chore(docs): get correct location for jasmine-node 2012-09-06 16:06:25 -07:00
Shyam Seshadri ca30fce28c fix(*): name all anonymous watch functions in Angular
This will allow us to see function names in Batarang and debugger.

Closes #1119
2012-09-06 16:06:25 -07:00
Xiangru Chen b6e4a71166 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 16:06:24 -07:00
Misko Hevery d9eff86ef7 fix($injector): more conservative annotation parsing 2012-09-06 16:06:24 -07:00
Pedro Del Gallego 8cb9c99ec0 feat(scenario): add dblclick method to the ngScenario dsl 2012-09-06 16:06:24 -07:00
Iwein Fuld 9473780e77 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 16:06:23 -07:00
Misko Hevery eb5fd400d3 docs(concept): correct example for creating injector 2012-09-06 16:06:23 -07:00
Godmar Back 0472c5f07e docs(module): fixed module example and corrected typos 2012-09-06 16:06:23 -07:00
Cameron Westland 92558fe411 feat(mocha): support mocha in angular mocks 2012-09-06 16:06:23 -07:00
Gregory Pike d519953a4b feat(ngModel): support ngTrim attribute on input 2012-09-06 16:06:23 -07:00
Benjamín Eidelman 4909d1d39d 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 16:06:22 -07:00
Jay Zeng 7079ff5eb6 docs(module): myAppModule -> simpleAppModule 2012-09-06 16:06:22 -07:00
petrovalex 10e1c759f4 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 16:06:22 -07:00
petrovalex 6c67719dfa fix(ngClassEven/Odd): filtering/ordering and repeater
Closes #1076
2012-09-06 16:06:22 -07:00
Max Martinsson cebd015f78 fix(ngClass): works with class interpolation
Closes #1016
2012-09-06 16:06:21 -07:00
Max Martinsson fbdab513dd feat($resource): support custom headers per action
Closes #736
2012-09-06 16:06:21 -07:00
Zhenbo Zhang f2b7fffdc0 fix(ngRepeat): now works with primitive types
closes #933
2012-09-06 16:06:21 -07:00
petrovalex 42c38b29f7 fix($parser): string concatination with undefined model
Closes #988
2012-09-06 16:06:21 -07:00
Stein Jakob Nordbø f299fd5122 fix(dateFilter): support sub-second precision on dateFilter 2012-09-06 16:06:19 -07:00
Igor Minar 05c88b866b docs($route): rename leftover $afterRouteChange to $routeChangeSuccess 2012-09-06 15:03:35 -07:00
Igor Minar 9b08bfa251 chore(release): prepare 1.1.1 pathological-kerning iteration 2012-09-06 10:41:23 -07:00
Misko Hevery 99a000bac2 fix(docs): broken url to angular-bootstrap 2012-09-04 18:15:00 -07:00
Igor Minar f353fea042 chore(Rakefile): add 'version' rake task to generate version.txt 2012-09-04 16:38:01 -07:00
Igor Minar b1f50307b3 chore(docs): bump up the stable version 2012-09-04 16:31:57 -07:00
Igor Minar d0c0eadedd chore(release): cut the 1.1.0 increase-gravatar release 2012-09-04 11:11:09 -07:00
Igor Minar b8fac353f0 chore(docs): don't rewrite colons in doc filenames 2012-09-04 11:11:09 -07:00
Igor Minar b22308152f chore(Rakefile): zip only the build dir 2012-08-31 13:59:03 -07:00
Igor Minar 5e9041818b revert: fix(ng-repeat) to work with primitive types
this was accidentaly merged in. the commit is not ready yet
and we don't have CLA signature.

This reverts commit 98d489712e.
2012-08-31 13:59:03 -07:00
Igor Minar db861db1f2 docs(changelog): release notes for 1.0.2 and 1.1.0 releases 2012-08-31 13:59:03 -07:00
Jonathan Zacsh b12d1b6813 fix(docs): Making sure gen_docs.sh looks for a globally installed copy of jasmine-node as well as local. 2012-08-30 22:33:30 -07:00
Fernando Correia acb499f820 docs(tutorial): correct typos and clarify a few sections 2012-08-30 22:19:34 -07:00
Brice Burgess 9a710c788d fix(docs): indicate support for passing a string as the controller property on $routeProvider's route object 2012-08-30 22:13:20 -07:00
brettcannon 1b34c6d558 doc(misc) Mention how attribute names map to directive names. 2012-08-30 22:09:16 -07:00
Igor Minar a62c7b8b4e test(locationSpec): fix broken tests after vojta's commit 2012-08-30 16:25:23 -07:00
Sahat Yalkabov 62cfedbe0c doc(module) changed simpleApp to myApp in the Module page guide for consistency 2012-08-30 16:10:39 -07:00
Steve Nicolai 5cb7297a08 doc(devguide) - Fix typos and small grammatical errors in the developer guide. 2012-08-30 16:02:24 -07:00
Igor Minar 0f05516d14 chore(docs): ask GAE to serve docs-keywords.js 2012-08-30 15:58:55 -07:00
Uri Goldshtein f5f1200f25 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 15:49:11 -07:00
Tyson Benson c023c850c3 docs(typos): fix typos in dev guide 2012-08-30 15:43:58 -07:00
German Galvis 5318588d6e fix(scenario): Adding meta tag to avoid cache issues 2012-08-30 15:36:42 -07:00
phil 14c8f6a7ca docs(api): fix typo on home page
Refference -> Reference
2012-08-30 15:31:29 -07:00
csugden 351deb555f Update docs/content/guide/overview.ngdoc
Corrects video information
2012-08-30 15:28:15 -07:00
Jamie Krug 847d2da0f8 fix(docs): Fix typos and improve grammar. 2012-08-30 15:25:21 -07:00
Jamie Krug dbefd671e4 fix(docs): Fix bad links. 2012-08-30 15:25:20 -07:00
Colin Frei aff68a9ddf docs(module) fix typo 2012-08-30 15:22:08 -07:00
Zhenbo Zhang 0a71753ce3 fix(ng-repeat) to work with primitive types 2012-08-30 15:20:40 -07:00
Vojta Jina 1a8642aac2 fix(mocks): free up memory after every spec 2012-08-30 15:18:09 -07:00
Igor Minar 8114d55a15 test(bootstrap): test exception siling during bootstrap
Closes #1018
2012-08-30 15:15:11 -07:00
Igor Minar 9398040a41 test(ngApp): add missing test for [ng-app] bootstrap 2012-08-30 15:15:11 -07:00
Brian Ford d804bbcd51 feat($interpolate): provide contextual error messages
if an exception occurs during interpolation of a string
(e.g. name() in "Hello, {{name()}}!" throws an exception) we now print
an error message with the expression that was being evaluated when the
exception was thrown.
2012-08-30 14:50:22 -07:00
Igor Minar d3fa7a2e9e 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:53:23 -07:00
Igor Minar 8693eac417 chore(docs): correctly link docs images 2012-08-30 02:26:35 -07:00
Igor Minar e0184d4aef chore(Rakefile): fix the default task 2012-08-29 16:56:48 -07:00
Igor Minar 1702e49548 chore(Rakefile): remove bogus symlink from build 2012-08-29 14:58:10 -07:00
Igor Minar d6706efe7f 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:06:50 -07:00
Igor Minar b08d4b22d2 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 12:38:34 -07:00
Misko Hevery e8ded01cf5 doc($log): correct non-working example 2012-08-27 15:44:38 -07:00
Misko Hevery 7a5f25f667 doc(guide): add concepts 2012-08-27 15:44:38 -07:00
Misko Hevery 96697f464f fix(ngdoc): failing test 2012-08-27 15:44:38 -07:00
Colin Frei 7e18724dfa doc(directive) correct typos 2012-08-27 15:01:50 -07:00
Misko Hevery c269eb3d26 fix(docs) typo 2012-08-27 14:59:19 -07:00
Misko Hevery fa62ea810f fix(ng-list): remove data bound flicker 2012-08-27 14:59:18 -07:00
Misko Hevery bf8ed8a532 doc(misc) updated getting started to reflect the new homepage 2012-08-27 14:59:18 -07:00
Misko Hevery d05a2809a1 doc(guide) simplify the guide home page 2012-08-27 14:59:17 -07:00
Igor Minar fa6c8c3131 chore(Rakefile): rewrite version numbers in all index files 2012-08-27 12:26:04 -07:00
Igor Minar f7ac8ef97a chore(docs): support _escaped_fragment_ hack for crawler 2012-08-25 02:30:55 -07:00
Igor Minar 4a4b28dbf3 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 14:54:35 -07:00
Igor Minar 3e12bc481d docs(a): expose hidden docs
It seems that docs for these directive were previously hidden by accident
2012-08-24 14:54:34 -07:00
johnlindquist 32137cab82 docs(ngRoute): fix typo
aftre -> after
2012-08-23 15:11:07 -04:00
phil f7b4296c38 docs(tutorial): fix typo in step_00
Just removed an extra comma. No big deal.
2012-08-23 01:02:28 -07:00
Igor Minar cab5e1d9b3 fix(docs): update docs top menu links 2012-08-16 11:26:36 -07:00
Igor Minar dfe99836cd 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:33:56 -07:00
Igor Minar 0f37194fb7 refactor($compile): code cleanup 2012-08-13 09:48:23 -07:00
Brian Ford e85774f709 fix(ngPluralize): fixes ng-pluralize when using non-standard start/end symbols
Closes #1134
2012-08-13 09:48:23 -07:00
Igor Minar 44345c74de style(ngPluralizeSpec): fix indentation 2012-08-13 09:48:22 -07:00
Igor Minar 58f121a5c2 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 09:48:22 -07:00
Igor Minar cf6023ef22 docs($interpolateProvider): fixing docs 2012-08-13 09:48:22 -07:00
Igor Minar 2034871764 fix($interpolate): $interpolateProvider.endSymbol() returns startSymbol
I also added missing tests.
2012-08-13 09:48:21 -07:00
Igor Minar 15d283b114 docs($interpolate): fix typo in description 2012-08-13 09:48:21 -07:00
Vojta Jina 9be169365c docs($compileProvider): remove duplicate of .directive() 2012-08-12 10:45:14 -07:00
Vojta Jina 00683a8bbb docs: fix broken links to $compileProvider.directive() 2012-08-12 10:44:29 -07:00
Brian Ford f00b6cca02 fix(docs): fixed documentation for using linky 2012-08-10 16:33:25 -07:00
Brian Ford e05a97c6f5 chore(ngDoc): add support for custom @usage metadata 2012-08-10 16:33:13 -07:00
Brian Ford 2e3651686c fix(docs): added note about using JSON3 as a polyfill for IE7 2012-08-10 16:27:44 -07:00
Brian Ford 536de14821 fix(docs): added note about needing JSON shim for IE7 and earlier 2012-08-10 16:27:44 -07:00
Vojta Jina e0a54f6b20 feat($http): support reponseType
Closes #1013
2012-08-10 16:17:59 -07:00
Igor Minar 9767f7bdd3 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:30 -07:00
Vojta Jina 167aa0c29c feat($sniffer): auto detect CSP mode
Chrome Canary now has CSP with apis that allow auto-detection. This change
will turn on CSP mode automatically when we detect its presence.

https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-interfaces--experimental
2012-08-10 14:53:53 -07:00
unirgy 4ccd9eb883 docs($rootScope): fix $on listener signature doc
Added args in $on() listener syntax declaration
2012-08-10 14:50:22 -07:00
Igor Minar c0d638a94b test(jqLite): add missing test for $destroy event 2012-08-10 13:04:39 -07:00
Igor Minar 054d40f338 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 13:03:55 -07:00
Igor Minar 5cec32492c 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-07 22:07:49 -07:00
Igor Minar c25cb7d488 refactor(formSpec): group preventDefault specs into a describe 2012-08-07 17:23:16 -07:00
Igor Minar 54e4a6ffbf docs(faq): update faq docs 2012-08-07 10:15:54 -07:00
Igor Minar eee9a51fad docs(styles): fix the cog icon alignment 2012-08-06 16:54:18 -07:00
Vojta Jina 77e6d833f6 chore(nodeserver): add font mime type 2012-08-04 12:09:28 -07:00
Vojta Jina 33ad2b4126 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-07-30 21:21:34 -07:00
Vojta Jina b84eaffd39 docs: fix icons
Copy fontawesome during build
2012-07-30 21:20:28 -07:00
brettcannon a1107e81eb fix(docs): "in depth" -> "in-depth" 2012-07-20 20:54:42 -07:00
JP Sugarbroad e3e8813e3c refactor($injector): move $injector into the providerCache
Better than special-casing '$injector' in createInjector.
2012-07-19 21:56:22 -07:00
Igor Minar 6e2d9711e8 chore(release): start 1.1.0 increase-gravatas iteration 2012-07-19 21:48:58 -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
679 changed files with 84168 additions and 17623 deletions
-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>
-1
View File
@@ -10,6 +10,5 @@ performance/temp*.html
*~
angular.js.tmproj
node_modules
jsTestDriver*.conf
angular.xcodeproj
.idea
-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
+13
View File
@@ -0,0 +1,13 @@
language: node_js
node_js:
- 0.8
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- npm install -g grunt-cli
- grunt package
- grunt webserver > /dev/null &
script:
- grunt test --browsers Firefox --reporters=dots
+1066 -2
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
+180
View File
@@ -0,0 +1,180 @@
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.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,
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: {}
},
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')
},
mobile: {
dest: 'build/angular-mobile.js',
src: util.wrap([
'src/ngMobile/mobile.js',
'src/ngMobile/directive/ngClick.js',
'src/ngMobile/directive/ngSwipe.js'
], 'module')
},
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/docs/components/angular-bootstrap.js',
src: util.wrap(['docs/components/bootstrap/bootstrap.js'], 'module')
},
bootstrapPrettify: {
dest: 'build/docs/components/angular-bootstrap-prettify.js',
src: util.wrap(['docs/components/bootstrap/bootstrap-prettify.js', 'docs/components/bootstrap/google-prettify/prettify.js'], 'module'),
styles: {
css: ['docs/components/bootstrap/google-prettify/prettify.css'],
minify: true
}
}
},
min: {
angular: 'build/angular.js',
cookies: 'build/angular-cookies.js',
loader: 'build/angular-loader.js',
mobile: 'build/angular-mobile.js',
resource: 'build/angular-resource.js',
sanitize: 'build/angular-sanitize.js',
bootstrap: 'build/docs/components/angular-bootstrap.js',
bootstrapPrettify: 'build/docs/components/angular-bootstrap-prettify.js',
},
docs: {
process: ['build/docs/*.html', 'build/docs/.htaccess']
},
copy: {
i18n: {
files: [
{ src: 'src/ngLocale/**', dest: 'build/i18n/', expand: true, flatten: true }
]
}
},
compress: {
build: {
options: {archive: 'build/' + dist +'.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('default', ['package']);
};
+29 -9
View File
@@ -1,19 +1,39 @@
AngularJS
=========
* Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/#!/tutorial
* API Docs: http://docs.angularjs.org
* Developer Guide: http://docs.angularjs.org/#!/guide
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!
Compiling
* 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
-------------
./server.sh # start the server
open http://localhost:9876/capture # capture browser
./test.sh # run all unit tests
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).
-328
View File
@@ -1,328 +0,0 @@
require 'yaml'
include FileUtils
content = File.open('angularFiles.js', 'r') {|f| f.read }
files = eval(content.gsub(/\};(\s|\S)*/, '}').
gsub(/angularFiles = /, '').
gsub(/:/, '=>').
gsub(/\/\//, '#'));
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].sub(/\D+.*$/, ''),
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
concat_file('angular-scenario.js', [
'lib/jquery/jquery.js',
'src/ngScenario/angular.prefix',
files['angularSrc'],
files['angularScenario'],
'src/ngScenario/angular.suffix',
], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css'))
end
desc 'Compile JSTD Scenario Adapter'
task :compile_jstd_scenario_adapter => :init do
concat_file('jstd-scenario-adapter.js', [
'src/ngScenario/jstd-scenario-adapter/angular.prefix',
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
'src/ngScenario/jstd-scenario-adapter/angular.suffix',
])
# 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 'Compile JavaScript'
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
concat_file('angular.js', [
'src/angular.prefix',
files['angularSrc'],
'src/angular.suffix',
], gen_css('css/angular.css', true))
FileUtils.cp_r 'src/ngLocale', path_to('i18n')
concat_file('angular-loader.js', [
'src/loader.prefix',
'src/loader.js',
'src/loader.suffix'])
concat_module('sanitize', [
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js'])
concat_module('resource', ['src/ngResource/resource.js'])
concat_module('cookies', ['src/ngCookies/cookies.js'])
concat_module('bootstrap', ['src/bootstrap/bootstrap.js'])
concat_module('bootstrap-prettify', ['src/bootstrap/bootstrap-prettify.js',
'src/bootstrap/google-prettify/prettify.js'],
gen_css('src/bootstrap/google-prettify/prettify.css', true))
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
closure_compile('angular.js')
closure_compile('angular-cookies.js')
closure_compile('angular-loader.js')
closure_compile('angular-resource.js')
closure_compile('angular-sanitize.js')
closure_compile('angular-bootstrap.js')
closure_compile('angular-bootstrap-prettify.js')
end
desc 'Generate docs'
task :docs => [:init] do
`node docs/src/gen-docs.js`
rewrite_file(path_to('docs/.htaccess')) do |content|
content.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)
[ path_to('angular.js'),
path_to('angular.min.js'),
path_to('angular-loader.js'),
path_to('angular-loader.min.js'),
path_to('angular-bootstrap.js'),
path_to('angular-bootstrap.min.js'),
path_to('angular-bootstrap-prettify.js'),
path_to('angular-bootstrap-prettify.min.js'),
path_to('angular-mocks.js'),
path_to('angular-cookies.js'),
path_to('angular-cookies.min.js'),
path_to('angular-resource.js'),
path_to('angular-resource.min.js'),
path_to('angular-sanitize.js'),
path_to('angular-sanitize.min.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('i18n'), "#{pkg_dir}/i18n-#{NG_VERSION.full}"
FileUtils.cp_r path_to('docs'), "#{pkg_dir}/docs-#{NG_VERSION.full}"
rewrite_file("#{pkg_dir}/angular-mocks-#{NG_VERSION.full}.js") do |content|
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
end
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/index.html",
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq.html",
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-nocache.html",
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-nocache.html",
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-debug.html",
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-debug.html"
].each do |src|
rewrite_file(src) do |content|
content.gsub!(/'angular(.*)\.js/, '\'angular\1-' + NG_VERSION.full + '.js')
end
end
rewrite_file("#{pkg_dir}/docs-#{NG_VERSION.full}/docs-scenario.html") do |content|
content.sub!('angular-scenario.js', "angular-scenario-#{NG_VERSION.full}.js")
end
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/appcache.manifest",
"#{pkg_dir}/docs-#{NG_VERSION.full}/appcache-offline.manifest"
].each do |src|
rewrite_file(src) do |content|
content.sub!('../angular.min.js', "angular-#{NG_VERSION.full}.min.js").
sub!('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/")
end
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
def closure_compile(filename)
puts "Compiling #{filename} ..."
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
%x(java -jar lib/closure-compiler/compiler.jar \
--compilation_level SIMPLE_OPTIMIZATIONS \
--language_in ECMASCRIPT5_STRICT \
--js #{path_to(filename)} \
--js_output_file #{min_path})
rewrite_file(min_path) do |content|
content.sub!("'use strict';", "").
sub!(/\(function\([^)]*\)\{/, "\\0'use strict';")
end
end
def concat_file(filename, deps, footer='')
puts "Building #{filename} ..."
File.open(path_to(filename), '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
sub(/\(function\([^)]*\)\s*\{/, "\\0\n'use strict';") # add single strict mode flag
f.write(content)
f.write(footer)
end
end
def concat_module(name, files, footer='')
concat_file('angular-' + name + '.js', ['src/module.prefix'] + files + ['src/module.suffix'], footer)
end
def rewrite_file(filename)
File.open(filename, File::RDWR) do |f|
content = f.read
content = yield content
raise "File rewrite failed - No content!" unless content
f.truncate 0
f.rewind
f.write content
end
end
Vendored Regular → Executable
+44 -36
View File
@@ -9,11 +9,12 @@ angularFiles = {
'src/auto/injector.js',
'src/ng/anchorScroll.js',
'src/ng/animation.js',
'src/ng/animator.js',
'src/ng/browser.js',
'src/ng/cacheFactory.js',
'src/ng/compile.js',
'src/ng/controller.js',
'src/ng/defer.js',
'src/ng/document.js',
'src/ng/exceptionHandler.js',
'src/ng/interpolate.js',
@@ -29,6 +30,7 @@ angularFiles = {
'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',
@@ -47,6 +49,7 @@ angularFiles = {
'src/ng/directive/ngController.js',
'src/ng/directive/ngCsp.js',
'src/ng/directive/ngEventDirs.js',
'src/ng/directive/ngIf.js',
'src/ng/directive/ngInclude.js',
'src/ng/directive/ngInit.js',
'src/ng/directive/ngNonBindable.js',
@@ -69,17 +72,20 @@ angularFiles = {
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
'src/ngMock/angular-mocks.js',
'src/ngMobile/mobile.js',
'src/ngMobile/directive/ngClick.js',
'src/ngMobile/directive/ngSwipe.js',
'src/bootstrap/bootstrap.js'
'docs/components/bootstrap/bootstrap.js'
],
'angularScenario': [
'src/ngScenario/Scenario.js',
'src/ngScenario/browserTrigger.js',
'src/ngScenario/Application.js',
'src/ngScenario/Describe.js',
'src/ngScenario/Future.js',
'src/ngScenario/ObjectModel.js',
'src/ngScenario/Describe.js',
'src/ngScenario/Runner.js',
'src/ngScenario/SpecRunner.js',
'src/ngScenario/dsl.js',
@@ -98,7 +104,6 @@ angularFiles = {
'test/ngScenario/jstd-scenario-adapter/*.js',
'test/*.js',
'test/auto/*.js',
'test/bootstrap/*.js',
'test/ng/*.js',
'test/ng/directive/*.js',
'test/ng/filter/*.js',
@@ -107,7 +112,10 @@ angularFiles = {
'test/ngSanitize/*.js',
'test/ngSanitize/directive/*.js',
'test/ngSanitize/filter/*.js',
'test/ngMock/*.js'
'test/ngMock/*.js',
'test/ngMobile/directive/*.js',
'docs/component-spec/bootstrap/*.js',
'docs/component-spec/*.js'
],
'jstd': [
@@ -145,16 +153,22 @@ angularFiles = {
'src/ngMock/angular-mocks.js',
'src/ngCookies/cookies.js',
'src/ngResource/resource.js',
'src/ngMobile/mobile.js',
'src/ngMobile/directive/ngClick.js',
'src/ngMobile/directive/ngSwipe.js',
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
'src/ngScenario/browserTrigger.js',
'test/matchers.js',
'test/testabilityPatch.js',
'test/ngMock/*.js',
'test/ngCookies/*.js',
'test/ngResource/*.js',
'test/ngSanitize/*.js',
'test/ngSanitize/directive/*.js',
'test/ngSanitize/filter/*.js'
'test/ngSanitize/filter/*.js',
'test/ngMobile/directive/*.js'
],
'jstdPerf': [
@@ -196,36 +210,30 @@ angularFiles = {
]
};
// Execute only in slim-jim
if (typeof JASMINE_ADAPTER !== 'undefined') {
// Testacular config
var mergedFiles = [];
angularFiles.jstd.forEach(function(file) {
// replace @ref
var match = file.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
if (!deps) {
console.log('No dependency:' + file)
if (exports) {
exports.files = angularFiles
exports.mergeFiles = function mergeFiles() {
var files = [];
[].splice.call(arguments, 0).forEach(function(file) {
if (file.match(/karma/)) {
files.push(file);
} else {
angularFiles[file].forEach(function(f) {
// replace @ref
var match = f.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
files = files.concat(deps);
} else {
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
files.push(f);
}
}
});
}
mergedFiles = mergedFiles.concat(deps);
} else {
mergedFiles.push(file);
}
});
});
files = [JASMINE, JASMINE_ADAPTER];
mergedFiles.forEach(function(file){
if (/jstd|jasmine/.test(file)) return;
files.push(file);
});
exclude = angularFiles.jstdExclude;
autoWatch = true;
autoWatchInterval = 1;
logLevel = LOG_INFO;
logColors = true;
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
+27 -22
View File
@@ -36,16 +36,15 @@ var parseRawCommit = function(raw) {
msg.breaks = [];
lines.forEach(function(line) {
match = line.match(/Closes\s#(\d+)/);
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
if (match) msg.closes.push(parseInt(match[1]));
});
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
if (match) {
console.log('found!!!')
msg.breaks.push(match[1]);
msg.breaking = match[1];
}
msg.body = lines.join('\n');
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
@@ -88,7 +87,8 @@ var currentDate = function() {
};
var printSection = function(stream, title, section) {
var printSection = function(stream, title, section, printCommitLinks) {
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
var components = Object.getOwnPropertyNames(section).sort();
if (!components.length) return;
@@ -109,11 +109,15 @@ var printSection = function(stream, title, section) {
}
section[name].forEach(function(commit) {
stream.write(util.format('%s %s (%s', prefix, commit.subject, linkToCommit(commit.hash)));
if (commit.closes.length) {
stream.write(', closes ' + commit.closes.map(linkToIssue).join(', '));
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');
});
});
@@ -122,7 +126,7 @@ var printSection = function(stream, title, section) {
var readGitLog = function(grep, from) {
var deffered = q.defer();
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) {
@@ -133,10 +137,10 @@ var readGitLog = function(grep, from) {
if (commit) commits.push(commit);
});
deffered.resolve(commits);
deferred.resolve(commits);
});
return deffered.promise;
return deferred.promise;
};
@@ -158,29 +162,30 @@ var writeChangelog = function(stream, commits, version) {
section[component].push(commit);
}
commit.breaks.forEach(function(breakMsg) {
sections.breaks[EMPTY_COMPONENT].push({
subject: breakMsg,
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);
printSection(stream, 'Breaking Changes', sections.breaks, false);
}
var getPreviousTag = function() {
var deffered = q.defer();
var deferred = q.defer();
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
if (code) deffered.reject('Cannot get the previous tag.');
else deffered.resolve(stdout.replace('\n', ''));
if (code) deferred.reject('Cannot get the previous tag.');
else deferred.resolve(stdout.replace('\n', ''));
});
return deffered.promise;
return deferred.promise;
};
+3 -3
View File
@@ -34,10 +34,10 @@ describe('changelog.js', function() {
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
'feat(ng-list): Allow custom separator\n' +
'bla bla bla\n\n' +
'Breaks first breaking change\nsomething else\n' +
'Breaks another breaking change\n');
'BREAKING CHANGE: first breaking change\nsomething else\n' +
'another line with more info\n');
expect(msg.breaks).toEqual(['first breaking change', 'another breaking change']);
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
});
});
});
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash
rake compile
grunt minify
gzip -c < build/angular.min.js > build/angular.min.js.gzip
ls -l build/angular.min.*
+50
View File
@@ -0,0 +1,50 @@
describe('Docs Syntax', function() {
beforeEach(module('bootstrap'));
describe('syntax', function() {
var id, element, document;
beforeEach(inject(function($compile, $rootScope, $document) {
document = $document[0];
//create the HTML elements missing in IE8 for this directive
document.createElement('nav');
element = angular.element(
'<div>' +
'<pre syntax ' +
'syntax-github="gh-url" ' +
'syntax-plunkr="pl-url" ' +
'syntax-fiddle="jf-url">' +
'</pre>' +
'</div>'
);
$compile(element)($rootScope);
$rootScope.$digest();
element = element[0];
document.body.appendChild(element);
}));
it("should properly prepare a github link in the page", function() {
var github = element.querySelector('.syntax-github');
expect(github.innerHTML).toMatch(/View on Github/i);
expect(github.getAttribute('href')).toBe('gh-url');
});
it("should properly prepare a plunkr link in the page", function() {
var plunkr = element.querySelector('.syntax-plunkr');
expect(plunkr.innerHTML).toMatch(/View on Plunkr/i);
expect(plunkr.getAttribute('href')).toBe('pl-url');
});
it("should properly prepare a jsfiddle link in the page", function() {
var jsfiddle = element.querySelector('.syntax-jsfiddle');
expect(jsfiddle.innerHTML).toMatch(/View on JSFiddle/i);
expect(jsfiddle.getAttribute('href')).toBe('jf-url');
});
});
});
@@ -222,6 +222,6 @@
function isActuallyNaN(val) {
return (typeof val === 'number') && isNaN(val);
}
};
}
})(window, document);
@@ -4,10 +4,10 @@ var directive = {};
var service = { value: {} };
var DEPENDENCIES = {
'angular.js': 'http://code.angularjs.org/angular-' + angular.version.full + '.min.js',
'angular-resource.js': 'http://code.angularjs.org/angular-resource-' + angular.version.full + '.min.js',
'angular-sanitize.js': 'http://code.angularjs.org/angular-sanitize-' + angular.version.full + '.min.js',
'angular-cookies.js': 'http://code.angularjs.org/angular-cookies-' + angular.version.full + '.min.js'
'angular.js': 'http://code.angularjs.org/' + angular.version.full + '/angular.min.js',
'angular-resource.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-resource.min.js',
'angular-sanitize.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-sanitize.min.js',
'angular-cookies.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-cookies.min.js'
};
@@ -179,7 +179,8 @@ directive.ngEvalJavascript = ['getEmbeddedTemplate', function(getEmbeddedTemplat
}];
directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', function($templateCache, $browser, docsRootScope, $location) {
directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', '$sniffer',
function($templateCache, $browser, docsRootScope, $location, $sniffer) {
return {
terminal: true,
link: function(scope, element, attrs) {
@@ -189,11 +190,17 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
$provide.value('$templateCache', $templateCache);
$provide.value('$anchorScroll', angular.noop);
$provide.value('$browser', $browser);
$provide.value('$sniffer', $sniffer);
$provide.provider('$location', function() {
this.$get = function() { return $location; };
this.$get = ['$rootScope', function($rootScope) {
docsRootScope.$on('$locationChangeSuccess', function(event, oldUrl, newUrl) {
$rootScope.$broadcast('$locationChangeSuccess', oldUrl, newUrl);
});
return $location;
}];
this.html5Mode = angular.noop;
});
$provide.decorator('$defer', ['$rootScope', '$delegate', function($rootScope, $delegate) {
$provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) {
return angular.extend(function(fn, delay) {
if (delay && delay > 50) {
return setTimeout(function() {
@@ -205,7 +212,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
}, $delegate);
}]);
$provide.decorator('$rootScope', ['$delegate', function(embedRootScope) {
docsRootScope.$watch(function() {
docsRootScope.$watch(function embedRootScopeDigestWatch() {
embedRootScope.$digest();
});
return embedRootScope;
@@ -218,6 +225,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
event.preventDefault();
}
});
angular.bootstrap(element, modules);
}
};
@@ -9,7 +9,7 @@ directive.dropdownToggle =
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch(function(){return $location.path();}, function() {
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
close && close();
});
@@ -48,6 +48,52 @@ directive.dropdownToggle =
};
}];
directive.syntax = function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
function makeLink(type, text, link, icon) {
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
'<span class="' + icon + '"></span> ' + text +
'</a>';
};
var html = '';
var types = {
'github' : {
text : 'View on Github',
key : 'syntaxGithub',
icon : 'icon-github'
},
'plunkr' : {
text : 'View on Plunkr',
key : 'syntaxPlunkr',
icon : 'icon-arrow-down'
},
'jsfiddle' : {
text : 'View on JSFiddle',
key : 'syntaxFiddle',
icon : 'icon-cloud'
}
};
for(var type in types) {
var data = types[type];
var link = attrs[data.key];
if(link) {
html += makeLink(type, data.text, link, data.icon);
}
};
var nav = document.createElement('nav');
nav.className = 'syntax-links';
nav.innerHTML = html;
var node = element[0];
var par = node.parentNode;
par.insertBefore(nav, node);
}
}
}
directive.tabbable = function() {
return {
@@ -143,6 +189,14 @@ directive.tabbable = function() {
};
};
directive.table = function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
element[0].className = 'table table-bordered table-striped code-table';
}
};
};
directive.tabPane = function() {
return {
@@ -643,7 +643,7 @@ var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[
* recognized.
*
* Shortcut is an optional string of characters, any of which, if the first
* character, gurantee that this pattern and only this pattern matches.
* character, guarantee that this pattern and only this pattern matches.
*
* @param {Array} shortcutStylePatterns patterns that always start with
* a known character. Must have a shortcut string.
+2 -2
View File
@@ -2,6 +2,6 @@
@name API Reference
@description
Use the API Refference 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 recomend the
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}.
@@ -1,5 +1,5 @@
@ngdoc overview
@name angular.module.ng
@name ng
@description
The `ng` is an angular module which contains all of the core angular services.
+12 -12
View File
@@ -3,7 +3,7 @@
@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}
@@ -12,22 +12,22 @@ to retrieve Buzz activity and comments.
<doc:example>
<doc:source>
<script>
BuzzController.$inject = ['$resource'];
function BuzzController($resource) {
this.userId = 'googlebuzz';
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: '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>
+6 -6
View File
@@ -5,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
@@ -35,8 +35,8 @@ In this example we have a simple app which consist of two screens:
angular.module('deepLinking', ['ngSanitize'])
.config(function($routeProvider) {
$routeProvider.
when("/welcome", {template:'welcome.html', controller:WelcomeCntl}).
when("/settings", {template:'settings.html', controller:SettingsCntl});
when("/welcome", {templateUrl:'welcome.html', controller:WelcomeCntl}).
when("/settings", {templateUrl:'settings.html', controller:SettingsCntl});
});
AppCntl.$inject = ['$scope', '$route']
@@ -141,11 +141,11 @@ In this example we have a simple app which consist of two screens:
# Things to notice
* Routes are defined in the `AppCntl` class. The initialization of the controller causes the
initialization of the {@link api/angular.module.ng.$route $route} service with the proper URL
initialization of the {@link api/ng.$route $route} service with the proper URL
routes.
* The {@link api/angular.module.ng.$route $route} service then watches the URL and instantiates the
* The {@link api/ng.$route $route} service then watches the URL and instantiates the
appropriate controller when the URL changes.
* The {@link api/angular.module.ng.$compileProvider.directive.ngView ngView} widget loads the
* 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.
+9 -10
View File
@@ -2,7 +2,7 @@
@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,7 +11,7 @@ allow a user to enter data.
<doc:source>
<script>
function FormController($scope) {
$scope.user = {
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'}]
@@ -20,12 +20,12 @@ allow a user to enter data.
$scope.zip = /^\d\d\d\d\d$/;
$scope.addContact = function() {
$scope.user.contacts.push({type:'email', value:''});
user.contacts.push({type:'email', value:''});
};
$scope.removeContact = function(contact) {
for (var i = 0, ii = this.user.contacts.length; i < ii; i++) {
if (contact === this.user.contacts[i]) {
for (var i = 0, ii = user.contacts.length; i < ii; i++) {
if (contact === user.contacts[i]) {
$scope.user.contacts.splice(i, 1);
}
}
@@ -102,14 +102,13 @@ allow a user to enter data.
# Things to notice
* The user data model is initialized {@link api/angular.module.ng.$compileProvider.directive.ngController controller} and is
available in the {@link api/angular.module.ng.$rootScope.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.module.ng.$compileProvider.directive.input input directives} simply refer
* The {@link api/ng.directive:input input directives} simply refer
to the model and are data-bound.
* The inputs {@link guide/dev_guide.forms validate}. (Try leaving them blank or entering non digits
in the zip field)
* 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.
+4 -4
View File
@@ -28,11 +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.module.ng.$compileProvider.directive.input input widget} which is
* 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.
* 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.module.ng.$rootScope.Scope scope}.
* 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 -4
View File
@@ -2,7 +2,7 @@
@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
@@ -44,8 +44,8 @@ allowing you to send links to specific screens in your app.
# Services
{@link api/angular.module.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
{@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).
@@ -55,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.
+9 -8
View File
@@ -2,13 +2,14 @@
@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>
@@ -84,8 +85,8 @@ no connection between the controller and the view.
Next Player: {{nextMove}}
<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"
<tr ng-repeat="row in board track by $index" style="height:15px;">
<td ng-repeat="cell in row track by $index" ng-style="cellStyle"
ng-click="dropPiece($parent.$index, $index)">{{cell}}</td>
</tr>
</table>
@@ -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.module.ng.$rootScope.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.
+111
View File
@@ -0,0 +1,111 @@
@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 or when the `angular.js` script is
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
for the {@link api/ng.directive:ngApp `ng-app`} directive which designates your application root.
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. The example is equivalent to using the {@link
api/ng.directive:ngApp ng-app} directive.
<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);
});
</script>
</body>
</html>
</pre>
This is the sequence that your code should follow:
1. After the page and all of the code is loaded, find the root of the HTML template, which is
typically the root of the document.
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the template into an
executable, bi-directionally bound application.
+143
View File
@@ -0,0 +1,143 @@
@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 element 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 center is found, and that this
center needs to be aligned with the text's center. Simply add `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 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 extension 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 {@link api/ng.directive:ngRepeat
`ng-repeat`} clone DOM elements once for each item in 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 in
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, or a class name. 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,54 +0,0 @@
@ngdoc overview
@name Developer Guide: Initializing Angular: Automatic Initialization
@description
For Angular to manage the DOM for your application, it needs to compile some or all of an HTML page. Angular does this initialization automatically when you load the angular.js script into your page and insert an `ngApp` directive (attribute) into one of the page's elements. For example, we can tell Angular to initialize the entire document:
<pre>
<!doctype html>
<html ng-app>
<head>
<script src="angular.js"></script>
</head>
<body>
I can add: {{ 1+2 }}.
</body>
</html>
</pre>
You can also tell Angular to manage only a portion of a page. You would want to do this if you are using some other framework to manage other parts of the page. You do this by placing the `ngApp` directive on one or more container elements in the document. For example:
<pre>
<div ng-app>
I can add: {{ 1+2 }}
</div>
</pre>
You can also ask `ngApp` to load additional {@link api/angular.module modules} containing services, directives or filers that you'll use on the page.
<pre>
<div ng-app="AwesomeModule">
...
</div>
</pre
From a high-level, here's what Angular does during the initialization process:
1. The browser loads the page, and then runs the Angular script. Angular then waits for the
`DOMContentLoaded` (or 'Load') event to attempt to initialize.
2. Angular looks for the `ngApp` directive. If found it compilies the DOM element containing `ngApp` and its children.
3. Angular creates a global variable `angular` and binds all Angular APIs to this object's fields.
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.bootstrap Initializing Angular}
* {@link dev_guide.bootstrap.manual_bootstrap Manual Initialization}
## Related API
{@link api/angular.module.ng.$compile Compiler API}
@@ -1,49 +0,0 @@
@ngdoc overview
@name Developer Guide: Initializing Angular: Manual Initialization
@description
In the vast majority of cases you'll want to let Angular handle initialization automatically.
If, however, you need to delay Angular from managing the page right after the DOMContentLoaded
event fires, you'll need to control this initialization manually.
To initialize Angular -- after you've done your own special-purpose initialization -- just call
the {@link api/angular.bootstrap bootstrap()} function with the HTML container node that you want
Angular to manage. In automatic initialization you'd do this by adding the `ngApp` attribute to
the same node. Now, you won't use `ngApp` anywhere in your document.
To show the contrast of manual vs. automatic initialization, this automatic method:
<pre>
<!doctype html>
<html ng-app>
<head>
<script src="http://code.angularjs.org/angular.js"></script>
...
</pre
is the same as this manual method:
<pre>
<!doctype html>
<html>
<head>
<script src="http://code.angularjs.org/angular.js"></script>
<script>
angular.element(document).ready(function() {
angular.bootstrap(document);
});
</script>
</head>
...
</pre>
## 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.module.ng.$compile Compiler API}
@@ -1,65 +0,0 @@
@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 (`ngApp`)
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 ng-app>
<head>
...
</head>
<body>
...
<script src="angular.js">
</body>
</pre>
## Specifying the Angular Namespace
<html xmlns:ng="http://angularjs.org">
You need to add the Angular namespace declaration if you use `ng:something` style of declaring
Angular directives and you write your templates as XHTML. Or when you are targeting Internet
Explorer older than version 9 (because older versions of IE do not render namespace
properly for either HTML or XHTML). For more info please read {@link ie Internet Explorer
Compatibility} doc.
## Creating Your Own Namespaces
When you are ready to define your own {@link guide/directive
directive}, you may chose to create your own namespace in addition to specifying the Angular
namespace. You use your own namespace to form the fully qualified name for directives that you
create.
For example, you could map the alias `my` to your domain, and create a directive called `my:directive`.
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,24 +0,0 @@
@ngdoc overview
@name Developer Guide: Angular HTML Compiler
@description
The core of Angular is its HTML compiler. The compiler processes Angular
{@link guide/directive directives} allowing them 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.testing_dom_element Testing a New DOM Element}
## Related API
* {@link api/angular.module.ng.$compile Angular Compiler API}
* {@link guide/directive Directives API}
@@ -1,16 +0,0 @@
@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}
## Related API
* {@link api/angular.module.ng.$compile $compile()}
@@ -1,34 +0,0 @@
@ngdoc overview
@name Developer Guide: Angular HTML Compiler: Understanding How the Compiler Works
@description
The {@link api/angular.module.ng.$compile compiler} is responsible for applying
{@link guide/directive directives} to the HTML. The directives
extend the behavior of HTML elements and can effect the DOM structure, presentation, and behavior.
This allows Angular to teach the browser new tricks.
The compilation starts at the root element and proceeds in a depth-first order. As the compiler
visits each node it collects the directives, orders them by priority and executes their compile
function. The result of the compilation process is a linking function. The linking function
can be used on the template clones to quickly bind the directives with the scope.
The result of the compilation process is a live view. We say 'live' since any changes to the
model attached to the {@link api/angular.module.ng.$rootScope.Scope scope} are reflected in the view,
and any changes in the view are reflected in the scope. This makes the scope the 'single source of
truth'.
Since directives allow attachment of behavior to the HTML, the angular philosophy is to use the
HTML as Domain Specific Language (DSL) when building an application. For example it may be useful
to declare `TabPanel` directive, or `KeyboardShortcut` directive when for an application.
For details on how directives are created see {@link guide/directive
directives}
## Related Topics
* {@link dev_guide.compiler Angular HTML Compiler}
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
## Related API
* {@link api/angular.module.ng.$compile $compile()}
-32
View File
@@ -1,32 +0,0 @@
@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.module.ng Service API}
* {@link api/angular.injector Angular Injector API}
@@ -1,193 +0,0 @@
@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.
Services are objects that handle common tasks in web applications. Angular provides several {@link
api/angular.module.ng built-in services}, and you can create your
{@link dev_guide.services.creating_services 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.module.ng 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. Module "phonecat" is created and all the service providers are registered with this module.
(the "ng" module is created by Angular behind the scenes as well)
2. `ngApp` triggers bootstrap sequence on given element, during which angular creates injector,
loads "phonecat" and "ng" modules and compiles the template.
3. The `ngController` directive implicitly creates a new child scope and instantiates
`PhoneListCtrl` controller.
4. Injector identifies the `$http` service as `PhoneListCtrl` controller's only dependency.
5. Injector checks its instances cache whether the `$http` service has already been instantiated.
If not uses the provider from the available modules to construct it.
6. Injector provides the instance of `$http` service to the `PhoneListCtrl` controller constructor.
## How Scope Relates to DI
The root scope of the application is just a service that is available for injection to any part of
the application under the service name "$rootScope".
## 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.module('module1', [], function($provide) {
$provide.factory('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.
### Dependency inference and variable name shadowing
During inference, the injector considers argument names with leading and trailing underscores to be
equivivalent to the name without these underscores. For example `_fooSvc_` argument name is treated
as if it was `fooSvc`, this is useful especially in tests where variable name shadowing can cause
some friction. This is best illustrated on examples:
When testing a service, it's common to need a reference to it in every single test. This can be
done in jasmine with DI inference like this:
<pre>
describe('fooSvc', function() {
it('should do this thing', inject(function(fooSvc) {
//test fooSvc
}));
it('should do that thing', inject(function(fooSvc) {
//test fooSvc
}));
// more its
});
</pre>
... but having to inject the service over and over gets easily tiresome.
It's likely better to rewrite these tests with a use of jasmine's `beforeEach`:
<pre>
describe('fooSvc', function() {
var fooSvc;
beforeEach(inject(function(fooSvc) {
fooSvc = fooSvc; // DOESN'T WORK! outer fooSvc is being shadowed
}));
it('should do this thing', function() {
//test fooSvc
});
it('should do that thing', function() {
//test fooSvc
});
// more its
});
</pre>
This obviously won't work because `fooSvc` variable in the describe block is being shadowed by the
`fooSvc` argument of the beforeEach function. So we have to resort to alternative solutions, like
for example use of array notation to annotate the beforeEach fn:
<pre>
describe('fooSvc', function() {
var fooSvc;
beforeEach(inject(['fooSvc', function(fooSvc_) {
fooSvc = fooSvc_;
}]));
it('should do this thing', function() {
//test fooSvc
});
it('should do that thing', function() {
//test fooSvc
});
});
</pre>
That's better, but it's still annoying, especially if you have many services to inject.
To resolve this shadowing problem, the injector considers `_fooSvc_` argument names equal to
`fooSvc`, so the test can be rewritten like this:
<pre>
describe('fooSvc', function() {
var fooSvc;
beforeEach(inject(function(_fooSvc_) {
fooSvc = _fooSvc_;
}));
it('should do this thing', function() {
//test fooSvc
});
it('should do that thing', function() {
//test fooSvc
});
// more its
});
</pre>
## Related Topics
* {@link dev_guide.services Angular Services}
## Related API
* {@link api/angular.module.ng Services API}
@@ -1,52 +0,0 @@
@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($location){
// do stuff with the $location service
}
MyController.$inject = ['$location'];
</pre>
In this example, the `MyController` constructor function takes one argument, the {@link
api/angular.module.ng.$location $location} service. Angular is then responsible for supplying the
instance of `$location` to the controller when the constructor is instantiated. There are two ways
to cause controller instantiation by configuring routes with the `$location` service, or by
referencing the controller from the HTML template, as follows:
<pre>
<!doctype html>
<html ng-controller="MyController" ng-app>
<script src="http://code.angularjs.org/angular.min.js"></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 = ['$location'];
</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}
+134 -8
View File
@@ -11,7 +11,7 @@ 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
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
@@ -78,26 +78,27 @@ Returns the window.location.search of the currently loaded page in the test fram
Returns the window.location.hash (without `#`) of the currently loaded page in the test frame.
## browser().location().url()
Returns the {@link api/angular.module.ng.$location $location.url()} of the currently loaded page in
Returns the {@link api/ng.$location $location.url()} of the currently loaded page in
the test frame.
## browser().location().path()
Returns the {@link api/angular.module.ng.$location $location.path()} of the currently loaded page in
Returns the {@link api/ng.$location $location.path()} of the currently loaded page in
the test frame.
## browser().location().search()
Returns the {@link api/angular.module.ng.$location $location.search()} of the currently loaded page
Returns the {@link api/ng.$location $location.search()} of the currently loaded page
in the test frame.
## browser().location().hash()
Returns the {@link api/angular.module.ng.$location $location.hash()} of the currently loaded page in
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')`
`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`.
@@ -122,7 +123,7 @@ Returns the current value of an input field with the given `name`.
## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
used for test ouput.
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
@@ -175,4 +176,129 @@ Executes the `method` passing in `key` and `value` on the element matching the g
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 do it.
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 structure 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>
@@ -1,245 +0,0 @@
@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>
<script>
function Cntl2($scope) {
$scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
this.exprs.push(expr);
};
$scope.removeExp = function(index) {
this.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>
# 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>
<script>
function Cntl1($window, $scope){
$scope.name = 'World';
$scope.greet = function() {
($window.mockWindow || $window).alert('Hello ' + this.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.
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.module.ng.$filter.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.module.ng.$filter.filter()`. You can
call it from JavaScript.
Extensions: You can further extend the expression vocabulary by adding new methods to
`angular.module.ng.$filter` 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 ng-model="searchText"/>
<table class="example3">
<thead>
<tr><th>Name</th><th>Phone</th><tr>
</thead>
<tbody>
<tr ng-repeat="friend in friends | filter:searchText">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
</tr>
</tbody>
</table>
</doc:source>
<doc:scenario>
it('should filter the list', function() {
var tr = using('table.example3 tbody').repeater('tr');
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.module.ng.$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.templates.filters Understanding Angular Filters}
## Related API
* {@link api/angular.module.ng.$compile Angular Compiler API}
+3 -3
View File
@@ -3,16 +3,16 @@
@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
@@ -2,11 +2,8 @@
@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.module.ng.$rootScope.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:
@@ -15,10 +12,10 @@ 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.
@@ -30,15 +27,29 @@ function GreetingCtrl($scope) {
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
**NOTE**: Many of the examples in the documentation show the creation of functions
in the global scope. This is only for demonstration purposes - in a real
application you should use the `.controller` method of your Angular module for
your application as follows:
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
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 are available in the template/view, and can be invoked via angular expressions
and `ng` event handler directives (e.g. {@link api/angular.module.ng.$compileProvider.directive.ngClick ngClick}).
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
# Using Controllers Correctly
@@ -47,7 +58,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:
@@ -55,22 +66,21 @@ 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
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 dev_guide.forms angular form controls} instead.
- 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
- To run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
services} instead.
- Instantiate or manage the life-cycle of other components (for example, to create service
- To instantiate or manage 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.module.ng.$rootScope.Scope#$new
scope.$new} api or implicitly via the {@link api/angular.module.ng.$compileProvider.directive.ngController ngController
directive} or {@link api/angular.module.ng.$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
@@ -157,15 +167,16 @@ input box) in the second button.
## Controller Inheritance Example
Controller inheritance in angular is based on {@link api/angular.module.ng.$rootScope.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">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
<p>Good {{timeOfDay}}, {{name}}!</p>
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
</div>
</body>
function MainCtrl($scope) {
@@ -197,7 +208,7 @@ 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.
@@ -241,8 +252,8 @@ describe('myController function', function() {
</pre>
If you need to test a nested controller one needs to create the same scope hierarchy
in your test as exist in the DOM.
If you need to test a nested controller you need to create the same scope hierarchy
in your test that exists in the DOM.
<pre>
describe('state', function() {
@@ -253,7 +264,7 @@ describe('state', function() {
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
childScope = mainScope.$new();
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
babyScope = $rootScope.$new();
babyScope = childCtrl.$new();
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
}));
@@ -2,16 +2,16 @@
@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
@@ -26,11 +26,11 @@ occurs in controllers:
$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='ball'}}">Click me</button>
* Use {@link api/angular.module.ng.$compileProvider.directive.ngInit ngInit 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' ">
@@ -45,18 +45,18 @@ when processing the following template constructs:
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.module.ng.$compileProvider.directive.ngRepeat ngRepeater}:
* An iterator declaration in {@link api/ng.directive:ngRepeat ngRepeater}:
<p ng-repeat="phone in phones"></p>
The code above creates one child scope for each item in the "phones" array and creates a "phone"
object (model) on each of these scopes with its value set to the value of "phone" in the array.
In angular, a JavaScript object stops being a model when:
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:
@@ -2,15 +2,15 @@
@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.module.ng.$compileProvider.directive.ngController
ngController} and {@link api/angular.module.ng.$compileProvider.directive.ngView ngView}, 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.
-236
View File
@@ -1,236 +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>
<script>
function InvoiceCntl($scope) {
$scope.qty = 1;
$scope.cost = 19.95;
}
</script>
<div ng-controller="InvoiceCntl">
<b>Invoice:</b>
<br />
<br />
<table>
<tr><td> </td><td> </td>
<tr><td>Quantity</td><td>Cost</td></tr>
<tr>
<td><input type="integer" min="0" ng-model="qty" required ></td>
<td><input type="number" ng-model="cost" required ></td>
</tr>
</table>
<hr />
<b>Total:</b> {{qty * cost | currency}}
</div>
</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 specify that this is an angular application with the `ngApp` directive.
The `ngApp' will cause the angular to {@link dev_guide.bootstrap auto initialize} your application.
<html ng-app>
We load the angular using the `<script>` tag:
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
From the `ngModel` attribute of the `<input>` tags, angular automatically sets up two-way data
binding, and we also demonstrate some easy input validation:
Quantity: <input type="integer" min="0" ng-model="qty" required >
Cost: <input type="number" ng-model="cost" required >
These input widgets look normal enough, but consider these points:
* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to
variables of the same name. Think of those variables as the "Model" component of the
Model-View-Controller design pattern.
* Note the angular/HTML widget, {@link api/angular.module.ng.$compileProvider.directive.input input}.
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 widgets make it easier to implement field validation 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 binding markup, a shortcut for
displaying data to the user. The expression within curly braces is monitored and its evaluated value
is updated into the view by angular's template compiler. Alternatively, one could use angular's
{@link api/angular.module.ng.$compileProvider.directive.ngBind ngBind}) directive. 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,230 +0,0 @@
@ngdoc overview
@name Developer Guide: Scopes: Scope Internals
@description
## What is a scope?
A scope is an execution context for {@link dev_guide.expressions expressions}. You can think of a
scope as a JavaScript object that has an extra set of APIs for registering change listeners and for
managing its own life cycle. In Angular's implementation of the model-view-controller design
pattern, a scope's properties comprise both the model and the controller methods.
### Scope characteristics
- Scopes provide APIs ({@link api/angular.module.ng.$rootScope.Scope#$watch $watch}) to observe model mutations.
- Scopes provide APIs ({@link api/angular.module.ng.$rootScope.Scope#$apply $apply}) to propagate any model changes
through the system into the view from outside of the "Angular realm" (controllers, services,
Angular event handlers).
- Scopes can be nested to isolate application components while providing access to shared model
properties. A scope (prototypically) inherits properties from its parent scope.
- In some parts of the system (such as controllers, services and directives), the scope is made
available as `this` within the given context. (Note: This api will change before 1.0 is released.)
### Root scope
Every application has a root scope, which is the ancestor of all other scopes.
### What is scope used for?
{@link dev_guide.expressions Expressions} in the view are {@link api/angular.module.ng.$rootScope.Scope#$eval evaluated}
against the current scope. When HTML DOM elements are attached to a scope, expressions in those
elements are evaluated against the attached scope.
There are two kinds of expressions:
- Binding expressions, which are observations of property changes. Property changes are reflected
in the view during the {@link api/angular.module.ng.$rootScope.Scope#$digest digest cycle}.
- Action expressions, which are expressions with side effects. Typically, the side effects cause
execution of a method in a controller in response to a user action, such as clicking on a button.
### Scope inheritance
A scope (prototypically) inherits properties from its parent scope. Since a given property may not
reside on a child scope, if a property read does not find the property on a scope, the read will
recursively check the parent scope, grandparent scope, etc. all the way to the root scope before
defaulting to undefined.
{@link guide/directive directives} associated with elements
(ngController, ngRepeat, ngInclude, etc.) create new child scopes that inherit properties from
the current parent scope. Any code in Angular is free to create a new scope. Whether or not your
code does so is an implementation detail of the directive, that is, you can decide when or if this
happens. Inheritance typically mimics HTML DOM element nesting, but does not do so with the same
granularity.
A property write will always write to the current scope. This means that a write can hide a parent
property within the scope it writes to, as shown in the following example.
<pre>
it('should inherit properties', inject(function($rootScope)) {
var root = $rootScope;
var child = root.$new();
root.name = 'angular';
expect(child.name).toEqual('angular');
expect(root.name).toEqual('angular');
child.name = 'super-heroic framework';
expect(child.name).toEqual('super-heroic framework');
expect(root.name).toEqual('angular');
});
</pre>
### Scope life cycle
1. **Creation**
* The root scope is created by the {@link api/angular.module.ng.$rootScope $rootScope} service.
* To create a child scopes, you should call {@link api/angular.module.ng.$rootScope.Scope#$new parentScope.$new()}.
2. **Watcher registration**
Watcher registration can happen at any time and on any scope (root or child) via {@link
api/angular.module.ng.$rootScope.Scope#$watch scope.$watch()} API.
3. **Model mutation**
For mutations to be properly observed, you should make them only within the execution of the
function passed into {@link api/angular.module.ng.$rootScope.Scope#$apply scope.$apply()} call. (Angular apis do this
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers, or
asynchronous work with {@link api/angular.module.ng.$http $http} or {@link api/angular.module.ng.$defer
$defer} services.
4. **Mutation observation**
At the end of each `$apply` call {@link api/angular.module.ng.$rootScope.Scope#$digest $digest} cycle is started on
the root scope, which then propagates throughout all child scopes.
During the `$digest` cycle, all `$watch-ers` expressions or functions are checked for model
mutation and if a mutation is detected, the `$watch-er` listener is called.
5. **Scope destruction**
When child scopes are no longer needed, it is the responsibility of the child scope creator to
destroy them via {@link api/angular.module.ng.$rootScope.Scope#$destroy scope.$destroy()} API. This will stop
propagation of `$digest` calls into the child scope and allow for memory used by the child scope
models to be reclaimed by the garbage collector.
The root scope can't be destroyed via the `$destroy` API. Instead, it is enough to remove all
references from your application to the scope object and garbage collector will do its magic.
## Scopes in Angular applications
To understand how Angular applications work, you need to understand how scopes work within an
application. This section describes the typical life cycle of an application so you can see how
scopes come into play throughout and get a sense of their interactions.
### How scopes interact in applications
1. At application compile time, a root scope is created and is attached to the root `<HTML>` DOM
element.
2. During the compilation phase, the {@link dev_guide.compiler compiler} matches {@link
guide/directive directives} against the DOM template. The directives
usually fall into one of two categories:
- Observing {@link guide/directive directives}, such as double-curly
expressions `{{expression}}`, register listeners using the {@link
api/angular.module.ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs to
be notified whenever the expression changes so that it can update the view.
- Listener directives, such as {@link api/angular.module.ng.$compileProvider.directive.ngClick
ngClick}, register a listener with the DOM. When the DOM listener fires, the directive executes
the associated expression and updates the view using the {@link
api/angular.module.ng.$rootScope.Scope#$apply $apply()} method.
3. When an external event (such as a user action, timer or XHR) is received, the associated {@link
dev_guide.expressions expression} must be applied to the scope through the {@link
api/angular.module.ng.$rootScope.Scope#$apply $apply()} method so that all listeners are updated correctly.
### Directives that create scopes
In most cases, {@link guide/directive directives} and scopes interact but do not create new
instances of scope. However, some directives, such as {@link api/angular.module.ng.$compileProvider.directive.ngController
ngController} and {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}, create new child scopes using
the {@link api/angular.module.ng.$rootScope.Scope#$new $new()} method and then attach the child scope to the
corresponding DOM element. You can retrieve a scope for any DOM element by using an
`angular.element(aDomElement).scope()` method call.)
### Controllers and scopes
Scopes and controllers interact with each other in the following situations:
- Controllers use scopes to expose controller methods to templates (see {@link
api/angular.module.ng.$compileProvider.directive.ngController ngController}).
- Controllers define methods (behavior) that can mutate the model (properties on the scope).
- Controllers may register {@link api/angular.module.ng.$rootScope.Scope#$watch watches} on the model. These watches
execute immediately after the controller behavior executes, but before the DOM gets updated.
See the {@link dev_guide.mvc.understanding_controller controller docs} for more information.
### Updating scope properties
You can update a scope by calling its {@link api/angular.module.ng.$rootScope.Scope#$apply $apply()} method with an
expression or a function as the function argument. However it is typically not necessary to do this
explicitly. In most cases, angular intercepts all external events (such as user interactions, XHRs,
and timers) and wraps their callbacks into the `$apply()` method call on the scope object for you
at the right time. The only time you might need to call `$apply()` explicitly is when you create
your own custom asynchronous widget or service.
The reason it is unnecessary to call `$apply()` from within your controller functions when you use
built-in angular widgets and services is because your controllers are typically called from within
an `$apply()` call already.
When a user inputs data, angularized widgets invoke `$apply()` on the current scope and evaluate an
angular expression or execute a function on this scope. Afterwards `$apply` will trigger `$digest`
call on the root scope, to propagate your changes through the entire system, which results in
$watch-ers firing and view getting updated. Similarly, when a request to fetch data from a server
is made and the response comes back, the data is written into the model (scope) within an $apply,
which then pushes updates through to the view and any other dependents.
A widget that creates scopes (such as {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}) via `$new`,
doesn't need to worry about propagating the `$digest` call from the parent scope to child scopes.
This happens automatically.
## Scopes in unit-testing
You can create scopes, including the root scope, in tests by having the $rootScope injected into
your spec. This allows you to mimic the run-time environment and have full control over
the life cycle of the scope so that you can assert correct model transitions. Since these scopes
are created outside the normal compilation process, their life cycles must be managed by the test.
### Using scopes in unit-testing
The following example demonstrates how the scope life cycle needs to be manually triggered from
within the unit-tests.
<pre>
// example of a test
it('should trigger a watcher', inject(function($rootScope) {
var scope = $rootScope;
scope.$watch('name', function(name) {
scope.greeting = 'Hello ' + name + '!';
});
scope.name = 'angular';
// The watch does not fire yet since we have to manually trigger the digest phase.
expect(scope.greeting).toEqual(undefined);
// manually trigger digest phase from the test
scope.$digest();
expect(scope.greeting).toEqual('Hello Angular!');
}
</pre>
### Dependency injection in Tests
When you find it necessary to inject your own mocks in your tests, use a scope to override the
service instances, as shown in the following example.
<pre>
it('should allow override of providers', inject(
function($provide) {
$provide.value('$location', {mode:'I am a mock'});
},
function($location){
expect($location.mode).toBe('I am a mock');
}
)};
</pre>
## Related Topics
* {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
## Related API
* {@link api/angular.module.ng.$rootScope.Scope Angular Scope API}
-35
View File
@@ -1,35 +0,0 @@
@ngdoc overview
@name Developer Guide: Scopes
@description
An Angular scope is a JavaScript object with additional APIs useful for watching property changes,
Angular scope is the model in Model-View-Controller paradigm. Instances of scope serve as the
context within which all {@link dev_guide.expressions expressions} get evaluated.
You can think of Angular scope objects as the medium through which the model, view, and controller
communicate. Scopes are linked during the compilation process with the view. This linkage provides
the contexts in which Angular creates data-bindings between the model and the view.
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.module.ng.$rootScope.Scope#$watch $watch}, bindings created by
{@link api/angular.module.ng.$compileProvider.directive.ngBind ngBind}, or HTML input elements).
Angular scope objects:
* Link the model, controller and view template together.
* Provide the mechanism to watch for model changes ({@link api/angular.module.ng.$rootScope.Scope#$watch $watch}).
* Apply model changes to the system ({@link api/angular.module.ng.$rootScope.Scope#$apply $apply}).
* Provide the context in which expressions are evaluated ({@link api/angular.module.ng.$rootScope.Scope#$eval $eval}).
## Related Topics
* {@link dev_guide.scopes.understanding_scopes Understanding Scopes}
* {@link dev_guide.scopes.internals Scopes Internals}
## Related API
* {@link api/angular.module.ng.$rootScope.Scope Angular Scope API}
@@ -1,66 +0,0 @@
@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.module.ng.$compileProvider.directive.ngRepeat ngRepeat} 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.internals Scopes Internals}
## Related API
* {@link api/angular.module.ng.$rootScope.Scope Angular Scope API}
@@ -23,13 +23,13 @@ changes to $location are reflected into the browser address bar.
## Comparing $location to window.location
<table>
<table class="table">
<thead>
<tr>
<td class="empty-corner-lt"></td>
<td>window.location</td>
<td>$location service</td>
<th class="empty-corner-lt"></th>
<th>window.location</th>
<th>$location service</th>
</tr>
</thead>
@@ -73,10 +73,9 @@ Any time your application needs to react to a change in the current URL or if yo
the current URL in the browser.
## What does it not do?
Does not cause a full page reload when the browser URL is changed. To reload the page after
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
@@ -89,7 +88,7 @@ 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/angular.module.ng.$locationProvider $locationProvider} and set the parameters as follows:
{@link api/ng.$locationProvider $locationProvider} and set the parameters as follows:
- **html5Mode(mode)**: {boolean}<br />
@@ -99,7 +98,7 @@ To configure the `$location` service, retrieve the
- **hashPrefix(prefix)**: {string}<br />
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)<br />
default: `'!'`
default: `""`
### Example configuration
<pre>
@@ -133,12 +132,12 @@ current URL without creating a new browser history record you can call:
// or you can chain these as: $location.path('/someNewPath').replace();
</pre>
Note that the setters don't update `window.location` immediately. Instead, `$location` service is
aware of the {@link api/angular.module.ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location`
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 addition to the browser history. Once the browser is updated, the $location service
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.
@@ -165,13 +164,13 @@ facilitate the browser URL change and history management.
<img src="img/guide/hashbang_vs_regular_url.jpg">
<table>
<table class="table">
<thead>
<tr>
<td class="empty-corner-lt"></td>
<td>Hashbang mode</td>
<td>HTML5 mode</td>
<th class="empty-corner-lt"></th>
<th>Hashbang mode</th>
<th>HTML5 mode</th>
</tr>
</thead>
@@ -212,7 +211,7 @@ In this mode, `$location` uses Hashbang URLs in all browsers.
<pre>
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5mode = false;
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix = '!';
},
function($location) {
@@ -261,7 +260,7 @@ having to worry about whether the browser displaying your app supports the histo
<pre>
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5mode = true;
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix = '!';
},
function($location) {
@@ -304,7 +303,7 @@ history API or not; the `$location` service makes this transparent to you.
### Html link rewriting
When you use the history API mode, you will need different links in different browser, but all you
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,
@@ -331,11 +330,11 @@ 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 rill need to add the following
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 empty `_escaped_fragment_` parameter so that
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}.
@@ -489,11 +488,11 @@ In this examples we use `<base href="/base/index.html" />`
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/angular.module.ng.$window $window.location.href}.
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/angular.module.ng.$rootScope.Scope scope} life-cycle. When a URL changes in
`$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
@@ -513,7 +512,7 @@ hashPrefix.
# Testing with the $location service
When using `$location` service during testing, you are outside of the angular's {@link
api/angular.module.ng.$rootScope.Scope scope} life-cycle. This means it's your responsibility to call `scope.$apply()`.
api/ng.$rootScope.Scope scope} life-cycle. This means it's your responsibility to call `scope.$apply()`.
<pre>
describe('serviceUnderTest', function() {
@@ -543,95 +542,106 @@ then uses the information it obtains to compose hashbang URLs (such as
## Changes to your code
<table>
<tr class="head">
<td>Navigation inside the app</td>
<td>Change to</td>
</tr>
<table class="table">
<thead>
<tr class="head">
<th>Navigation inside the app</th>
<th>Change to</th>
</tr>
</thead>
<tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
<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>
<td>$location.path(path).search(search)</td>
</tr>
<tr>
<td>$location.hashPath = path</td>
<td>$location.path(path)</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>
<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 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.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>
<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 class="head">
<td>Read access</td>
<td>Change to</td>
</tr>
<tr>
<td>$location.hashPath</td>
<td>$location.path()</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.hashSearch</td>
<td>$location.search()</td>
</tr>
<tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
<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
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
/>$location.path() + $location.search()</td>
</tr>
</tr>
<tr>
<td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.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,
you will need to specify an extra property that has two watchers. For example:
<pre>
<!-- html -->
<input type="text" ng-model="locationPath" />
</pre>
<pre>
// js - controller
this.$watch('locationPath', function(path) {
$location.path(path);
});
this.$watch('$location.path()', function(path) {
scope.locationPath = path;
});
</pre>
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/angular.module.ng.$location $location API}
* {@link api/ng.$location $location API}
@@ -2,12 +2,12 @@
@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
with a module either via the {@link api/angular.module Module#factory api} or directly
via the {@link api/angular.module.AUTO.$provide $provide} api inside of module config function.
via the {@link api/AUTO.$provide $provide} api inside of module config function.
All angular services participate in {@link dev_guide.di dependency injection (DI)} by registering
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
@@ -18,7 +18,7 @@ testable.
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/angular.module.AUTO.$provide $provide} service in the module configuration
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:
@@ -48,9 +48,9 @@ create this instance when called.
# Dependencies
Services can not only be depended upon, but also have its own dependencies. These can be specified
as arguments of the factory function. {@link dev_guide.di.understanding_di Read more} about the DI
in Angular and the use of array notation and $inject property to make DI annotation
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
@@ -76,17 +76,17 @@ angular.module('myModule', [], function($provide) {
# Instantiating Angular Services
All services in Angular are instantiates services lazily, this means that a service will be created
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 lazy services unless they are requested directly or
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 the global state, it is possible to create multiple injectors, each with its own instance of a
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.
@@ -101,4 +101,4 @@ important.
## Related API
* {@link api/angular.module.ng Angular Service API}
* {@link api/ng Angular Service API}
@@ -115,4 +115,4 @@ dependencies with the `$inject` property.
## Related API
{@link api/angular.module.ng Angular Service API}
{@link api/ng Angular Service API}
@@ -39,8 +39,8 @@ function myModuleCfgFn($provide) {
</pre>
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:
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>
/**
@@ -50,7 +50,7 @@ provided by Angular's web framework:
* @param {*} message Message to be logged.
*/
function batchLogModule($provide){
$provide.factory('batchLog', ['$defer', '$log', function($defer, $log) {
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
var messageQueue = [];
function log() {
@@ -58,7 +58,7 @@ provided by Angular's web framework:
$log('batchLog messages: ', messageQueue);
messageQueue = [];
}
$defer(log, 50000);
$timeout(log, 50000);
}
// start periodic checking
@@ -76,7 +76,7 @@ provided by Angular's web framework:
$provide.factory('routeTemplateMonitor',
['$route', 'batchLog', '$rootScope',
function($route, batchLog, $rootScope) {
$rootScope.$on('$afterRouteChange', function() {
$rootScope.$on('$routeChangeSuccess', function() {
batchLog($route.current ? $route.current.template : null);
});
}]);
@@ -88,10 +88,10 @@ provided by Angular's web framework:
Things to notice in this example:
* The `batchLog` service depends on the built-in {@link api/angular.module.ng.$defer $defer} and
{@link api/angular.module.ng.$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.module.ng.$route
* The `routeTemplateMonitor` service depends on the built-in {@link api/ng.$route
$route} service as well as our custom `batchLog` service.
* 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
@@ -110,5 +110,5 @@ that the injector uses to determine which services and in which order to inject.
## Related API
* {@link api/angular.module.ng Angular Service API}
* {@link api/ng Angular Service API}
* {@link api/angular.injector Angular Injector API}
+4 -5
View File
@@ -2,10 +2,9 @@
@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
@@ -18,4 +17,4 @@ most often used with {@link dev_guide.di dependency injection}, also a key featu
## Related API
* {@link api/angular.module.ng Angular Service API}
* {@link api/ng Angular Service API}
@@ -2,7 +2,7 @@
@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.
@@ -55,8 +55,8 @@ 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.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.module.ng Angular Service API}
* {@link api/ng Angular Service API}
@@ -3,12 +3,12 @@
@description
Angular services are singletons that carry out specific tasks common to web apps, such as the
{@link api/angular.module.ng.$http $http 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
@@ -18,19 +18,19 @@ must explicitly define its dependencies by using the `$inject` property. For ex
myController.$inject = ['$location'];
The angular web framework provides a set of services for common operations. Like other core angular
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.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.testing_services Testing Angular Services}
## Related API
* {@link api/angular.module.ng Angular Service API}
* {@link api/ng Angular Service API}
* {@link api/angular.injector Injector API}
@@ -9,10 +9,10 @@ Angular sets these CSS classes. It is up to your application to provide useful s
* `ng-invalid`, `ng-valid`
- **Usage:** angular applies this class to an input widget element if that element's input does
notpass validation. (see {@link api/angular.module.ng.$compileProvider.directive.input input} directive).
not pass validation. (see {@link api/ng.directive:input input} directive).
* `ng-pristine`, `ng-dirty`
- **Usage:** angular {@link api/angular.module.ng.$compileProvider.directive.input input} directive applies `ng-pristine` class
- **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`.
@@ -20,4 +20,4 @@ Angular sets these CSS classes. It is up to your application to provide useful s
## Related Topics
* {@link dev_guide.templates Angular Templates}
* {@link dev_guide.forms Angular Forms}
* {@link forms Angular Forms}
@@ -2,8 +2,8 @@
@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 synchronization 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.
@@ -19,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
@@ -34,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}
@@ -2,16 +2,10 @@
@name Developer Guide: Templates: Filters: Creating Angular Filters
@description
Writing your own filter is very easy: just define a JavaScript function on the `angular.module.ng.$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.
@@ -59,8 +53,8 @@ text upper-case and assigns color.
## 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.module.ng.$filter Angular Filter API}
* {@link api/ng.$filter Angular Filter API}
@@ -2,9 +2,7 @@
@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:
@@ -12,10 +10,7 @@ displaying it to the user. You can pass expressions through a chain of filters l
name | uppercase
The expression evaluator simply passes the value of name to
{@link api/angular.module.ng.$filter.uppercase uppercase filter}.
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.
{@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.module.ng.$filter Angular Filter API}
* {@link api/ng.$filter Angular Filter API}
@@ -2,7 +2,7 @@
@name Developer Guide: Templates: Filters: Using Angular Filters
@description
Filters can be part of any {@link api/angular.module.ng.$rootScope.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 }}
@@ -19,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:
@@ -37,4 +41,4 @@ argument that specifies how many digits to display to the right of the decimal p
## Related API
* {@link api/angular.module.ng.$filter Angular Filter API}
* {@link api/ng.$filter Angular Filter API}
+11 -11
View File
@@ -2,27 +2,27 @@
@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 guide/directive Directive} — An attribute or element that
augments an existing DOM element or represents a reusable DOM component - a widget.
* {@link api/angular.module.ng.$interpolate Markup} — The double
* {@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.forms Form controls} — Lets you validate user input.
* {@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 guide/directive directives} and curly-brace bindings
with {@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 ng-app>
@@ -41,8 +41,8 @@ with {@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.module.ng.$route
$route} service in conjunction with the {@link api/angular.module.ng.$compileProvider.directive.ngView ngView} 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.
@@ -50,7 +50,7 @@ eight.
## Related Topics
* {@link dev_guide.templates.filters Angular Filters}
* {@link dev_guide.forms Angular Forms}
* {@link forms Angular Forms}
## Related API
+113 -42
View File
@@ -3,37 +3,49 @@
@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
@@ -52,10 +64,10 @@ function MyClass() {
}
</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>
@@ -69,7 +81,7 @@ 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() {
@@ -83,9 +95,9 @@ 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}
@@ -119,7 +131,7 @@ 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).
@@ -164,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
@@ -173,7 +185,7 @@ 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');
@@ -197,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>
@@ -207,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');
@@ -218,36 +230,35 @@ 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();
var pc = new PasswordCtrl();
pc.password('abc');
pc.grade();
expect(span.strength).toEqual('weak');
expect(pc.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.module.ng.$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.
@@ -264,18 +275,78 @@ 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</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</h1>`. Now we are going to write a jasmine unit test to
verify this functionality.
<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);
// Check that the compiled element contains the templated content
expect(element.html()).toContain("lidless, wreathed in flame");
});
});
</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" 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.
+235
View File
@@ -0,0 +1,235 @@
@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 make 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 ask 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 annotate 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:
<pre>
var MyController = function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
}
MyController.$inject = ['$scope', 'dep1', 'dep2'];
</pre>
## 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>
+183 -159
View File
@@ -1,5 +1,5 @@
@ngdoc overview
@name directive
@name Directives
@description
Directives are a way to teach HTML new tricks. During DOM compilation directives are matched
@@ -10,7 +10,7 @@ can be extended such that HTML can be turned into a declarative domain specific
# Invoking directives from HTML
Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating
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
@@ -39,11 +39,11 @@ the following example.
</script>
<div ng-controller="Ctrl1">
Hello <input ng-model='name'> <hr/>
&ltspan ng:bind="name"&gt <span ng:bind="name"></span> <br/>
&ltspan ng_bind="name"&gt <span ng_bind="name"></span> <br/>
&ltspan ng-bind="name"&gt <span ng-bind="name"></span> <br/>
&ltspan data-ng-bind="name"&gt <span data-ng-bind="name"></span> <br/>
&ltspan x-ng-bind="name"&gt <span x-ng-bind="name"></span> <br/>
&lt;span ng:bind="name"&gt; <span ng:bind="name"></span> <br/>
&lt;span ng_bind="name"&gt; <span ng_bind="name"></span> <br/>
&lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
&lt;span data-ng-bind="name"&gt; <span data-ng-bind="name"></span> <br/>
&lt;span x-ng-bind="name"&gt; <span x-ng-bind="name"></span> <br/>
</div>
</doc:source>
<doc:scenario>
@@ -53,49 +53,74 @@ the following example.
</doc:scenario>
</doc:example>
# String interpolation
# Text and attribute bindings
During the compilation process the {@link api/angular.module.ng.$compile compiler} matches text and
attributes using the {@link api/angular.module.ng.$interpolate $interpolate} service to see if they
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/angular.module.ng.$rootScope.Scope#$watch watches} and will update as part of normal {@link
api/angular.module.ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is shown
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>
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
<a href="img/{{username}}.jpg">Hello {{username}}!</a>
</pre>
# ngAttr attribute bindings
If an attribute with a binding is prefixed with `ngAttr` prefix (denormalized prefix: 'ng-attr-',
'ng:attr-') then during the compilation the prefix will be removed and the binding will be applied
to an unprefixed attribute. This allows binding to attributes that would otherwise be eagerly
processed by browsers in their uncompiled form (e.g. `img[src]` or svg's `circle[cx]` attributes).
For example, considering template:
<svg>
<circle ng-attr-cx="{{cx}}"></circle>
</svg>
and model cx set to 5, will result in rendering this dom:
<svg>
<circle cx="5"></circle>
</svg>
If you were to bind `{{cx}}` directly to the `cx` attribute, you'd get the following error:
`Error: Invalid value for attribute cx="{{cx}}"`. With `ng-attr-cx` you can work around this
problem.
# 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 then on DOM elements.
systems that operate on strings, rather than on DOM elements.
2. The compilation of the DOM is performed by the call to {@link api/angular.module.ng.$compile
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/angular.module.ng.$compile $compile()} method returns a combined linking function, which is a
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/angular.module.ng.$rootScope.Scope#$watch watches} with the {@link
api/angular.module.ng.$rootScope.Scope scope}. The result of this is a live binding between the
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>';
var html = '<div ng-bind="exp"></div>';
// Step 1: parse HTML into DOM element
var template = angular.element(html);
@@ -109,8 +134,8 @@ Compilation of HTML happens in three phases:
## Reasons behind the compile/link separation
At this point you may wonder why is the compile process broken down to a compile and link phase.
To understand this, lets look at a real world example with repeater:
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:
@@ -125,49 +150,49 @@ The short answer is that compile and link separation is needed any time a change
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 {@link api/angular.module.ng.$interpolate interpolation} directive. {@link
api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} is another directive. But {@link
api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} has a dilemma. It needs to be
`{{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.descriptions}}` evaluate against the right {@link api/angular.module.ng.$rootScope.Scope
scope}. A naive method would be to simply insert a copy of the `li` elemnt and then compile it.
`{{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 problem.
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 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/angular.module.ng.$rootScope.Scope scope} and the specific
links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific
instance of an `li` is performed.
{@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} works by preventing the
compilation process form descending into `li` element. Instead the {@link
api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} directive compiles `li`
seperatly. The result of 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 `li`
element. At runtime the {@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat}
{@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/angular.module.ng.$rootScope.Scope scope} for the cloned `li` element and calls the
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 then
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. Link function
* *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 which displays the current time.
In this example we will build a directive that displays the current time.
<doc:example module="time">
<doc:source>
@@ -178,12 +203,12 @@ In this example we will build a directive which displays the current time.
angular.module('time', [])
// Register the 'myCurrentTime' directive factory method.
// We inject $defer and dateFilter service since the factory method is DI.
.directive('myCurrentTime', function($defer, dateFilter) {
// 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
deferId; // deferId, so that we can cancel the time updates
timeoutId; // timeoutId, so that we can cancel the time updates
// used to update the UI
function updateTime() {
@@ -198,36 +223,39 @@ In this example we will build a directive which displays the current time.
// schedule update in one second
function updateLater() {
// save the deferId for canceling
deferId = $defer(function() {
// save the timeoutId for canceling
timeoutId = $timeout(function() {
updateTime(); // update DOM
updateLater(); // schedule another update
}, 1000);
}
// listen on DOM destroy (removal) event, and cancel the next UI update
// to prevent updating time ofter the DOM element was removed.
// to prevent updating time after the DOM element was removed.
element.bind('$destroy', function() {
$defer.cancel(deferId);
$timeout.cancel(timeoutId);
});
updateLater(); // kick of the UI update process.
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
Date format: <input ng-model="format"> <hr/>
Current time is: <span my-current-time="format"></span>
</div>
</doc:source>
<doc:scenario>
</doc:scenario>
</doc:example>
# Writing directives (long version)
The full skeleton of the directive is shown here:
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(...);
@@ -241,6 +269,7 @@ The full skeleton of the directive is shown here:
transclude: false,
restrict: 'A',
scope: false,
controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
@@ -253,12 +282,11 @@ The full skeleton of the directive is shown here:
});
</pre>
In most cases you will not need such fine control and so the above can be simplified. All of the
different parts of this skeleton are explained in following sections. In this section we are
interested only isomers of this skeleton.
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.
The first step in simplyfing the code is to rely on the deafult values. Therefore the above can be
simplified as:
Therefore the above can be simplified as:
<pre>
var myModule = angular.module(...);
@@ -273,8 +301,10 @@ simplified as:
});
</pre>
Most directives concern themselves only with instances not with template transformations allowing
further simplification:
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(...);
@@ -288,17 +318,17 @@ further simplification:
## Factory method
The factory method is responsible for creating the directive. It is invoked only once, when the
{@link api/angular.module.ng.$compile compiler} matches the directive for the first time. You can
{@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
http://localhost:8000/build/docs/api/angular.module.AUTO.$injector#invoke $injector.invoke} which
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/angular.module.ng.$compile
The directive definition object provides instructions to the {@link api/ng.$compile
compiler}. The attributes are:
* `name` - Name of the current scope. Optional defaults to the name at registration.
* `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
@@ -312,55 +342,63 @@ compiler}. The attributes are:
* `scope` - If set to:
* `true` - then a new scope will be created for this directive. If multiple directives on the
same element request new scope, only one new scope is created. The new scope rule does not
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 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
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 normalized element attribute name to their
corresponding binding strategy. Valid binding strategies are:
templates. Locals definition is a hash of local scope property to its source:
* `attribute` - one time read of element attribute value and save it to widget scope. <br/>
Given `<widget my-attr='abc'>` and widget definition of `scope: {myAttr:'attribute'}`,
then widget scope property `myAttr` will be `"abc"`.
* `@` 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).
* `evaluate` - one time evaluation of expression stored in the attribute. <br/> Given
`<widget my-attr='name'>` and widget definition of `scope: {myAttr:'evaluate'}`, and
parent scope `{name:'angular'}` then widget scope property `myAttr` will be `"angular"`.
* `=` 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`. If the parent
scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
* `bind` - Set up one way binding from the element attribute to the widget scope. <br/>
Given `<widget my-attr='{{name}}'>` and widget definition of `scope: {myAttr:'bind'}`,
and parent scope `{name:'angular'}` then widget scope property `myAttr` will be
`"angular"`, but any changes in the parent scope will be reflected in the widget scope.
* `accessor` - Set up getter/setter function for the expression in the widget element
attribute to the widget scope. <br/> Given `<widget my-attr='name'>` and widget definition
of `scope: {myAttr:'prop'}`, and parent scope `{name:'angular'}` then widget scope
property `myAttr` will be a function such that `myAttr()` will return `"angular"` and
`myAttr('new value')` will update the parent scope `name` property. This is useful for
treating the element as a data-model for reading/writing.
* `expression` - Treat element attribute as an expression to be executed on the parent scope.
<br/>
Given `<widget my-attr='doSomething()'>` and widget definition of `scope:
{myAttr:'expression'}`, and parent scope `{doSomething:function() {}}` then calling the
widget scope function `myAttr` will execute the expression against the parent scope.
* `&` 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 behavior. The controller is injectable with the following locals:
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 obeject for the 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:
@@ -369,32 +407,6 @@ compiler}. The attributes are:
* `^` - Look for the controller on parent elements as well.
* `inject` (object hash) - Specifies a way to inject bindings into a controller. Injection
definition is a hash of normalized element attribute names to their corresponding binding
strategy. Valid binding strategies are:
* `attribute` - inject attribute value. <br/>
Given `<widget my-attr='abc'>` and widget definition of `inject: {myAttr:'attribute'}`, then
`myAttr` will inject `"abc"`.
* `evaluate` - inject one time evaluation of expression stored in the attribute. <br/>
Given `<widget my-attr='name'>` and widget definition of `inject: {myAttr:'evaluate'}`, and
parent scope `{name:'angular'}` then `myAttr` will inject `"angular"`.
* `accessor` - inject a getter/setter function for the expression in the widget element
attribute to the widget scope. <br/>
Given `<widget my-attr='name'>` and widget definition of `inject: {myAttr:'prop'}`, and
parent scope `{name:'angular'}` then injecting `myAttr` will inject a function such
that `myAttr()` will return `"angular"` and `myAttr('new value')` will update the parent
scope `name` property. This is usefull for treating the element as a data-model for
reading/writing.
* `expression` - Inject expression function. <br/>
Given `<widget my-attr='doSomething()'>` and widget definition of
`inject: {myAttr:'expression'}`, and parent scope `{doSomething:function() {}}` then
injecting `myAttr` will inject a function which when called will execute the expression
against the parent scope.
* `restrict` - String of subset of `EACM` which restricts the directive to a specific directive
declaration style. If omitted directives are allowed on attributes only.
@@ -404,18 +416,26 @@ compiler}. The attributes are:
* `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 Creating
Widgets section below for more information.
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.
You can specify `template` as a string representing the template or as a function which takes
two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
a string value representing the template.
* `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 then
You can specify `templateUrl` as a string representing the URL or as a function which takes two
arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
a string value representing the url.
* `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/angular.module.ng.$compileProvider.directive.ngTransclude
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`
@@ -437,31 +457,31 @@ compiler}. The attributes are:
function compile(tElement, tAttrs, transclude) { ... }
</pre>
Compile function deals with transforming the template DOM. Since most directives do not do
template transformation, it is not used often. Examples which require compile functions are
directives which transform template DOM such as {@link
api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat} or load the contents
asynchronously such as {@link api/angular.module.ng.$compileProvider.directive.ngView ngView}. The
compile functions takes the following arguments.
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
#Attributes Attributes}
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 the DOM
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 function - is equivalent to registering the linking function via the `link` property
of the config object when the compile function is empty.
* 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
@@ -474,19 +494,20 @@ A compile function can have a return value which can be either a function or an
function link(scope, iElement, iAttrs, controller) { ... }
</pre>
Link function is responsible for registering DOM listeners as well as updating the DOM. It is
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/angular.module.ng.$rootScope.Scope Scope} - The scope to be used by the
directive for registering {@link api/angular.module.ng.$rootScope.Scope#$watch watches}.
* `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 #Attributes Attributes}
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
@@ -501,16 +522,16 @@ compiler linking function will fail to locate the correct elements for linking.
### Post-linking function
Executed after the child elements are linked. Safe to do DOM transformation in here.
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 attributes object - passed as a parameter in the link() or compile() functions - is a way of
accessing:
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
sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
the attributes.
* *directive inter-communication:* All directives share the same instance of the attributes
@@ -555,6 +576,7 @@ dialog component may work.
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
@@ -564,7 +586,7 @@ into the dialog.
Here is an example of what the template definition for the `dialog` widget may look like.
<pre>
<div ng-show="show()">
<div ng-show="visible">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
@@ -576,18 +598,18 @@ Here is an example of what the template definition for the `dialog` widget may l
This will not render properly, unless we do some scope magic.
The first issue we have to solve is that the dialog box template expect `title` to be defined, but
the place of instantiation would like to bind to `username`. Furthermore the buttons expect `onOk`
as well as `onCancel` functions to be present in the scope. This limits the usefulness of the
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: 'bind', // set up title to accept data-binding
onOk: 'expression', // create a delegate onOk function
onCancel: 'expression', // create a delegate onCancel function
show: 'accessor' // create a getter/setter function for visibility.
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>
@@ -605,12 +627,12 @@ To solve the issue of lack of isolation, the directive declares a new `isolated`
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
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 as unexpected complexity, but it gives the widget user and developer the least
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:
@@ -618,13 +640,16 @@ Therefore the final directive definition looks something like this:
<pre>
transclude: true,
scope: {
title: 'bind', // set up title to accept data-binding
onOk: 'expression', // create a delegate onOk function
onCancel: 'expression', // create a delegate onCancel function
show: 'accessor' // create a getter/setter function for visibility.
}
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
@@ -633,7 +658,6 @@ can be built.
Following is an example of building a reusable widget.
<doc:example module="zippyModule">
<doc:source>
<script>
@@ -649,9 +673,9 @@ Following is an example of building a reusable widget.
// This HTML will replace the zippy directive.
replace: true,
transclude: true,
scope: { zippyTitle:'bind' },
scope: { title:'@zippyTitle' },
template: '<div>' +
'<div class="title">{{zippyTitle}}</div>' +
'<div class="title">{{title}}</div>' +
'<div class="body" ng-transclude></div>' +
'</div>',
// The linking function will add behavior to the template
+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 such evaluations generate `NullPointerExceptions`.
* **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.
@@ -1,5 +1,5 @@
@ngdoc overview
@name Developer Guide: Forms
@name Forms
@description
Controls (`input`, `select`, `textarea`) are a way for user to enter data.
@@ -12,9 +12,9 @@ Server-side validation is still necessary for a secure application.
# Simple form
The key directive in understanding two-way data-binding is {@link api/angular.module.ng.$compileProvider.directive.ngModel ngModel}.
The key directive in understanding two-way data-binding is {@link api/ng.directive:ngModel ngModel}.
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
In addition it provides {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController API} for other directives to augment its behavior.
In addition it provides an {@link api/ng.directive:ngModel.NgModelController API} for other directives to augment its behavior.
<doc:example>
<doc:source>
@@ -63,7 +63,7 @@ To allow styling of form as well as controls, `ngModel` add these CSS classes:
- `ng-pristine`
- `ng-dirty`
Following example uses the CSS to display validity of each form control.
The following example uses the CSS to display validity of each form control.
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
@@ -93,10 +93,10 @@ This ensures that the user is not distracted with an error until after interacti
<script>
function Controller($scope) {
$scope.master= {};
$scope.master = {};
$scope.update = function(user) {
$scope.master= angular.copy(user);
$scope.master = angular.copy(user);
};
$scope.reset = function() {
@@ -113,9 +113,9 @@ This ensures that the user is not distracted with an error until after interacti
# Binding to form and control state
A form is in instance of {@link api/angular.module.ng.$compileProvider.directive.form.FormController FormController}.
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
The form instance can optionally be published into the scope using the `name` attribute.
Similarly control is an instance of {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController NgModelController}.
Similarly control is an instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
The control instance can similarly be published into the form instance using the `name` attribute.
This implies that the internal state of both the form and the control is available for binding in the view using the standard binding primitives.
@@ -178,30 +178,30 @@ This allows us to extend the above example with these features:
# Custom Validation
Angular provides basic implementation for most common html5 {@link api/angular.module.ng.$compileProvider.directive.input input}
types: ({@link api/angular.module.ng.$compileProvider.directive.input.text text}, {@link api/angular.module.ng.$compileProvider.directive.input.number number}, {@link api/angular.module.ng.$compileProvider.directive.input.url url}, {@link api/angular.module.ng.$compileProvider.directive.input.email email}, {@link api/angular.module.ng.$compileProvider.directive.input.radio radio}, {@link api/angular.module.ng.$compileProvider.directive.input.checkbox checkbox}), as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`, `min`, `max`).
Angular provides basic implementation for most common html5 {@link api/ng.directive:input input}
types: ({@link api/ng.directive:input.text text}, {@link api/ng.directive:input.number number}, {@link api/ng.directive:input.url url}, {@link api/ng.directive:input.email email}, {@link api/ng.directive:input.radio radio}, {@link api/ng.directive:input.checkbox checkbox}), as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`, `min`, `max`).
Defining your own validator can be done by defining your own directive which adds a custom validation function to the `ngModel` {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController controller}.
Defining your own validator can be done by defining your own directive which adds a custom validation function to the `ngModel` {@link api/ng.directive:ngModel.NgModelController controller}.
To get a hold of the controller the directive specifies a dependency as shown in the example below.
The validation can occur in two places:
* **Model to View update** -
Whenever the bound model changes, all functions in {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$formatters NgModelController#$formatters} array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
Whenever the bound model changes, all functions in {@link api/ng.directive:ngModel.NgModelController#$formatters NgModelController#$formatters} array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through {@link api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
* **View to Model update** -
In a similar way, whenever a user interacts with a control, the controll calls {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
This in turn pipelines all functions in {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
In a similar way, whenever a user interacts with a control it calls {@link api/ng.directive:ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
This in turn pipelines all functions in the {@link api/ng.directive:ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
In the following example we create two directives.
* The first one is `integer` and it validates whether the input is a valid integer.
For example `1.23` is an invalid value, since it contains a fraction.
Note, that we unshift the array instead of pushing.
Note that we unshift the array instead of pushing.
This is because we want to be first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
* The second directive is a `smart-float`.
It parses both `1.2` and `1,2` into a valid float number `1.2`.
Note that, we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
Note that we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
<doc:example module="form-example1">
@@ -272,13 +272,13 @@ In the following example we create two directives.
</doc:example>
# Implementing custom form control (using `ngModel`)
Angular implements all of the basic HTML form controls ({@link api/angular.module.ng.$compileProvider.directive.input input}, {@link api/angular.module.ng.$compileProvider.directive.select select}, {@link api/angular.module.ng.$compileProvider.directive.textarea textarea}), which should be sufficient for most cases.
# Implementing custom form controls (using `ngModel`)
Angular implements all of the basic HTML form controls ({@link api/ng.directive:input input}, {@link api/ng.directive:select select}, {@link api/ng.directive:textarea textarea}), which should be sufficient for most cases.
However, if you need more flexibility, you can write your own form control as a directive.
In order for custom control to work with `ngModel` and to achieve two-way data-binding it needs to:
- implement `render` method, which is responsible for rendering the data after it passed the {@link api/angular.module.ng.$compileProvider.directive.ngModel.NgModelController#$formatters NgModelController#$formatters},
- implement `$render` method, which is responsible for rendering the data after it passed the {@link api/ng.directive:ngModel.NgModelController#$formatters NgModelController#$formatters},
- call `$setViewValue` method, whenever the user interacts with the control and model needs to be updated. This is usually done inside a DOM Event listener.
See {@link guide/directive $compileProvider.directive} for more info.
@@ -300,8 +300,8 @@ The following example shows how to add two-way data-binding to contentEditable e
});
// model -> view
ctrl.render = function(value) {
elm.html(value);
ctrl.$render = function() {
elm.html(ctrl.$viewValue);
};
// load init value from DOM
@@ -17,15 +17,15 @@ abstracted bits.
**What level of support for i18n/l10n is currently in Angular?**
Currently, Angular supports i18n/l10n for {@link
http://docs.angularjs.org/#!/api/angular.module.ng.$filter.date datetime}, {@link
http://docs.angularjs.org/#!/api/angular.module.ng.$filter.number number} and {@link
http://docs.angularjs.org/#!/api/angular.module.ng.$filter.currency currency} filters.
http://docs.angularjs.org/#!/api/ng.filter:date datetime}, {@link
http://docs.angularjs.org/#!/api/ng.filter:number number} and {@link
http://docs.angularjs.org/#!/api/ng.filter:currency currency} filters.
Additionally, Angular supports localizable pluralization support provided by the {@link
api/angular.module.ng.$compileProvider.directive.ngPluralize ngPluralize directive}.
api/ng.directive:ngPluralize ngPluralize directive}.
All localizable Angular components depend on locale-specific rule sets managed by the {@link
api/angular.module.ng.$locale $locale service}.
api/ng.$locale $locale service}.
For readers who want to jump straight into examples, we have a few web pages that showcase how to
use Angular filters with various locale rule sets. You can find these examples either on {@link
@@ -53,7 +53,7 @@ There are two approaches to providing locale rules to Angular:
You can pre-bundle the desired locale file with Angular by concatenating the content of the
locale-specific file to the end of `angular.js` or `angular.min.js` file.
For example on *nix, to create a an angular.js file that contains localization rules for german
For example on *nix, to create an angular.js file that contains localization rules for german
locale, you can do the following:
`cat angular.js i18n/angular-locale_de-ge.js > angular_de-ge.js`
@@ -90,8 +90,8 @@ because an extra script needs to be loaded.
**Currency symbol "gotcha"**
Angular's {@link http://docs.angularjs.org/#!/api/angular.module.ng.$filter.currency currency filter} allows
you to use the default currency symbol from the {@link api/angular.module.ng.$locale locale service},
Angular's {@link http://docs.angularjs.org/#!/api/ng.filter:currency currency filter} allows
you to use the default currency symbol from the {@link api/ng.$locale locale service},
or you can provide the filter with a custom currency symbol. If your app will be used only in one
locale, it is fine to rely on the default currency symbol. However, if you anticipate that viewers
in other locales might use your app, you should provide your own currency symbol to make sure the
@@ -104,7 +104,7 @@ browser will specify the locale as ja, and the balance of '¥1000.00' will be sh
will really upset your client.
In this case, you need to override the default currency symbol by providing the {@link
http://docs.angularjs.org/#!/api/angular.module.ng.$filter.currency currency filter} with a currency symbol as
http://docs.angularjs.org/#!/api/ng.filter:currency currency filter} with a currency symbol as
a parameter when you configure the filter, for example, {{ 1000 | currency:"USD$"}}. This way,
Angular will always show a balance of 'USD$1000' and disregard any locale changes.
+59 -34
View File
@@ -5,43 +5,68 @@
# Overview
This document describes the Internet Explorer (IE) idiosyncrasies when dealing with custom HTML
attributes and tags. Read this document if you are planning on deploying your angular application
attributes and tags. Read this document if you are planning on deploying your Angular application
on IE v8.0 or earlier.
# Short Version
To make your angular application work on IE please make sure that:
To make your Angular application work on IE please make sure that:
1. you **do not** use custom element tags such as `<ng:view>` (use the attribute version `<div
ng-view>` instead), or
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
[JSON2](https://github.com/douglascrockford/JSON-js) or
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org">
<head>
<!--[if lte IE 8]>
<script src="/path/to/json2.js"></script>
<![endif]-->
</head>
<body>
...
</body>
</html>
</pre>
2. if you **do use** custom element tags, then you must take these steps to make IE happy:
2. add `id="ng-app"` to the root element in conjunction with `ng-app` attribute
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
...
</html>
</pre>
<pre>
<html xmlns:ng="http://angularjs.org">
<head>
<!--[if lte IE 8]>
<script>
document.createElement('ng-include');
document.createElement('ng-pluralize');
document.createElement('ng-view');
// Optionally these for CSS
document.createElement('ng:include');
document.createElement('ng:pluralize');
document.createElement('ng:view');
</script>
<![endif]-->
</head>
<body>
...
</body>
</html>
</pre>
3. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
`<div ng-view>` instead), or
4. if you **do use** custom element tags, then you must take these steps to make IE happy:
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
<head>
<!--[if lte IE 8]>
<script>
document.createElement('ng-include');
document.createElement('ng-pluralize');
document.createElement('ng-view');
// Optionally these for CSS
document.createElement('ng:include');
document.createElement('ng:pluralize');
document.createElement('ng:view');
</script>
<![endif]-->
</head>
<body>
...
</body>
</html>
</pre>
The **important** parts are:
* `xmlns:ng` - *namespace* - you need one namespace for each custom tay you are planning on
* `xmlns:ng` - *namespace* - you need one namespace for each custom tag you are planning on
using.
* `document.createElement(yourTagName)` - *creation of custom tag names* - Since this is an
@@ -52,7 +77,7 @@ The **important** parts are:
# Long Version
IE has an issues with element tag names which are not standard HTML tag names. These fall into two
IE has issues with element tag names which are not standard HTML tag names. These fall into two
categories, and each category has its own fix.
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
@@ -61,13 +86,13 @@ categories, and each category has its own fix.
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
`document.createElement('my-tag')`
* If you have are planning on styling the custom tag with CSS selectors, then it must be
* If you are planning on styling the custom tag with CSS selectors, then it must be
pre-created using `document.createElement('my-tag')` regardless of XML namespace.
## The Good News
The good news is that these restrictions only apply to element tag names, and not to element
The good news is that these restrictions only apply to element tag names, and not to element
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
@@ -84,7 +109,7 @@ result):
</html>
</pre>
It should pares into the following DOM:
It should parse into the following DOM:
<pre>
#document
@@ -118,12 +143,12 @@ In IE, the behavior is that the `BODY` element has three children:
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
the `/` character. Furthermore this closing element should not be part of the DOM since it is
only used to delimitate the structure of the DOM.
only used to delineate the structure of the DOM.
## CSS Styling of Custom Tag Names
The to make CSS selector work with custom elements the custom element name must be shived with the
To make CSS selectors work with custom elements, the custom element name must be pre-created with
`document.createElement('my-tag')` regardless of XML namespace.
<pre>
@@ -133,7 +158,7 @@ The to make CSS selector work with custom elements the custom element name must
<script>
// needed to make ng-include parse properly
document.createElement('ng-include');
// needed to enable CSS reference
document.createElement('ng:view');
</script>
+1 -42
View File
@@ -2,7 +2,7 @@
@name Developer Guide
@description
Welcome to the angular Developer Guide. If you are here to learn the details of how to use angular
Welcome to the angular Developer Guide. If you are here to learn the details of how to use angular
to develop web apps, you've come to the right place.
If you are completely or relatively unfamiliar with angular, you may want to check out one or both
@@ -10,44 +10,3 @@ of the following documents before returning here to the Developer Guide:
* {@link misc/started Getting Started}
* {@link tutorial/index Angular Tutorial}
<hr>
## {@link dev_guide.overview Overview of Angular}
## {@link dev_guide.bootstrap Initializing Angular}
* {@link dev_guide.bootstrap.auto_bootstrap Understanding Automatic Initialization}
* {@link dev_guide.bootstrap.manual_bootstrap Understanding Manual Initialization}
## {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
## {@link dev_guide.scopes Angular Scope Objects}
* {@link dev_guide.scopes.understanding_scopes Understanding Angular Scope Objects}
* {@link dev_guide.scopes.internals Angular Scope Internals}
## {@link dev_guide.compiler Angular HTML Compiler}
* {@link guide/directive Understanding Angular Directives}
## {@link dev_guide.templates Angular Templates}
* {@link dev_guide.templates.filters Understanding Angular Filters}
* {@link dev_guide.forms Understanding Angular Forms}
## {@link dev_guide.services Angular Services}
* {@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.testing_services Testing Angular Services}
## {@link dev_guide.di About Dependency Injection}
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
* {@link dev_guide.di.using_di_controllers Using DI in Controllers}
@@ -3,40 +3,40 @@
@description
Angular is pure client-side technology, written entirely in JavaScript. It works with the
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of web
apps easier and faster than ever before.
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of
web apps easier and faster than ever before.
One important way that angular simplifies web development is by increasing the level of abstraction
One important way that Angular simplifies web development is by increasing the level of abstraction
between the developer and most low-level web app development tasks. Angular automatically takes
care of many of these tasks, including:
* DOM Manipulation
* Setting Up Listeners and Notifiers
* Input Validation
* DOM Manipulation
* Setting Up Listeners and Notifiers
* Input Validation
Because angular handles much of the work involved in these tasks, developers can concentrate more
Because Angular handles much of the work involved in these tasks, developers can concentrate more
on application logic and less on repetitive, error-prone, lower-level coding.
At the same time that angular simplifies the development of web apps, it brings relatively
At the same time that Angular simplifies the development of web apps, it brings relatively
sophisticated techniques to the client-side, including:
* Separation of data, application logic, and presentation components
* Data Binding between data and presentation components
* Services (common web app operations, implemented as substitutable objects)
* Dependency Injection (used primarily for wiring together services)
* An extensible HTML compiler (written entirely in JavaScript)
* Ease of Testing
* Separation of data, application logic, and presentation components
* Data Binding between data and presentation components
* Services (common web app operations, implemented as substitutable objects)
* Dependency Injection (used primarily for wiring together services)
* An extensible HTML compiler (written entirely in JavaScript)
* Ease of Testing
These techniques have been for the most part absent from the client-side for far too long.
## Single-page / Round-trip Applications
You can use angular to develop both single-page and round-trip apps, but angular is designed
You can use Angular to develop both single-page and round-trip apps, but Angular is designed
primarily for developing single-page apps. Angular supports browser history, forward and back
buttons, and bookmarking in single-page apps.
You normally wouldn't want to load angular with every page change, as would be the case with using
angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
angular's features (for example, templates to leverage angular's data-binding feature) to an
You normally wouldn't want to load Angular with every page change, as would be the case with using
Angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
Angular's features (for example, templates to leverage angular's data-binding feature) to an
existing round-trip app. You might follow this course of action if you were migrating an older app
to a single-page angular app.
to a single-page Angular app.
+16 -17
View File
@@ -5,9 +5,8 @@
# What is a Module?
Most applications have a main method which instantiates, wires, and bootstraps the application.
Angular apps don't have a main method, instead the modules serves the purpose of declaratively
specifying how an application should be bootstrapped. There are several advantages to this
approach:
Angular apps don't have a main method. Instead modules declaratively specify how an application
should be bootstrapped. There are several advantages to this approach:
* The process is more declarative which is easier to understand
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
@@ -19,7 +18,7 @@ approach:
# The Basics
Ok, I'm in a hurry how do i get a Hello World module working?
Ok, I'm in a hurry. How do I get a Hello World module working?
Important things to notice:
@@ -27,15 +26,15 @@ Important things to notice:
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
bootstraps the app using your module.
<doc:example module='simpleApp'>
<doc:example module='myApp'>
<doc:source>
<script>
// declare a module
var simpleAppModule = angular.module('simpleApp', []);
var myAppModule = angular.module('myApp', []);
// configure the module.
// in this example we will create a greeting filter
simpleAppModule.filter('greet', function() {
myAppModule.filter('greet', function() {
return function(name) {
return 'Hello, ' + name + '!';
};
@@ -62,9 +61,9 @@ that you break your application to multiple modules like this:
initialization code.
The reason for this breakup is that in your tests, it is often necessary to ignore the
initialization code, which tends to be difficult to test. By putting it into separate module it
initialization code, which tends to be difficult to test. By putting it into a separate module it
can be easily ignored in tests. The tests can also be more focused by only loading the modules
which are relevant to tests.
that are relevant to tests.
The above is only a suggestion, so feel free to tailor it to your needs.
@@ -139,7 +138,7 @@ angular.module('myModule', []).
// This is an example of a run block.
// You can have as many of these as you want.
// You can only inject instances (not Providers)
// int the run blocks
// into the run blocks
});
</pre>
@@ -159,9 +158,9 @@ angular.module('myModule', []).
angular.module('myModule', []).
config(function($provide, $compileProvider, $filterProvider) {
$provide.value('a', 123)
$provide.factory('a', function() { return 123; })
$compileProvider.directive('directiveName', ...).
$provide.value('a', 123);
$provide.factory('a', function() { return 123; });
$compileProvider.directive('directiveName', ...);
$filterProvider.register('filterName', ...);
});
</pre>
@@ -181,7 +180,7 @@ ignored in the unit-tests.
Modules can list other modules as their dependencies. Depending on a module implies that required
module needs to be loaded before the requiring module is loaded. In other words the configuration
blocks of the required modules execute before the configuration blocks or the requiring module.
blocks of the required modules execute before the configuration blocks of the requiring module.
The same is true for the run blocks. Each module can only be loaded once, even if multiple other
modules require it.
@@ -195,7 +194,7 @@ and thus script loaders can take advantage of this property and parallelize the
# Unit Testing
In its simplest form a unit-test is a way of instantiating a subset of the application in test and
In its simplest form a unit test is a way of instantiating a subset of the application in test and
then applying a stimulus to it. It is important to realize that each module can only be loaded
once per injector. Typically an app has only one injector. But in tests, each test has its own
injector, which means that the modules are loaded multiple times per VM. Properly structured
@@ -223,8 +222,8 @@ In all of these examples we are going to assume this module definition:
Let's write some tests:
<pre>
describe('myApp', function() {
// load the application relevant modules then load a special
// test module which overrides the $window with mock version,
// load the relevant application modules then load a special
// test module which overrides the $window with a mock version,
// so that calling window.alert() will not block the test
// runner with a real alert box. This is an example of overriding
// configuration information in tests.
+207
View File
@@ -0,0 +1,207 @@
@ngdoc overview
@name Developer Guide: Overview
@description
# What Is Angular?
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
language and lets you extend HTML's syntax to express your application's components clearly and
succinctly. Out of the box, it eliminates much of the code you currently write through data
binding and dependency injection. And it all happens in JavaScript within the browser making it an
ideal partner with any server technology.
Angular is what HTML would have been had it been designed for applications. HTML is a great
declarative language for static documents. It does not contain much in the way of creating
applications, and as a result building web applications is an exercise in *what do I have to do, so
that I trick the browser in to doing what I want.*
The impedance mismatch between dynamic applications and static documents is often solved as:
* **library** - a collection of functions which are useful when writing web apps. Your code is
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
* **frameworks** - a particular implementation of a web application, where your code fills in
the details. The framework is in charge and it calls into your code when it needs something
app specific. E.g., `knockout`, `sproutcore`, etc.
Angular takes another approach. It attempts to minimize the impedance mismatch between document
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
browser new syntax through a construct we call directives. Examples include:
* Data binding as in `{{}}`.
* DOM control structures for repeating/hiding DOM fragments.
* Support for forms and form validation.
* Attaching code-behind to DOM elements.
* Grouping of HTML into reusable components.
## End-to-end solution
Angular tries to be an end-to-end solution, when building a web application. This means it is
not a single piece in an overall puzzle of building a web application, but an end-to-end solution.
This makes Angular opinionated about how a CRUD application should be built. But while it is
opinionated, it also tries to make sure that its opinion is just a starting point, which you can
easily change. Angular comes with the following out-of-the-box:
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
directives, form validation, routing, deep-linking, reusable components, dependency injection.
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
* Seed application with directory layout and test scripts as a starting point.
## Angular Sweet Spot
Angular simplifies application development by presenting a higher level of abstraction to the
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
is a good fit for Angular. Angular was built for the CRUD application in mind. Luckily CRUD
applications represent at least 90% of the web applications. But to understand what Angular is
good at one also has to understand when an app is not a good fit for Angular.
Games, and GUI editors are examples of very intensive and tricky DOM manipulation. These kinds of
apps are different from CRUD apps, and as a result are not a good fit for Angular. In these cases
using something closer to bare metal such as `jQuery` may be a better fit.
# An Introductory Angular Example
Below is a typical CRUD application which contains a form. The form values are validated, and
are used to compute the total, which is formatted to a particular locale. These are some common
concepts which the application developer may face:
* attaching data-model to the UI.
* writing, reading and validating user input.
* computing new values based on the model.
* formatting output in a user specific locale.
<example>
<file name="script.js">
function InvoiceCntl($scope) {
$scope.qty = 1;
$scope.cost = 19.95;
}
</file>
<file name="index.html">
<div ng-controller="InvoiceCntl">
<b>Invoice:</b>
<br>
<br>
<table>
<tr><td>Quantity</td><td>Cost</td></tr>
<tr>
<td><input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required ></td>
<td><input type="number" ng-model="cost" required ></td>
</tr>
</table>
<hr>
<b>Total:</b> {{qty * cost | currency}}
</div>
</file>
<file name="scenario.js">
it('should show 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');
});
</file>
</example>
Try out the Live Preview above, and then let's walk through the example and describe what's going
on.
In the `<html>` tag, we specify that it is an Angular
application with the `ng-app` directive. The `ng-app` will cause Angular to {@link
bootstrap auto initialize} your application.
<html ng-app>
We load Angular using the `<script>` tag:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
From the `ng-model` attribute of the `<input>` tags, Angular automatically sets up two-way data
binding, and we also demonstrate some easy input validation:
Quantity: <input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required >
Cost: <input type="number" ng-model="cost" required >
These input widgets look normal enough, but consider these points:
* When this page loaded, Angular bound the names of the input widgets (`qty` and `cost`) to
variables of the same name. Think of those variables as the "Model" component of the
Model-View-Controller design pattern.
* Note that the HTML widget {@link api/ng.directive:input input}
has special powers. The input invalidates itself by turning red when you enter invalid data or
leave the the input fields blank. These new widget behaviors make it easier to implement field
validation common in CRUD applications.
And finally, the mysterious `{{ double curly braces }}`:
Total: {{qty * cost | currency}}
This notation, `{{ _expression_ }}`, is Angular markup for data-binding. The expression itself can
be a combination of both an expression and a {@link dev_guide.templates.filters filter}: `{{
expression | filter }}`. Angular provides filters for formatting display data.
In the example above, the expression in double-curly braces directs Angular to "bind the data we
got from the input widgets to the display, multiply them together, and format the resulting number
into output that looks like money."
Notice that we achieved this application behavior not by calling Angular methods, nor by
implementing application specific behavior as a framework. We achieved the behavior because the
browser behaved more in line with what is needed for a dynamic web application rather then what is
needed for a static document. Angular has lowered the impedance mismatch to the point where no
library/framework calls are needed.
# The Zen of Angular
Angular is built around the belief that declarative code is better than imperative when it comes
to building UIs and wiring software components together, while imperative code is excellent for
expressing business logic.
* It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves
the testability of the code.
* It is a really, _really_ good idea to regard app testing as equal in importance to app
writing. Testing difficulty is dramatically affected by the way the code is structured.
* It is an excellent idea to decouple the client side of an app from the server side. This
allows development work to progress in parallel, and allows for reuse of both sides.
* It is very helpful indeed if the framework guides developers through the entire journey of
building an app: from designing the UI, through writing the business logic, to testing.
* It is always good to make common tasks trivial and difficult tasks possible.
Angular frees you from the following 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 programmatically:** Manipulating HTML DOM is a cornerstone of AJAX
applications, but it's cumbersome and error-prone. By declaratively describing how the UI
should change as your application state changes, you are freed from low level DOM manipulation
tasks. Most applications written with Angular never have to programmatically manipulate the
DOM, although you can if you want to.
* **Marshaling data to and from the UI:** CRUD operations make up the majority of AJAX
applications. The flow of marshaling data from the server to an internal object to an HTML
form, allowing users to modify the form, validating the form, displaying validation errors,
returning to an internal model, and then back to the server, creates a lot of boilerplate
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
overall flow of the application rather than all of the implementation details.
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
your app easily using services, which are auto-injected into your application in a {@link
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
to get started developing features quickly. As a bonus, you get full control over the
initialization process in automated tests.
# Watch a Presentation About Angular
Here is a presentation on Angular from May 2012. The {@link http://mhevery.github.io/angular-demo-slides/index.html#/list corresponding slides} are also available.
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
+331
View File
@@ -0,0 +1,331 @@
@ngdoc overview
@name Developer Guide: Scopes
@description
# What are Scopes?
{@link api/ng.$rootScope.Scope scope} is an object that refers to the application
model. It is an execution context for {@link expression expressions}. Scopes are
arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can
watch {@link guide/expression expressions} and propagate events.
## Scope characteristics
- Scopes provide APIs ({@link api/ng.$rootScope.Scope#$watch $watch}) to observe
model mutations.
- Scopes provide APIs ({@link api/ng.$rootScope.Scope#$apply $apply}) to
propagate any model changes through the system into the view from outside of the "Angular
realm" (controllers, services, Angular event handlers).
- Scopes can be nested to isolate application components while providing access to shared model
properties. A scope (prototypically) inherits properties from its parent scope.
- Scopes provide context against which {@link guide/expression expressions} are evaluated. For
example `{{username}}` expression is meaningless, unless it is evaluated against a specific
scope which defines the `username` property.
## Scope as Data-Model
Scope is the glue between application controller and the view. During the template {@link compiler
linking} phase the {@link api/ng.$compileProvider#directive directives} set up
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
`$watch` allows the directives to be notified of property changes, which allows the directive to
render the updated value to the DOM.
Both controllers and directives have reference to the scope, but not to each other. This
arrangement isolates the controller from the directive as well as from DOM. This is an important
point since it makes the controllers view agnostic, which greatly improves the testing story of
the applications.
<example>
<file name="script.js">
function MyController($scope) {
$scope.username = 'World';
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}
</file>
<file name="index.html">
<div ng-controller="MyController">
Your name:
<input type="text" ng-model="username">
<button ng-click='sayHello()'>greet</button>
<hr>
{{greeting}}
</div>
</file>
</example>
In the above example notice that the `MyController` assigns `World` to the `username` property of
the scope. The scope then notifies the `input` of the assignment, which then renders the input
with username pre-filled. This demonstrates how a controller can write data into the scope.
Similarly the controller can assign behavior to scope as seen by the `sayHello` method, which is
invoked when the user clicks on the 'greet' button. The `sayHello` method can read the `username`
property and create a `greeting` property. This demonstrates that the properties on scope update
automatically when they are bound to HTML input widgets.
Logically the rendering of `{{greeting}}` involves:
* retrieval of the scope associated with DOM node where `{{greeting}}` is defined in template.
In this example this is the same scope as the scope which was passed into `MyController`. (We
will discuss scope hierarchies later.)
* Evaluate the `greeting` {@link guide/expression expression} against the scope retrieved above,
and assign the result to the text of the enclosing DOM element.
You can think of the scope and its properties as the data which is used to render the view. The
scope is the single source-of-truth for all things view related.
From a testability point of view, the separation of the controller and the view is desirable, because it allows us
to test the behavior without being distracted by the rendering details.
<pre>
it('should say hello', function() {
var scopeMock = {};
var cntl = new MyController(scopeMock);
// Assert that username is pre-filled
expect(scopeMock.username).toEqual('World');
// Assert that we read new username and greet
scopeMock.username = 'angular';
scopeMock.sayHello();
expect(scopeMock.greeting).toEqual('Hello angular!');
});
</pre>
## Scope Hierarchies
Each Angular application has exactly one {@link api/ng.$rootScope root scope}, but
may have several child scopes.
The application can have multiple scopes, because some {@link guide/directive directives} create
new child scopes (refer to directive documentation to see which directives create new scopes).
When new scopes are created, they are added as children of their parent scope. This creates a tree
structure which parallels the DOM where they're attached
When Angular evaluates `{{username}}`, it first looks at the scope associated with the given
element for the `username` property. If no such property is found, it searches the parent scope
and so on until the root scope is reached. In JavaScript this behavior is known as prototypical
inheritance, and child scopes prototypically inherit from their parents.
This example illustrates scopes in application, and prototypical inheritance of properties.
<example>
<file name="style.css">
/* remove .doc-example-live in jsfiddle */
.doc-example-live .ng-scope {
border: 1px dashed red;
}
</file>
<file name="script.js">
function EmployeeController($scope) {
$scope.department = 'Engineering';
$scope.employee = {
name: 'Joe the Manager',
reports: [
{name: 'John Smith'},
{name: 'Mary Run'}
]
};
}
</file>
<file name="index.html">
<div ng-controller="EmployeeController">
Manager: {{employee.name}} [ {{department}} ]<br>
Reports:
<ul>
<li ng-repeat="employee in employee.reports">
{{employee.name}} [ {{department}} ]
</li>
</ul>
<hr>
{{greeting}}
</div>
</file>
</example>
Notice that Angular automatically places `ng-scope` class on elements where scopes are
attached. The `<style>` definition in this example highlights in red the new scope locations. The
child scopes are necessary because the repeater evaluates `{{employee.name}}` expression, but
depending on which scope the expression is evaluated it produces different result. Similarly the
evaluation of `{{department}}` prototypically inherits from root scope, as it is the only place
where the `department` property is defined.
## Retrieving Scopes from the DOM.
Scopes are attached to the DOM as `$scope` data property, and can be retrieved for debugging
purposes. (It is unlikely that one would need to retrieve scopes in this way inside the
application.) The location where the root scope is attached to the DOM is defined by the location
of {@link api/ng.directive:ngApp `ng-app`} directive. Typically
`ng-app` is placed on the `<html>` element, but it can be placed on other elements as well, if,
for example, only a portion of the view needs to be controlled by Angular.
To examine the scope in the debugger:
1. right click on the element of interest in your browser and select 'inspect element'. You
should see the browser debugger with the element you clicked on highlighted.
2. The debugger allows you to access the currently selected element in the console as `$0`
variable.
3. To retrieve the associated scope in console execute: `angular.element($0).scope()`
## Scope Events Propagation
Scopes can propagate events in similar fashion to DOM events. The event can be {@link
api/ng.$rootScope.Scope#$broadcast broadcasted} to the scope children or {@link
api/ng.$rootScope.Scope#$emit emitted} to scope parents.
<example>
<file name="script.js">
function EventController($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}
</file>
<file name="index.html">
<div ng-controller="EventController">
Root scope <tt>MyEvent</tt> count: {{count}}
<ul>
<li ng-repeat="i in [1]" ng-controller="EventController">
<button ng-click="$emit('MyEvent')">$emit('MyEvent')</button>
<button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button>
<br>
Middle scope <tt>MyEvent</tt> count: {{count}}
<ul>
<li ng-repeat="item in [1, 2]" ng-controller="EventController">
Leaf scope <tt>MyEvent</tt> count: {{count}}
</li>
</ul>
</li>
</ul>
</div>
</file>
</example>
## Scope Life Cycle
The normal flow of a browser receiving an event is that it executes a corresponding JavaScript
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
more events.
When the browser calls into JavaScript the code executes outside the Angular execution context,
which means that Angular is unaware of model modifications. To properly process model
modifications the execution has to enter the Angular execution context using the {@link
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
execute inside the `$apply` method will be properly accounted for by Angular. For example if a
directive listens on DOM events, such as {@link
api/ng.directive:ngClick `ng-click`} it must evaluate the
expression inside the `$apply` method.
After evaluating the expression, the `$apply` method performs a {@link
api/ng.$rootScope.Scope#$digest `$digest`}. In the $digest phase the scope examines all
of the `$watch` expressions and compares them with the previous value. This dirty checking is done
asynchronously. This means that assignment such as `$scope.username="angular"` will not
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
`$watch` notification as well as it guarantees that during the `$watch` notification no other
`$watch`es are running. If a `$watch` changes the value of the model, it will force additional
`$digest` cycle.
1. **Creation**
The {@link api/ng.$rootScope root scope} is created during the application
bootstrap by the {@link api/AUTO.$injector $injector}. During template
linking, some directives create new child scopes.
2. **Watcher registration**
During template linking directives register {@link
api/ng.$rootScope.Scope#$watch watches} on the scope. These watches will be
used to propagate model values to the DOM.
3. **Model mutation**
For mutations to be properly observed, you should make them only within the {@link
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular APIs do this
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
or asynchronous work with {@link api/ng.$http $http} or {@link
api/ng.$timeout $timeout} services.
4. **Mutation observation**
At the end `$apply`, Angular performs a {@link api/ng.$rootScope.Scope#$digest
$digest} cycle on the root scope, which then propagates throughout all child scopes. During
the `$digest` cycle, all `$watch`ed expressions or functions are checked for model mutation
and if a mutation is detected, the `$watch` listener is called.
5. **Scope destruction**
When child scopes are no longer needed, it is the responsibility of the child scope creator
to destroy them via {@link api/ng.$rootScope.Scope#$destroy scope.$destroy()}
API. This will stop propagation of `$digest` calls into the child scope and allow for memory
used by the child scope models to be reclaimed by the garbage collector.
### Scopes and Directives
During the compilation phase, the {@link compiler compiler} matches {@link
api/ng.$compileProvider#directive directives} against the DOM template. The directives
usually fall into one of two categories:
- Observing {@link api/ng.$compileProvider#directive directives}, such as
double-curly expressions `{{expression}}`, register listeners using the {@link
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
to be notified whenever the expression changes so that it can update the view.
- Listener directives, such as {@link api/ng.directive:ngClick
ng-click}, register a listener with the DOM. When the DOM listener fires, the directive
executes the associated expression and updates the view using the {@link
api/ng.$rootScope.Scope#$apply $apply()} method.
When an external event (such as a user action, timer or XHR) is received, the associated {@link
expression expression} must be applied to the scope through the {@link
api/ng.$rootScope.Scope#$apply $apply()} method so that all listeners are updated
correctly.
### Directives that Create Scopes
In most cases, {@link api/ng.$compileProvider#directive directives} and scopes interact
but do not create new instances of scope. However, some directives, such as {@link
api/ng.directive:ngController ng-controller} and {@link
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM
element by using an `angular.element(aDomElement).scope()` method call.
### Controllers and Scopes
Scopes and controllers interact with each other in the following situations:
- Controllers use scopes to expose controller methods to templates (see {@link
api/ng.directive:ngController ng-controller}).
- Controllers define methods (behavior) that can mutate the model (properties on the scope).
- Controllers may register {@link api/ng.$rootScope.Scope#$watch watches} on
the model. These watches execute immediately after the controller behavior executes.
See the {@link api/ng.directive:ngController ng-controller} for more
information.
### Scope `$watch` Performance Considerations
Dirty checking the scope for property changes is a common operation in Angular and for this reason
the dirty checking function must be efficient. Care should be taken that the dirty checking
function does not do any DOM access, as DOM access is orders of magnitude slower then property
access on JavaScript object.
-3
View File
@@ -1,3 +0,0 @@
@ngdoc overview
@name Developer Guide: Type
@description
+104 -73
View File
@@ -13,19 +13,19 @@
<a name="H1_1"></a>
# License
`Angular` is an open source project licensed under the {@link
AngularJS is an open source project licensed under the {@link
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
always welcome. When working with `angular` source base, please follow the guidelines provided on
always welcome. When working with AngularJS code base, please follow the guidelines provided on
this page.
<a name="H1_2"></a>
# Contributing to Source Code
We'd love for you to contribute to our source code and to make `angular` even better than it is
today! Here are the guidelines we'd like you to use:
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
* Major changes that you intend to contribute to the project must be discussed first on our {@link
* Major changes that you intend to contribute to the project should be discussed first on our {@link
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
is successfully accepted upstream.
@@ -64,46 +64,44 @@ inheritance only when absolutely necessary.
external API. See our existing code to see what we mean.
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
that is used throughout `angular`. The best guidance is to do what makes the most sense.
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
<a name="H1_4"></a>
# Checking Out and Building Angular
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. Several steps are needed to check out and build `angular`:
The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. The AngularJS repository can be found at **<https://github.com/angular/angular.js>**.
Several steps are needed to check out and build AngularJS:
## Installation Dependencies
Before you can build `angular`, you must install or configure the following dependencies on your
Before you can build AngularJS, you must install or configure the following dependencies on your
machine:
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
Rake website.
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
development web server. Depending on your system, you can install Node either from source or as a
pre-packaged bundle.
You'll also need npm and the following npm modules:
* install npm: `curl http://npmjs.org/install.sh | sh`
* install q: `npm install q`
* install qq: `npm install qq`
* install q-fs: `npm install q-fs`
* install jasmine-node: `npm install jasmine`
* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
`angular` source base, which means there is no need to install or configure it separately.
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
quite a good source for information on Git.
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation, run a
development web server, run tests, and generate a build. Depending on your system, you can install Node either from source or as a
pre-packaged bundle.
* {@link http://www.java.com Java}: JavaScript is minified using
{@link https://developers.google.com/closure/ Closure Tools} jar. Make sure you have Java (version 6 or higher) installed
and included in your {@link http://docs.oracle.com/javase/tutorial/essential/environment/paths.html PATH} variable.
Once installed, you'll also need several npms (node packages), which you can install once you checked out a local copy
of the Angular repository (see below) with:
* `cd angular.js`
* `npm install`
* {@link http://gruntjs.com Grunt}: We use Grunt as our build system. Install the grunt command-line tool globally with:
* `sudo npm install -g grunt-cli`
## Creating a Github Account and Forking Angular
@@ -112,31 +110,39 @@ Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
https://github.com/angular/angular.js main angular repository}.
## Building `Angular`
## Building AngularJS
To build `angular`, you check out the source code and use Rake to generate the non-minified and
minified `angular` files:
To build AngularJS, you check out the source code and use Grunt to generate the non-minified and
minified AngularJS files:
1. To clone your Github repository, run:
git clone git@github.com:<github username>/angular.js.git
2. To go to the `angular` directory, run:
2. To go to the AngularJS directory, run:
cd angular.js
3. To add the main `angular` repository as an upstream remote to your repository, run:
3. To add the main AngularJS repository as an upstream remote to your repository, run:
git remote add upstream https://github.com/angular/angular.js.git
4. To build `angular`, run:
4. To add node.js dependencies
npm install
5. To build AngularJS, run:
grunt package
NOTE: If you're using Windows you must run your command line with administrative privileges (right click, run as
Administrator).
rake package
The build output can be located under the `build` directory. It consists of the following files and
directories:
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build
* `angular-<version>.zip` — This is the complete zip file, which contains all of the release build
artifacts.
* `angular.js` — The non-minified `angular` script.
@@ -145,8 +151,6 @@ artifacts.
* `angular-scenario.js` — The `angular` End2End test runner.
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
* `docs/index.html` — The main page for the documentation.
@@ -154,60 +158,78 @@ artifacts.
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
<a name="webserver"></a>
## Running a Local Development Web Server
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
To debug code and run end-to-end tests, it is often useful to have a local HTTP server. For this purpose, we have
made available a local web server based on Node.js.
1. To start the web server, run:
./nodeserver.sh
grunt webserver
2. To access the local server, go to this website:
http://localhost:8000/
By default, it serves the contents of the `angular` project directory.
By default, it serves the contents of the AngularJS project directory.
<a name="unit-tests"></a>
## Running the Unit Test Suite
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
tests:
Our unit and integration tests are written with Jasmine and executed with Karma. To run all of the
tests once on Chrome run:
1. To start the JSTD server, run:
grunt test:unit
./server.sh
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
2. To capture one or more browsers, go to this website:
grunt test:unit --browsers Opera,Firefox
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
During development it's however more productive to continuously run unit tests every time the source or test files
change. To execute tests in this mode run:
1. To start the Karma server, capture Chrome browser and run unit tests, run:
grunt autotest:jqlite
2. To capture more browsers, open this url in the desired browser (url might be different if you have multiple instance
of Karma running, read Karma's console output for the correct url):
http://localhost:9876/
3. To trigger a test execution, run:
./test.sh
4. To automatically run the test suite each time one or more of the files in the project directory
is changed, you can install `watchr` and then run:
watchr watchr.rb
5. To view the output of each test run, you can tail this log file:
./logs/jstd.log
3. To re-run tests just change any source or test file.
## Running the End2End Test Suite
To learn more about all of the preconfigured Grunt tasks run:
To run the End2End test suite:
grunt --help
## Running the end-to-end Test Suite
To run the E2E test suite:
1. Start the local web server if it's not running already.
grunt webserver
1. Start the local web server.
2. In a browser, go to:
http://localhost:8000/build/docs/docs-scenario.html
The tests are executed automatically.
or in terminal run:
grunt test:end2end
For convenience you can also simply run:
grunt test:e2e
This will start the webserver for you and run the tests.
@@ -216,30 +238,39 @@ To run the End2End test suite:
To create and submit a change:
1. Create a new branch off the master for your changes:
1. <a name="CLA"></a>
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
accepted, the CLA must be signed. It's a quick process, we promise!
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form](http://code.google.com/legal/corporate-cla-v1.0.html).
2. Create a new branch off the master for your changes:
git branch my-fix-branch
2. Check out the branch:
3. Check out the branch:
git checkout my-fix-branch
3. Create your patch, make sure to have plenty of tests (that pass).
4. Create your patch, make sure to have plenty of tests (that pass).
4. Commit your changes:
5. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
please check out our
[commit message conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
and our commit message presubmit hook `validate-commit-msg.js`):
git commit -a
5. Run JavaScript Lint and be sure to address all new warnings and errors:
rake lint
6. Push your branch to Github:
git push origin my-fix-branch
7. In Github, send a pull request to `angular:master`.
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
from the main (upstream) repository:
+24 -19
View File
@@ -2,10 +2,9 @@
@name Downloading
@description
# Including angular scripts from the angular server
The quickest way to get started is to point your html `<script>` tag to a
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
local copy.
# Including angular scripts from the Google CDN
The quickest way to get started is to point your html `<script>` tag to a Google CDN URL.
This way, you don't have to download anything or maintain a local copy.
There are two types of angular script URLs you can point to, one for development and one for
production:
@@ -15,21 +14,25 @@ development.
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
production.
To point your code to an angular script on the angular server, use the following template. This
example points to (non-minified) version 0.10.6:
To point your code to an angular script on the Google CDN server, use the following template. This
example points to the minified version 1.0.2:
<pre>
<!doctype html>
<html ng-app>
<head>
<title>My Angular App</title>
<script src="http://code.angularjs.org/angular-0.10.6.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
</head>
<body>
</body>
</html>
</pre>
Note that only versions 1.0.1 and above are available on the CDN, if you need an earlier version
you can use the <http://code.angularjs.org/> URL which was the previous recommended location for
hosted code source. If you're still using the angular server you should switch to the CDN version
for even faster loading times.
# Downloading and hosting angular files locally
This option is for those who want to work with angular offline, or those who want to host the
@@ -42,29 +45,31 @@ Download the version you want and have fun.
Each directory under <http://code.angularjs.org/> includes the following set of files:
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by
* __`angular.js`__ — This file is non-obfuscated, non-minified, and human-readable by
opening it it any editor or browser. In order to get better error messages during development, you
should always use this non-minified angular script.
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of
`angular-<version>.js` created with the Closure compiler. Use this version for production in order
* __`angular.min.js`__ — This is a minified and obfuscated version of
`angular.js` created with the Closure compiler. Use this version for production in order
to minimize the size of the application that is downloaded by your user's browser.
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released
* __`angular.zip`__ — This is a zip archive that contains all of the files released
for this angular version. Use this file to get everything in a single download.
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
of angular files, make sure that this file is available for download, and that it resides under the
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
* __`angular-mocks.js`__ — This file contains an implementation of mocks that makes
testing angular apps even easier. Your unit/integration test harness should load this file after
`angular-<version>.js` is loaded.
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you
* __`angular-scenario.js`__ — This file is a very nifty JavaScript file that allows you
to write and execute end-to-end tests for angular applications.
* __`docs-<version>`__ — this directory contains all the files that compose the
* __`angular-loader.min.js`__ — Module loader for Angular modules. If you are loading multiple script files containing
Angular modules, you can load them asynchronously and in any order as long as you load this file first. Often the
contents of this file are copy&pasted into the `index.html` to avoid even the initial request to `angular-loader.min.js`.
See [angular-seed](https://github.com/angular/angular-seed/blob/master/app/index-async.html) for an example of usage.
* __`angular-resource.js`__, __`angular-cookies.js`__, etc - extra Angular modules with additional functionality.
* __`docs`__ — this directory contains all the files that compose the
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
our docs, or even more importantly, view the docs offline.
+186 -46
View File
@@ -4,78 +4,218 @@
#FAQ
### Why is this project called "angular"? Why is the namespace called "ng"?
## Questions
Because HTML has angular brackets and "ng" sounds like "angular".
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
### Is <angular/> an HTML5 tag?
Because HTML has Angular brackets and "ng" sounds like "Angular".
No, <angular/> is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two
together.
### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}?
### Is AngularJS a library, framework, plugin or a browser extension?
No, angular is none of these. You don't call its functions, it does not call your functions,
it does not provide a way to manipulate DOM, but does provide primitives to create UI projections
of your data. There are lots of existing widget libraries which you can integrate with angular.
It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
AngularJS fits the definition of a framework the best, even though it's much more lightweight than
a typical framework and that's why many confuse it with a library.
### Do I need to worry about security holes in angular?
AngularJS is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
So it's definitely not a plugin or some other native browser extension.
Like with any technology, angular is not impervious to attack. angular does, however, provide
built-in protection from basic security holes including cross-site scripting and HTML injection
attacks. angular does round-trip escaping on all strings for you.
### Can I download the source, build, and host the angular environment locally?
### Is AngularJS a templating system?
Yes. See instructions in {@link downloading}.
### Is angular a templating system?
At the highest level, angular does look like a just another templating system. But there is one
important reason why angular templating system is different and makes it very good fit for
application development: bidirectional data binding. The template is compiled on the browser and
the compilation step produces a live view. This means you, the developer, don't need to write
At the highest level, Angular does look like a just another templating system. But there is one
important reason why the Angular templating system is different, that makes it very good fit for
application development: bidirectional data binding. The template is compiled in the browser and
the compilation step produces a live view. This means you, the developers, don't need to write
code to constantly sync the view with the model and the model with the view as in other
templating systems.
### What browsers does angular work with?
Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and
above. Note that CSS only works on IE7 and above.
### Do I need to worry about security holes in AngularJS?
### What's angular's performance like?
Like any other technology, AngularJS is not impervious to attack. Angular does, however, provide
built-in protection from basic security holes including cross-site scripting and HTML injection
attacks. AngularJS does round-trip escaping on all strings for you and even offers XSRF protection
for server-side communication.
angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your
app's performance will vary depending on how many bindings you use.
AngularJS was designed to be compatible with other security measures like Content Security Policy
(CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
possible attack vectors and we highly recommended their use.
### How big is the angular bootstrap JS file that I need to include?
The size of the library itself is < 50KB compressed and obfuscated.
### Can I download the source, build, and host the AngularJS environment locally?
### Can I use the open-source Closure Library with angular?
Yes. See instructions in {@link downloading}.
### What browsers does Angular work with?
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
Explorer Compatibility} for more details in supporting legacy IE browsers.
### What's Angular's performance like?
The startup time heavily depends on your network connection, state of the cache, browser used and
available hardware, but typically we measure bootstrap time in tens or hundreds of milliseconds.
The runtime performance will vary depending on the number and complexity of bindings on the page
as well as the speed of your backend (for apps that fetch data from the backend). Just for an
illustration we typically build snappy apps with hundreds or thousands of active bindings.
### How big is the angular.js file that I need to include?
The size of the file is < 29KB compressed and minified.
### Can I use the open-source Closure Library with Angular?
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
in angular.
in Angular.
### Does angular use the jQuery library?
### Does Angular use the jQuery library?
Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library.
If jQuery is not present in your script path, angular falls back on its own implementation of
{@link api/angular.element jQuery lite}. If jQuery is present in the path, angular uses it to
manipulate the DOM.
Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
### What is testability like in angular?
Very testable. It has an integrated dependency injection framework. See
{@link api/angular.module.ng service} for details.
### What is testability like in Angular?
### How can I learn more about angular?
Very testable and designed this way from ground up. It has an integrated dependency injection
framework, provides mocks for many heavy dependencies (server-side communication). See
{@link api/ng service} for details.
Watch the July 28, 2010 talk
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
AJAX Apps}".
### How is angular licensed?
### How can I learn more about Angular?
Watch the July 17, 2012 talk
"{@link http://www.youtube.com/watch?v=1CpiB3Wk25U AngularJS Intro + Dependency Injection}".
### How is Angular licensed?
The MIT License.
### Can I download and use the Angular logo artwork?
Yes! You can find design files in our github repository, under "{@link https://github.com/angular/angular.js/tree/master/images/logo
angular.js/images/logo}"
The logo design is licensed under a "{@link http://creativecommons.org/licenses/by-sa/3.0/
Creative Commons Attribution-ShareAlike 3.0 Unported License}". If you have some other use in mind, contact us.
### How can I get some AngularJS schwag?
We often bring a few t-shirts and stickers to events where we're presenting. If you want to order your own, the folks who
make our schwag will be happy to do a custom run for you, based on our existing template. By using the design they have on file,
they'll waive the setup costs, and you can order any quantity you need.
**Stickers**
Contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
As long as the design stays exactly the same, {@link http://www.stickergiant.com StickerGiant} will give you a reorder discount.
**T-shirts**
Contact sales at {@link http://www.customink.com www.customink.com} and tell them you want some shirts with design name "angularjs",
just like past order #2106371. You'll have to give them your own info for billing and shipping.
As long as the design stays exactly the same, CustomInk won't charge for any set up fees, and they'll give you a reorder discount.
## Common Pitfalls
The Angular support channel (#angularjs on Freenode) sees a number of recurring pitfalls that new users of Angular fall into.
This document aims to point them out before you discover them the hard way.
### DOM Manipulation
Stop trying to use jQuery to modify the DOM in controllers. Really.
That includes adding elements, removing elements, retrieving their contents, showing and hiding them.
Use built-in directives, or write your own where necessary, to do your DOM manipulation.
See below about duplicating functionality.
If you're struggling to break the habit, consider removing jQuery from your app.
Really. Angular has the $http service and powerful directives that make it almost always unnecessary.
Angular's bundled jQLite has a handful of the features most commonly used in writing Angular directives, especially binding to events.
### Trying to duplicate functionality that already exists
There's a good chance that your app isn't the first to require certain functionality.
There are a few pieces of Angular that are particularly likely to be reimplemented out of old habits.
**ng-repeat**
`ng-repeat` gets this a lot.
People try to use jQuery (see above) to add more elements to some container as they're fetched from the server.
No, bad dog.
This is what `ng-repeat` is for, and it does its job very well.
Store the data from the server in an array on your `$scope`, and bind it to the DOM with `ng-repeat`.
**ng-show**
`ng-show` gets this frequently too.
Conditionally showing and hiding things using jQuery is a common pattern in other apps, but Angular has a better way.
`ng-show` (and `ng-hide`) conditionally show and hide elements based on boolean expressions.
Describe the conditions for showing and hiding an element in terms of `$scope` variables:
<div ng-show="!loggedIn">Click <a href="#/login">here</a> to log in</div>
Note also the counterpart `ng-hide` and similar `ng-disabled`.
Note especially the powerful `ng-switch` that should be used instead of several mutually exclusive `ng-show`s.
**ng-class**
`ng-class` is the last of the big three.
Conditionally applying classes to elements is another thing commonly done manually using jQuery.
Angular, of course, has a better way.
You can give `ng-class` a whitespace-separated set of class names, and then it's identical to ordinary `class`.
That's not very exciting, so there's a second syntax:
<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div>
Where you give `ng-class` an object, whose keys are CSS class names and whose values are conditional expressions using `$scope` variables.
The element will then have all the classes whose conditions are truthy, and none of those whose conditions are falsy.
Note also the handy `ng-class-even` and `ng-class-odd`, and the related though somewhat different `ng-style`.
### `$watch` and `$apply`
Angular's two-way data binding is the root of all awesome in Angular.
However, it's not magic, and there are some situations where you need to give it a nudge in the right direction.
When you bind a value to an element in Angular using `ng-model`, `ng-repeat`, etc., Angular creates a `$watch` on that value.
Then whenever a value on a scope changes, all `$watch`es observing that element are executed, and everything updates.
Sometimes, usually when you're writing a custom directive, you will have to define your own `$watch` on a scope value to make the directive react to changes.
On the flip side, sometimes you change a scope value in some code but the app doesn't react to it.
Angular checks for scope variable changes after pieces of your code have finished running; for example, when `ng-click` calls a function on your scope, Angular will check for changes and react.
However, some code is outside of Angular and you'll have to call `scope.$apply()` yourself to trigger the update.
This is most commonly seen in event handlers in custom directives.
### Combining `ng-repeat` with other directives
`ng-repeat` is extremely useful, one of the most powerful directives in Angular.
However the transformation it applies to the DOM is substantial.
Therefore applying other directives (such as `ng-show`, `ng-controller` and others) to the same element as `ng-repeat` generally leads to problems.
If you want to apply a directive to the whole repeat, wrap the repeat in a parent element and put it there.
If you want to apply a directive to each inner piece of the repeat, put it on a child of the element with `ng-repeat`.
### `$rootScope` exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree.
Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app.
For these, you can inject `$rootScope` and set values on it like any other scope.
Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like `ng-show` just like values on your local `$scope`.
Of course, global state sucks and you should use `$rootScope` sparingly, like you would (hopefully) use with global variables in any language.
In particular, don't use it for code, only data.
If you're tempted to put a function on `$rootScope`, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
+24 -129
View File
@@ -2,142 +2,37 @@
@name Getting Started
@description
# Hello World!
We want you to have an easy time while starting to use Angular. We've put together the following steps on your path to
becoming an Angular expert.
A great way for you to get started with AngularJS is to create the tradtional
"Hello World!" app:
1. In your favorite text editor, create an HTML file
(for example, `helloworld.html`).
2. From the __Source__ box below, copy and paste the code into your HTML file.
(Double-click on the source to easily select all.)
3. Open the file in your web browser.
<doc:example>
<doc:source>
Hello {{'World'}}!
</doc:source>
</doc:example>
The resulting web page should look something like the following:
<img class="center" src="img/helloworld.png" border="1">
Now let's take a closer look at that code, and see what is going on behind
the scenes.
The `ng-app` tags tells angular to process the entire HTML page and bootstrap the app when the page
is loaded:
<pre>
<html ng-app>
</pre>
The next line downloads the angular script:
<pre>
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
</pre>
(For details on what happens when angular processes an HTML page,
see {@link guide/dev_guide.bootstrap Bootstrap}.)
Finally, this line in the `<body>` of the page is the template that describes
how to display our greeting in the UI:
<pre>
Hello {{'World'}}!
</pre>
Note the use of the double curly brace markup (`{{ }}`) to bind the expression to
the greeting text. Here the expression is the string literal 'World'.
Next let's look at a more interesting example, that uses AngularJS to
bind a dynamic expression to our greeting text.
# Hello AngularJS World!
This example demonstrates angular's two-way data binding:
1. Edit the HTML file you created in the "Hello World!" example above.
2. Replace the contents of `<body>` with the code from the __Source__ box below.
3. Refresh your browser window.
<doc:example>
<doc:source>
Your name: <input type="text" ng-model="yourname" placeholder="World">
<hr>
Hello {{yourname || 'World'}}!
</doc:source>
</doc:example>
After the refresh, the page should look something like this:
<img class="left" src="img/helloworld_2way.png" border="1" >
These are some of the important points to note from this example:
* The text input {@link guide/directive directive}
is bound to a model variable called `yourname`.
* The double curly braces notation binds the `yourname` model to the greeting text.
* You did not need to explicitly register an event listener or define an event handler for events!
Now try typing your name into the input box, and notice the immediate change to
the displayed greeting. This demonstrates the concept of angular's
{@link guide/dev_guide.templates.databinding bi-directional data binding}. Any changes to the input
field are immediately
reflected in the model (one direction), and any changes to the model are
reflected in the greeting text (the other direction).
1. Read the {@link guide/concepts conceptual overview}.<br/>Understand Angular's vocabulary and how all the Angular
components work together.
1. Do the {@link tutorial/ AngularJS Tutorial}.<br/>Walk end-to-end through building and application complete with tests
on top of a node.js web server. Covers every major AngularJS feature and show you how to set up your development
environment.
1. Download or clone the {@link https://github.com/angular/angular-seed Seed App project template}.<br/>Gives you a
starter app with a directory layout, test harness, and scripts to begin building your application.
# Anatomy Of An Angular App
#Further Steps
This section describes the 3 parts of an angular app, and explains how they map to the
Model-View-Controller design pattern:
##Watch Videos
## Templates
If you havent had a chance to watch the videos from the homepage, please check out:
* {@link http://www.youtube.com/watch?v=WuiHuZq_cg4&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Introduction to AngularJS}
* {@link http://www.youtube.com/watch?v=Yg-R1gchccg&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Creating Directives}
* {@link http://www.youtube.com/watch?v=IRelx4-ISbs&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Communicating with Servers}
Templates, which you write in HTML and CSS, serve as the View. You add elements, attributes, and
markup to HTML, which serve as instructions to the angular compiler. The angular compiler is fully
extensible, meaning that with angular you can build your own declarative language on top of HTML!
And visit our {@link http://www.youtube.com/user/angularjs YouTube channel} for more AngularJS video presentations and
tutorials.
##Subscribe
## Application Logic and Behavior
* Subscribe to the {@link http://groups.google.com/forum/?fromgroups#!forum/angular mailing list}. Ask questions here!
* Follow us on {@link https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F&region=follow_link&screen_name=angularjs&source=followbutton&variant=2.0 Twitter}
* Add us to your circles on {@link https://plus.google.com/110323587230527980117/posts Google+}
Application Logic and Behavior, which you define in JavaScript, serve as the Controller. With
angular (unlike with standard AJAX applications) you don't need to write additional listeners or
DOM manipulators, because they are built-in. This feature makes your application logic very easy to
write, test, maintain, and understand.
##Read more
## Data
The Model is referenced from properties on {@link guide/dev_guide.scopes angular scope objects}.
The data in your model could be Javascript objects, arrays, or primitives, it doesn't matter. What
matters is that these are all referenced by the scope object.
Angular employs scopes to keep your data model and your UI in sync. Whenever something occurs to
change the state of the model, angular immediately reflects that change in the UI, and vice versa.
The following illustration shows the parts of an angular application and how they work together:
<img class="left" src="img/angular_parts.png" border="0" />
In addition, angular comes with a set of Services, which have the following properties:
* The services provided are very useful for building web applications.
* You can extend and add application-specific behavior to services.
* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction.
# Where To Go Next
* If you like what you've learned so far, you should definitely check out our awesome {@link
tutorial/ Tutorial}, which walks you through the process of building real apps with AngularJS.
* For further explanations and examples of the AngularJS concepts presented on this page, see the
{@link guide/index Developer Guide}.
* For additional hands-on examples of using AngularJS, including more source code that you can
copy and paste into your own pages, take a look through the {@link cookbook/ Cookbook}.
The AngularJS documentation includes the {@link guide/index Developer Guide} covering concepts and the
{@link api/ API Reference} for syntax and usage.
+93 -124
View File
@@ -2,41 +2,42 @@
@name Tutorial
@description
A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
the construction of an AngularJS web app. The app you will build is a catalog that displays a list
of Android devices, lets you filter the list to see only devices that interest you, and then view
details for any device.
<div class="tutorial-page tutorial-page-no-nav">
A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
the construction of an AngularJS web app. The app you will build is a catalog that displays a list
of Android devices, lets you filter the list to see only devices that interest you, and then view
details for any device.
<img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413">
<img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413">
Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions
or plug-ins. As you work through the tutorial, you will:
Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions
or plug-ins. As you work through the tutorial, you will:
* See examples of how to use client-side data binding and dependency injection to build dynamic
views of data that change immediately in response to user actions.
* See how Angular creates listeners on your data without the need for DOM manipulation.
* Learn a better, easier way to test your web apps.
* Learn how to use Angular services to make common web tasks, such as getting data into your app,
easier.
* See examples of how to use client-side data binding and dependency injection to build dynamic
views of data that change immediately in response to user actions.
* See how Angular creates listeners on your data without the need for DOM manipulation.
* Learn a better, easier way to test your web apps.
* Learn how to use Angular services to make common web tasks, such as getting data into your app,
easier.
And all of this works in any browser without modification to the browser!
And all of this works in any browser without modification to the browser!
When you finish the tutorial you will be able to:
When you finish the tutorial you will be able to:
* Create a dynamic application that works in any browser.
* Define the differences between Angular and common JavaScript frameworks.
* Understand how data binding works in AngularJS.
* Use the angular-seed project to quickly boot-strap your own projects.
* Create and run tests.
* Identify resources for learning more about AngularJS.
* Create a dynamic application that works in any browser.
* Define the differences between Angular and common JavaScript frameworks.
* Understand how data binding works in AngularJS.
* Use the angular-seed project to quickly boot-strap your own projects.
* Create and run tests.
* Identify resources for learning more about AngularJS.
The tutorial guides you through the entire process of building a simple application, including
writing and running unit and end-to-end tests. Experiments at the end of each step provide
suggestions for you learn more about AngularJS and the application you are building.
The tutorial guides you through the entire process of building a simple application, including
writing and running unit and end-to-end tests. Experiments at the end of each step provide
suggestions for you to learn more about AngularJS and the application you are building.
You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
really digging into it. If you're looking for a shorter introduction to AngularJS, check out the
{@link misc/started Getting Started} document.
You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
really digging into it. If you're looking for a shorter introduction to AngularJS, check out the
{@link misc/started Getting Started} document.
@@ -44,105 +45,73 @@ really digging into it. If you're looking for a shorter introduction to AngularJ
# Working with the code
# Working with the code
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
environment. Options for working with the tutorial are to use the Git versioning system for source
code management or to use scripts that copy snapshots of project files into your workspace
(`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your
computer for your preferred option.
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
environment. The tutorial relies on the use of Git versioning system for source code management.
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
and follow the instructions for setting up your computer.
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the
following command in a terminal window:</p>
<pre>java -version</pre>
<p>You will need Java to run unit tests.</p></li>
<li><p>Download Git from the <a href="http://git-scm.com/download">Git</a> site.</p>
<p>You can build Git from source or use the pre-compiled package.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the <code>angular-phonecat</code> directory in your current
directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can <a
href="http://nodejs.org/#download">install node.js</a>. Use <code>node</code> to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
don't have it already:</p>
<pre>npm install -g karma</pre>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the <code>angular-phonecat</code> directory in your current
directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Java to run unit tests, so run the following command to verify that you
have <a href="http://java.com/">Java</a> installed and that the <code>java</code> executable is on
your <code>PATH</code>.</p>
<pre>java -version</pre>
<p></p></li>
<li><p>Install msysGit from <a href="http://git-scm.com/download">the Git</a> site.</p></li>
<li><p>Open msysGit bash and clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
<li><p>Change your current directory to angular-phonecat.</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p>
<p>You should run all <code>git</code> commands from msysGit bash.</p>
<p>Other commands like <code>test-server.bat</code> or <code>test.bat</code> should be
executed from the Windows command line.</li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
don't have it already:</p>
<pre>npm install -g karma</pre>
</li>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
<li><p>Change your current directory to angular-phonecat.</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p>
<p>You should run all <code>git</code> commands from Git bash.</p>
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
executed from the Windows command line.</li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux">
<ol>
<li><p>You need Java to run unit tests, so verify that you have <a
href="http://java.com/">Java</a> installed by running the following command in a terminal
window:</p>
<pre>java -version</pre>
<li><p>Download the <a href="http://code.angularjs.org/angular-phonecat/">zip archive</a>
containing all of the files and unzip them into the [tutorial-dir] directory</p>.</li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from your
<code>sandbox</code> directory.</p></li>
<li><p>You need an http server running on your system and Mac and Linux machines typically
have Apache pre-installed. If you don't have an http server installed, you can <a
href="http://nodejs.org/#download">install node.js</a> and use it to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
The last thing to do is to make sure your computer has a web browser and a good text editor
installed. Now, let's get some cool stuff done!
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows">
<ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
<code>java</code> executable is on your <code>PATH</code> by running the following command in the
Windows command line:</p>
<pre>java -version</pre>
<p>You need Java to run unit tests, so download the <a
href="http://code.angularjs.org/angular-phonecat/">zip archive</a> that contains all of the files
and unzip the files into the [tutorial-dir] directory</p></li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from this directory.</p></li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
</divs>
The last thing to do is to make sure your computer has a web browser and a good text editor
installed. Now, let's get some cool stuff done!
{@link step_00 <span class="btn btn-primary">Get Started!</span>}
{@link step_00 <span class="btn btn-primary">Get Started!</span>}
</div>
+15 -78
View File
@@ -46,7 +46,7 @@ directory.</li>
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
<ol>
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p>
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
<pre>git checkout -f step-0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
@@ -74,70 +74,6 @@ directory.</li>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux" value="snapshotUnix">
<ol>
<li><p>In the angular-phonecat directory, run this command:</p>
<pre>./goto_step.sh 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run
<code>./scripts/web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows" value="snapshotWin">
<ol>
<li><p>Open windows command line and run this command (in the angular-phonecat directory):</p>
<pre>goto_step.bat 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run <code>node
scripts\web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
</div>
@@ -173,10 +109,11 @@ __`app/index.html`:__
<html ng-app>
The `ng-app` attribute is represents an Angular directive used to flag an element which Angular
should consider to be the root element of our application. This gives application developers the
freedom to tell Angular if the entire html page or only a portion of it should be treated as the
Angular application.
The `ng-app` attribute represents an Angular directive (named `ngApp`; Angular uses
`name-with-dashes` for attribute names and `camelCase` for the corresponding directive name)
used to flag an element which Angular should consider to be the root element of our application.
This gives application developers the freedom to tell Angular if the entire html page or only a
portion of it should be treated as the Angular application.
* AngularJS script tag:
@@ -184,41 +121,41 @@ __`app/index.html`:__
This code downloads the `angular.js` script and registers a callback that will be executed by the
browser when the containing HTML page is fully downloaded. When the callback is executed, Angular
looks for the {@link api/angular.module.ng.$compileProvider.directive.ngApp ngApp} directive. If
looks for the {@link api/ng.directive:ngApp ngApp} directive. If
Angular finds the directive, it will bootstrap the application with the root of the application DOM
being the element on which the `ngApp` directive was defined.
* Double-curly binding with an expression:
Nothing here {{'yet' + '!'}}`
Nothing here {{'yet' + '!'}}
This line demonstrates the core feature of Angular's templating capabilities a binding, denoted
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
The binding tells Angular, that it should evaluate an expression and insert the result into the
The binding tells Angular that it should evaluate an expression and insert the result into the
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
binding will result in efficient continuous updates whenever the result of the expression
evaluation changes.
{@link guide/dev_guide.expressions Angular expression} is a JavaScript-like code snippet that is
{@link guide/expression Angular expression} is a JavaScript-like code snippet that is
evaluated by Angular in the context of the current model scope, rather than within the scope of
the global context (`window`).
As expected, once this template is processed by Angular, the html page will contains text:
As expected, once this template is processed by Angular, the html page contains the text:
"Nothing here yet!".
## Bootstrapping AngularJS apps
Bootstrapping AngularJS apps automatically using the `ngApp` directive is very easy and suitable
for most cases. In advanced cases, such as when using script loaders, you can use
{@link guide/dev_guide.bootstrap.manual_bootstrap imperative / manual way} to bootstrap the app.
{@link guide/bootstrap imperative / manual way} to bootstrap the app.
There are 3 important things that happen during the app bootstrap:
1. The {@link api/angular.module.AUTO.$injector injector} that will be used for dependency injection
1. The {@link api/AUTO.$injector injector} that will be used for dependency injection
within this app is created.
2. The injector will then create the {@link api/angular.module.ng.$rootScope root scope} that will
2. The injector will then create the {@link api/ng.$rootScope root scope} that will
become the context for the model of our application.
3. Angular will then "compile" the DOM starting at the `ngApp` root element, processing any
@@ -226,7 +163,7 @@ There are 3 important things that happen during the app bootstrap:
Once an application is bootstrapped, it will then wait for incoming browser events (such as mouse
click, key press or incoming HTTP response) that might change the model. Once such event occurs,
click, key press or incoming HTTP response) that might change the model. Once such an event occurs,
Angular detects if it caused any model changes and if changes are found, Angular will reflect them
in the view by updating all of the affected bindings.
+2 -2
View File
@@ -5,8 +5,8 @@
<ul doc-tutorial-nav="1"></ul>
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
page and then examine how we can turn this HTML code into a template that angular will use to
In order to illustrate how Angular enhances standard HTML, you will create a purely *static* HTML
page and then examine how we can turn this HTML code into a template that Angular will use to
dynamically display the same result with any set of data.
In this step you will add some basic information about two cell phones to an HTML page.
+19 -25
View File
@@ -52,8 +52,8 @@ __`app/index.html`:__
</pre>
We replaced the hard-coded phone list with the
{@link api/angular.module.ng.$compileProvider.directive.ngRepeat ngRepeat directive} and two
{@link guide/dev_guide.expressions Angular expressions} enclosed in curly braces:
{@link api/ng.directive:ngRepeat ngRepeat directive} and two
{@link guide/expression Angular expressions} enclosed in curly braces:
`{{phone.name}}` and `{{phone.snippet}}`:
* The `ng-repeat="phone in phones"` statement in the `<li>` tag is an Angular repeater. The
@@ -61,7 +61,7 @@ repeater tells Angular to create a `<li>` element for each phone in the list usi
tag as the template.
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
bindings. As opposed to evaluating constants, these expression are refering to our application
bindings. As opposed to evaluating constants, these expressions are referring to our application
model, which was set up in our `PhoneListCtrl` controller.
<img class="diagram" src="img/tutorial/tutorial_02.png">
@@ -96,11 +96,11 @@ as follows:
* `PhoneListCtrl` — the name of our controller function (located in the JavaScript file
`controllers.js`), matches the value of the
{@link api/angular.module.ng.$compileProvider.directive.ngController ngController} directive located
{@link api/ng.directive:ngController ngController} directive located
on the `<body>` tag.
* The phone data is then attached to the *scope* (`$scope`) that was injected into our controller
function. The controller scope is a prototypically descendant of the root scope that was created
function. The controller scope is a prototypical descendant of the root scope that was created
when the application bootstrapped. This controller scope is available to all bindings located within
the `<body ng-controller="PhoneListCtrl">` tag.
@@ -110,7 +110,7 @@ contained in the template, data model, and controller, to keep models and views
sync. Any changes made to the model are reflected in the view; any changes that occur in the view
are reflected in the model.
To learn more about Angular scopes, see the {@link api/angular.module.ng.$rootScope.Scope angular scope documentation}.
To learn more about Angular scopes, see the {@link api/ng.$rootScope.Scope angular scope documentation}.
## Tests
@@ -146,31 +146,26 @@ http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
The angular-seed project is pre-configured to run all unit tests using {@link
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
http://karma-runner.github.io/ Karma}. To run the test, do the following:
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
`./scripts/test-server.sh` to start the test web server.
`./scripts/test.sh` to start the Karma server (the config file necessary to start the server
is located at `./config/karma.conf.js`).
2. Open a new browser window and navigate to {@link http://localhost:9876}.
2. Karma will start a new instance of Chrome browser automatically. Just ignore it and let it run in
the background. Karma will use this browser for test execution.
3. Choose "Capture this browser in strict mode".
3. You should see the following or similar output in the terminal:
At this point, you can leave this window open and forget about it. JsTestDriver will use it to
execute the tests and report the results in the terminal.
4. Execute the test by running `./scripts/test.sh`
You should see the following or similar output:
Chrome: Runner reset.
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
info: Karma server started at http://localhost:9876/
info (launcher): Starting browser "Chrome"
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
Yay! The test passed! Or not...
Note: If you see errors after you run the test, close the browser window and go back to the
terminal and kill the script, then repeat the procedure above.
4. To rerun the tests, just change any of the source or test files. Karma will notice the change
and will rerun the tests for you. Now isn't that sweet?
# Experiments
@@ -198,8 +193,7 @@ execute the tests and report the results in the terminal.
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
</table>
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
`./scripts/test.sh` script.
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`.
# Summary
+21 -14
View File
@@ -54,14 +54,14 @@ __`app/index.html`:__
</div>
</pre>
We added a standard HTML `<input>` tag and used angular's
{@link api/angular.module.ng.$filter.filter $filter} function to process the input for the
`ngRepeate` directive.
We added a standard HTML `<input>` tag and used Angular's
{@link api/ng.filter:filter $filter} function to process the input for the
{@link api/ng.directive:ngRepeat ngRepeat} directive.
This lets a user enter search criteria and immediately see the effects of their search on the phone
list. This new code demonstrates the following:
* Data-binding. This is one of the core features in Angular. When the page loads, Angular binds the
* Data-binding: This is one of the core features in Angular. When the page loads, Angular binds the
name of the input box to a variable of the same name in the data model and keeps the two in sync.
In this code, the data that a user types into the input box (named __`query`__) is immediately
@@ -71,7 +71,7 @@ the DOM to reflect the current state of the model.
<img class="diagram" src="img/tutorial/tutorial_03.png">
* Use of `filter` filter. The {@link api/angular.module.ng.$filter.filter filter} function uses the
* Use of the `filter` filter: The {@link api/ng.filter:filter filter} function uses the
`query` value to create a new array that contains only those records that match the `query`.
`ngRepeat` automatically updates the view in response to the changing number of phones returned
@@ -122,6 +122,11 @@ To run the end-to-end test, open one of the following in a new browser tab:
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
Previously we've seen how Karma can be used to execute unit tests. Well, it can also run the
end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests are slow, so unlike
with unit tests, Karma will exit after the test run and will not automatically rerun the test
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
This test verifies that the search box and the repeater are correctly wired together. Notice how
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
really is that easy to set up any functional, readable, end-to-end test.
@@ -148,12 +153,12 @@ and title elements:
<html ng-app ng-controller="PhoneListCtrl">
Be sure to *remove* the `ng-controller` declaration from the body element.
Be sure to __remove__ the `ng-controller` declaration from the body element.
While using double curlies works fine in within the title element, you might have noticed that
While using double curlies works fine within the title element, you might have noticed that
for a split second they are actually displayed to the user while the page is loading. A better
solution would be to use the {@link api/angular.module.ng.$compileProvider.directive.ngBind
ngBind} or {@link api/angular.module.ng.$compileProvider.directive.ngBindTemplate
solution would be to use the {@link api/ng.directive:ngBind
ngBind} or {@link api/ng.directive:ngBindTemplate
ngBindTemplate} directives, which are invisible to the user while the page is loading:
<title ng-bind-template="Google Phone Gallery: {{query}}">Google Phone Gallery</title>
@@ -176,12 +181,14 @@ ngBindTemplate} directives, which are invisible to the user while the page is lo
Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content
with the `query` binding.
with the `query` binding, prefixed by "Current filter:". For instance:
* Add a `pause()` statement into an end-to-end test and rerun it. You'll see the runner pause; this
gives you the opportunity to explore the state of your application while it is displayed in the
browser. The app is live! You can change the search query to prove it. Notice how useful this is
for troubleshooting end-to-end tests.
<div id="status">Current filter: {{query}}</div>
* Add a `pause()` statement inside of an end-to-end test and rerun it. You'll see the runner pause;
this gives you the opportunity to explore the state of your application while it is displayed in
the browser. The app is live! You can change the search query to prove it. Notice how useful this
is for troubleshooting end-to-end tests.
# Summary
+7 -11
View File
@@ -47,7 +47,7 @@ two provided sorting options.
<img class="diagram" src="img/tutorial/tutorial_04.png">
* We then chained the `filter` filter with {@link api/angular.module.ng.$filter.orderBy `orderBy`}
* We then chained the `filter` filter with {@link api/ng.filter:orderBy `orderBy`}
filter to further process the input into the repeater. `orderBy` is a filter that takes an input
array, copies it and reorders the copy which is then returned.
@@ -63,7 +63,7 @@ necessary!
## Controller
__`app/js/controller.js`:__
__`app/js/controllers.js`:__
<pre>
function PhoneListCtrl($scope) {
$scope.phones = [
@@ -103,7 +103,7 @@ to the model.
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
the unit test first.
__`test/unit/controllerSpec.js`:__
__`test/unit/controllersSpec.js`:__
<pre>
describe('PhoneCat controllers', function() {
@@ -134,13 +134,9 @@ The unit test now verifies that the default ordering property is set.
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
shared by all tests in the parent `describe` block.
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
following output.
You should now see the following output in the Karma tab:
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
Let's turn our attention to the end-to-end test.
@@ -168,8 +164,8 @@ __`test/e2e/scenarios.js`:__
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
`runner.html` to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
Angular's server}.
+21 -21
View File
@@ -6,8 +6,8 @@
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
from our server using one of angular's built-in {@link api/angular.module.ng services} called {@link
api/angular.module.ng.$http $http}. We will use angular's {@link guide/dev_guide.di dependency
from our server using one of angular's built-in {@link api/ng services} called {@link
api/ng.$http $http}. We will use angular's {@link guide/di dependency
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
@@ -22,7 +22,7 @@ GitHub}:
## Data
The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones
The `app/phones/phones.json` file in your project is a dataset that contains a larger list of phones
stored in the JSON format.
Following is a sample of the file:
@@ -42,12 +42,12 @@ Following is a sample of the file:
## Controller
We'll use angular's {@link api/angular.module.ng.$http $http} service in our controller to make an HTTP
We'll use angular's {@link api/ng.$http $http} service in our controller to make an HTTP
request to your web server to fetch the data in the `app/phones/phones.json` file. `$http` is just
one of several built-in {@link api/angular.module.ng angular services} that handle common operations
one of several built-in {@link api/ng angular services} that handle common operations
in web apps. Angular injects these services for you where you need them.
Services are managed by angular's {@link guide/dev_guide.di DI subsystem}. Dependency injection
Services are managed by angular's {@link guide/di DI subsystem}. Dependency injection
helps to make your web apps both well-structured (e.g., separate components for presentation, data,
and control) and loosely coupled (dependencies between components are not resolved by the
components themselves, but by the DI subsystem).
@@ -71,7 +71,7 @@ relative to our `index.html` file). The server responds by providing the data in
browser and our app they both look the same. For the sake of simplicity we used a json file in this
tutorial.)
The `$http` service returns a {@link api/angular.module.ng.$q promise object} with a `success`
The `$http` service returns a {@link api/ng.$q promise object} with a `success`
method. We call this method to handle the asynchronous response and assign the phone data to the
scope controlled by this controller, as a model called `phones`. Notice that angular detected the
json response and parsed it for us!
@@ -104,7 +104,7 @@ to avoid any possible naming collisions.
Since angular infers the controller's dependencies from the names of arguments to the controller's
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
minified as well, and the dependency injector would not being able to identify services correctly.
minified as well, and the dependency injector would not be able to identify services correctly.
To overcome issues caused by minification, just assign an array with service identifier strings
into the `$inject` property of the controller function, just like the last line in the snippet
@@ -138,6 +138,9 @@ describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
var scope, ctrl, $httpBackend;
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('phones/phones.json').
@@ -155,24 +158,24 @@ use to access and configure the injector.
We created the controller in the test environment, as follows:
* We used the `inject` helper method to inject instances of
{@link api/angular.module.ng.$rootScope $rootScope},
{@link api/angular.module.ng.$controller $controller} and
{@link api/angular.module.ng.$httpBackend $httpBackend} services into the Jasmine's `beforeEach`
{@link api/ng.$rootScope $rootScope},
{@link api/ng.$controller $controller} and
{@link api/ng.$httpBackend $httpBackend} services into the Jasmine's `beforeEach`
function. These instances come from an injector which is recreated from scratch for every single
test. This guarantees that each test starts from a well known starting point and each test is
isolated from the work done in other tests.
* We created a new scope for our controller by calling `$rootScope.$new()`
* We called `scope.$new(PhoneListCtrl)` to get Angular to create the child scope associated with
the `PhoneListCtrl` controller.
* We called the injected `$controller` function passing the `PhoneListCtrl` function and the created
scope as parameters.
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
incoming request from the controller. To do this we:
* Request `$httpBackend` service to be injected into our `beforeEach` function. This is a mock
mock version of the service that in production environment facilitates all XHR and JSONP requests.
version of the service that in a production environment facilitates all XHR and JSONP requests.
The mock version of this service allows you to write tests without having to deal with
native APIs and the global state associated with them — both of which make testing a nightmare.
@@ -180,7 +183,7 @@ native APIs and the global state associated with them — both of which make tes
HTTP request and tell it what to respond with. Note that the responses are not returned until we call
the `$httpBackend.flush` method.
Now, we will make assertions to verify that the `phones` model doesn't exist on the scope, before
Now, we will make assertions to verify that the `phones` model doesn't exist on `scope` before
the response is received:
<pre>
@@ -208,13 +211,10 @@ Finally, we verify that the default value of `orderProp` is set correctly:
});
</pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
You should now see the following output in the Karma tab:
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
# Experiments
+12 -7
View File
@@ -61,11 +61,11 @@ now-familiar double-curly brace binding in the `href` attribute values. In step
the element attribute.
We also added phone images next to each record using an image tag with the {@link
api/angular.module.ng.$compileProvider.directive.ngSrc ngSrc} directive. That directive prevents the
api/ng.directive:ngSrc ngSrc} directive. That directive prevents the
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
Using `ngSrc` (`ng-src`) prevents the browser from making an http request to an invalid location.
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
## Test
@@ -84,10 +84,11 @@ __`test/e2e/scenarios.js`__:
We added a new end-to-end test to verify that the app is generating correct links to the phone
views that we will implement in the upcoming steps.
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
angular's server}.
Angular's server}.
# Experiments
@@ -96,11 +97,15 @@ or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
`/app/{{phone.imageUrl}}`).
The issue here is that the browser will fire a request for that invalid image address as soon as
it hits the `img` tag, which is before Angular has a chance to evaluate the expression and inject
the valid address.
# Summary
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about angular
layout templates and how angular makes it easy to create applications that have multiple views.
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about Angular
layout templates and how Angular makes it easy to create applications that have multiple views.
<ul doc-tutorial-nav="6"></ul>
+23 -22
View File
@@ -19,7 +19,7 @@ detail page is displayed.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-6...step-7
GitHub}:
GitHub}.
## Multiple Views, Routing and Layout Template
@@ -35,9 +35,9 @@ template into what we call a "layout template". This is a template that is commo
our application. Other "partial templates" are then included into this layout template depending on
the current "route" — the view that is currently displayed to the user.
Application routes in angular are declared via the
{@link api/angular.module.ng.$routeProvider $routeProvider}, which is the provider of the
{@link api/angular.module.ng.$route $route service}. This service makes it easy to wire together
Application routes in Angular are declared via the
{@link api/ng.$routeProvider $routeProvider}, which is the provider of the
{@link api/ng.$route $route service}. This service makes it easy to wire together
controllers, view templates, and the current
URL location in the browser. Using this feature we can implement {@link
http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize the browser's
@@ -46,8 +46,8 @@ history (back and forward navigation) and bookmarks.
### A Note About DI, Injector and Providers
As you noticed the dependency injection is the core feature of AngularJS, so it's important for you
to understand a thing or two about how it works.
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} (DI) is the core feature of
AngularJS, so it's important for you to understand a thing or two about how it works.
When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
this app. The injector itself doesn't know anything about what `$http` or `$route` services do, in
@@ -56,9 +56,9 @@ module definitions. The sole responsibilities of the injector are to load specif
definition(s), register all service providers defined in these modules and when asked inject
a specified function with dependencies (services) that it lazily instantiates via their providers.
Providers are objects that provide (create) instances of services and expose configuration apis
Providers are objects that provide (create) instances of services and expose configuration APIs
that can be used to control the creation and runtime behavior of a service. In case of the `$route`
service, the `$routeProvider` exposes apis that allow you to define routes for your application.
service, the `$routeProvider` exposes APIs that allow you to define routes for your application.
Angular modules solve the problem of removing global state from the application and provide a way
of configuring the injector. As opposed to AMD or require.js modules, Angular modules don't try to
@@ -72,15 +72,15 @@ __`app/js/app.js`:__
angular.module('phonecat', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {template: 'partials/phone-list.html', controller: PhoneListCtrl}).
when('/phones/:phoneId', {template: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl}).
when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
otherwise({redirectTo: '/phones'});
}]);
</pre>
In order to configure our application with routes, we need to create a module for our application.
We call this module `phonecatApp` and using the `config` api we request the `$routeProvider` to be
injected into our config function and use `$routeProvider.when` api to define our routes.
We call this module `phonecat` and using the `config` API we request the `$routeProvider` to be
injected into our config function and use `$routeProvider.when` API to define our routes.
Note that during the injector configuration phase, the providers can be injected as well, but they
will not be available for injection once the injector is created and starts creating service
@@ -104,24 +104,24 @@ the browser address doesn't match either of our routes.
Note the use of the `:phoneId` parameter in the second route declaration. The `$route` service uses
the route declaration — `'/phones/:phoneId'` — as a template that is matched against the current
URL. All variables defined with the `:` notation are extracted into the
{@link api/angular.module.ng.$routeParams $routeParams} object.
{@link api/ng.$routeParams $routeParams} object.
In order for our application to bootstrap with our newly created module we'll also need to specify
the module name as the value of the {@link api/angular.module.ng.$compileProvider.directive.ngApp ngApp}
the module name as the value of the {@link api/ng.directive:ngApp ngApp}
directive:
__`app/index.html`:__
<pre>
<!doctype html>
<html ng-app="phonecat">
<html lang="en" ng-app="phonecat">
...
</pre>
## Controllers
__`app/js/controller.js`:__
__`app/js/controllers.js`:__
<pre>
...
function PhoneDetailCtrl($scope, $routeParams) {
@@ -134,17 +134,18 @@ function PhoneDetailCtrl($scope, $routeParams) {
## Template
The `$route` service is usually used in conjunction with the {@link api/angular.module.ng.$compileProvider.directive.ngView
The `$route` service is usually used in conjunction with the {@link api/ng.directive:ngView
ngView} directive. The role of the `ngView` directive is to include the view template for the current
route into the layout template, which makes it a perfect fit for our `index.html` template.
__`app/index.html`:__
<pre>
<html ng-app="phonecat">
<html lang="en" ng-app="phonecat">
<head>
...
<script src="lib/angular/angular.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
</head>
<body>
@@ -155,7 +156,7 @@ __`app/index.html`:__
</pre>
Note that we removed most of the code in the `index.html` template and replaced it with a single
line containing a div with `ng-view` attribute. The code that we removed was placed into the
line containing a div with the `ng-view` attribute. The code that we removed was placed into the
`phone-list.html` template:
__`app/partials/phone-list.html`:__
@@ -231,10 +232,10 @@ to various URLs and verify that the correct view was rendered.
</pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
angular's server}.
Angular's server}.
# Experiments

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