Compare commits

..

290 Commits

Author SHA1 Message Date
Brian Ford 7bcaf39437 docs(changelog): release notes for 1.3.0-beta.6 expedient-caffeination 2014-04-21 15:57:08 -07:00
Simon Taranto 2da94a701b docs(tutorial): update step_07.ngdoc
Closes #7169
2014-04-21 15:32:23 -07:00
ttam3d0 5ce17efbbd docs(tutorial/step_03): sync markup with angular-phonecat
Update from Bootstrap 2.3 to 3.1 changed "span" to "col" tags

Closes #7172
2014-04-21 15:22:58 -07:00
Amin Ogarrio b1559be5cf docs(tutorial): fix typos in examples
The phonecatApp and phonecatAnimations modules have a dot where a semicolon should be at the end of the sentence

Closes #7167
2014-04-21 15:09:04 -07:00
Thomas Junghans 8570585692 docs(tutorial): update step_11.ngdoc
Change toEqual to toEqualData in the test 'should create "phones" model with 2 phones fetched from xhr'
to make test more consistent.

Closes #7182
2014-04-21 15:01:55 -07:00
Igor Minar 9178c318e1 docs(guide/forms): fix quotes around updateOn that broke ngModelOptions example 2014-04-21 14:53:04 -07:00
Igor Minar 546cb429d9 perf($interpolate): speed up interpolation by recreating watchGroup approach
This change undoes the use of watchGroup by code that uses $interpolate, by
moving the optimizations into the $interpolate itself. While this is not ideal,
it means that we are making the existing api faster rather than require people
to use $interpolate differently in order to benefit from the speed improvements.
2014-04-21 11:48:38 -07:00
Igor Minar 1db3b8cfb7 refactor($interpolate): attempt to remove hacky code due to $interpolation perf improvements 2014-04-21 11:47:23 -07:00
rodyhaddad 0ebfa0d112 perf($compile): watch interpolated expressions individually 2014-04-21 11:12:35 -07:00
rodyhaddad 88c2193c71 refactor($interpolate): split .parts into .expressions and .separators
BREAKING CHANGE: the function returned by $interpolate
no longer has a `.parts` array set on it.
It has been replaced by two arrays:
* `.expressions`, an array of the expressions in the
  interpolated text. The expressions are parsed with
  $parse, with an extra layer converting them to strings
  when computed
* `.separators`, an array of strings representing the
  separations between interpolations in the text.
  This array is **always** 1 item longer than the
  `.expressions` array for easy merging with it
2014-04-21 11:12:35 -07:00
rodyhaddad 21f9316338 feat(Scope): add $watchGroup method for observing a set of expressions
Given an array of expressions, if any one expression changes then the listener function fires
with an arrays of old and new values.

$scope.watchGroup([expression1, expression2, expression3], function(newVals, oldVals) {
 // newVals and oldVals are arrays of values corresponding to expression1..3
 ...
});

Port of angular/angular.dart@a3c31ce1dd
2014-04-21 11:12:35 -07:00
Igor Minar 8d0cb30688 chore(jshint): add jshint for the test/ folder 2014-04-18 16:33:03 -07:00
Igor Minar 45c356586b chore(Scope): name the $watch deregistration function as 2014-04-18 16:32:07 -07:00
jerryfan 02fcac5e04 docs(tutorial/step_12): fix grammar 2014-04-18 18:38:37 -04:00
Caitlin Potter 64a3f42f14 style(input): fix trailing whitespace
Oops. I blame vim for this little accident.
2014-04-18 18:13:53 -04:00
Caitlin Potter ff428e7283 fix(input): don't dirty model when input event triggered due to placeholder change
Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.

It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.

Closes #2614
Closes #5960
2014-04-18 17:47:25 -04:00
Janas Page a990078173 docs(form.FormController): fix grammar 2014-04-18 16:42:27 -04:00
Chris Wheatley f0407d2aa0 docs(ngMock): grammar fix
Small grammar fix for mock $httpBackend documentation.
2014-04-18 15:41:26 -04:00
Caitlin Potter 49e7c32bb4 fix($location): fix and test html5Mode url-parsing algorithm for legacy browsers
This CL fixes problems and adds test cases for changes from #6421. Changes
include fixing the algorithm for preprocessing href attribute values, as
well as supporting xlink:href attributes. Credit for the original URL
parsing algorithm still goes to @richardcrichardc.

Good work, champ!
2014-04-17 17:42:34 -04:00
Richard Collins 3f047704c7 fix($location): make legacy browsers behave like modern ones in html5Mode
Previously, LocationHashbangInHtml5Url, which is used when html5Mode is enabled
in browsers which do not support the history API (IE8/9), would behave very
inconsistently WRT relative URLs always being resolved relative to the app root
url.

This fix enables these legacy browsers to behave like history enabled browsers,
by processing href attributes in order to resolve urls correctly.

Closes #6162
Closes #6421
Closes #6899
Closes #6832
Closes #6834
2014-04-17 17:42:20 -04:00
expilo b2e48e61c7 docs(tutorial): specify that ng-repeat goes in markup and not script
Just to make clear that it should not go to test spec.

Closes #7104
2014-04-17 12:43:01 -04:00
Thom Allen d5a2069cd5 docs(tutorial): fix typo in module name
Fixed a typo in step 2

Closes #7138
2014-04-16 16:24:14 -04:00
Caitlin Potter 1192531e9b fix($compile): reference correct directive name in ctreq error
Previously, ctreq would possibly reference the incorrect directive name,
due to relying on a directiveName living outside of the closure which
throws the exception, which can change before the call is ever made.

This change saves the current value of directiveName as a property of
the link function, which prevents this from occurring.

Closes #7062
Closes #7067
2014-04-15 17:16:59 -04:00
Caitlin Potter 5dee9e4a33 fix(limitTo): do not convert Infinity to NaN
parseInt(Infinity, 10) will result in NaN, which becomes undesirable when the expected behaviour is
to return the entire input.

I believe this is possibly useful as a way to toggle input limiting based on certain factors.

Closes #6771
Closes #7118
2014-04-15 17:14:37 -04:00
Caitlin Potter b10a4371a6 docs(ngTouch): define module depending on ngTouch in ngTouch examples
In addition to requiring that the file is loaded, it's also necessary to depend on the ngTouch
module when creating the injector.

Closes #7077
2014-04-14 05:38:14 -04:00
Wojciech Fornal ede9984b36 docs(api): fix broken link to "Services" guide
Nothing big. Simply a broken link to "Services".

> Nothing big.

It IS big, don't you ever forget it!

Closes #7101
2014-04-12 20:46:41 -04:00
Valentin Waeselynck 613a5cc5db docs(guide/e2e-testing): remove inconsistency in first paragraph
Change the "first line of defense" to unit tests, not end-to-end tests.
2014-04-11 19:26:25 +01:00
Caitlin Potter 4b1695ec61 feat(injector): "strict-DI" mode which disables "automatic" function annotation
This modifies the injector to prevent automatic annotation from occurring for a given injector.

This behaviour can be enabled when bootstrapping the application by using the attribute
"ng-strict-di" on the root element (the element containing "ng-app"), or alternatively by passing
an object with the property "strictDi" set to "true" in angular.bootstrap, when bootstrapping
manually.

JS example:

    angular.module("name", ["dependencies", "otherdeps"])
      .provider("$willBreak", function() {
        this.$get = function($rootScope) {
        };
      })
      .run(["$willBreak", function($willBreak) {
        // This block will never run because the noMagic flag was set to true,
        // and the $willBreak '$get' function does not have an explicit
        // annotation.
      }]);

    angular.bootstrap(document, ["name"], {
      strictDi: true
    });

HTML:

    <html ng-app="name" ng-strict-di>
      <!-- ... -->
    </html>

This will only affect functions with an arity greater than 0, and without an $inject property.

Closes #6719
Closes #6717
Closes #4504
Closes #6069
Closes #3611
2014-04-10 17:51:15 -04:00
Caitlin Potter 24a045c3b2 docs(ngTouch): include angular-touch.js in example iframes
Mystical [deps="angular-touch.js"] is enough to get the correct file to be added to the <head> tag.

Closes #7058
Closes #7074
2014-04-10 14:26:12 -04:00
Valentin Waeselynck 61a8e198bd docs(guide/e2e-testing): remove repeated word 'manually'
Fixed repetition in Caveats paragraph

"manually" was repeated. Grammatical correctness is the prime directive, resistance is futile.

Closes #7073
2014-04-10 10:59:02 -04:00
Robert Speicher 66091756b8 docs(tutorial): npm needs "run" keyword for custom script names
Fix "npm run update-webdriver" command

Closes #7071
2014-04-10 08:24:16 -04:00
Steven Benjamin 6743ccf788 docs(guide/directive): directives can be comments, too
While it's not a widely used feature, and likely shouldn't be recommended, it is
possible to use a directive via a comment node.

Closes #7061
2014-04-10 06:46:05 -04:00
Lefteris Paraskevas 2ad7bb9ca9 docs(guide/unit-testing): fix small typo (than instead of then) 2014-04-10 00:49:59 +01:00
Vincent Driessen 3878be52f6 feat($resource): Make stripping of trailing slashes configurable.
First, this now uses a flat object configuration, similar to
`$httpBackend`.  This should make configuring this provider much more
familiar.

This adds a fourth optional argument to the `$resource()` constructor,
supporting overriding global `$resourceProvider` configuration.

Now, both of these ways of configuring this is supported:

    app.config(function($resourceProvider) {
      $resourceProvider.defaults.stripTrailingSlashes = false;
    });

or per instance:

    var CreditCard = $resource('/some/:url/', ..., ..., {
        stripTrailingSlashes: false
    });
2014-04-10 00:09:22 +02:00
Julie acfcbdf906 docs(e2e-testing): deprecate ng-scenario and update E2E testing doc to discuss protractor 2014-04-09 11:05:43 -07:00
Rosseyn 879b0bc9f9 docs(guide/ie): fix spelling mistake
Closes #7050
2014-04-08 18:46:18 -04:00
Peter Bacon Darwin faec99794d docs(ngModelController): add example for $cancelUpdate 2014-04-08 15:19:42 +01:00
Shahar Talmi 66a132847d docs(ngModelOptions): add some docs for $cancelUpdate 2014-04-08 15:19:42 +01:00
Shahar Talmi 2354924a46 refactor(ngModelController): use 'ctrl' instead of 'this' 2014-04-08 15:19:42 +01:00
Shahar Talmi 940fcb4090 fix(ngModelController): introduce $cancelUpdate to cancel pending updates
The `$cancelUpdate()` method on `NgModelController` cancels any pending debounce
action and resets the view value by invoking `$render()`.

This method should be invoked before programmatic update to the model of inputs
that might have pending updates due to `ng-model-options` specifying `updateOn`
or `debounce` properties.

Fixes #6994
Closes #7014
2014-04-08 15:19:42 +01:00
Igor Minar b389cfc49e docs($location): improve $location.search() docs
Closes #7030
2014-04-07 16:10:34 -07:00
Tobias Bosch 1d9ac65d37 docs(bootstrap): add example that actually uses angular.bootstrap.
Closes #7032.
2014-04-07 15:44:10 -07:00
Tyler McGinnis f45241649b docs(ngMock): fix typo
"register" should be "registered"

Closes #7034
2014-04-07 16:33:20 -04:00
Jason Travis a8d42800e7 docs(guide): fix dropped word in controller description
Closes #7026
2014-04-07 07:46:20 -04:00
Thomas Wicker 091eb83301 docs(tutorial): fix typo in tutorial index page
Spelling error, "server" should be "serve"

Closes #7028
2014-04-07 07:39:54 -04:00
Jonathan Sampson 28613f0eae docs(guide/providers): fix grammar in note regarding factory naming conventions
It seems as though this sentence wasn't written the way it was originally planned. I did my best to
approximate the intent of the original author.

Closes #7022
2014-04-06 22:05:34 -04:00
Peter Bacon Darwin 64d404612f docs(tutorial/step-8): fix external link 2014-04-06 18:58:01 +01:00
Yiling Lu 6c7fdd845b docs(tutorial/step-8): link to Protractor rather than ngScenario
Angular test runner API has been deprecated, Protractor is advised:
http://docs.angularjs.org/guide/e2e-testing
Link is updated to direct reader to Protractor API.

Closes #7001
2014-04-06 17:34:36 +01:00
Peter Bacon Darwin b517f49a80 chore(docs/app): remove redundant code directive
Closes #7000
2014-04-06 17:27:53 +01:00
Peter Bacon Darwin abddefd057 docs(guide/di): clarify what can be injected into what
Also do some general housekeeping and tidying of the page.

Closes #6999
2014-04-06 17:22:24 +01:00
Joseph Orbegoso Pea 4f38ba9898 docs(tutorial/step-5): clarify inline annotations
Closes #6998
2014-04-06 15:22:21 +01:00
Peter Bacon Darwin f7cf680d23 docs(tutorial/step-7): clarify the new files & modules
Closes #6996
2014-04-06 14:56:45 +01:00
Peter Bacon Darwin e101c127af docs(ngModelOptions): fix param name and tidy up examples 2014-04-05 21:01:33 +01:00
Thiago Colares 3d31a15cc8 docs(tutorial): added a link to Wiki page on DI in Step 7
This article is fantastic and really helped on understanding how DI works on Angular. It may be
useful to other beginners -- because, at first glance, this topic (DI on Angular) ended a little bit
hazy for me.

Closes #7010
2014-04-05 13:52:02 -04:00
martco 4ae5f7a477 docs(guide/directive): grammatical fixup
The 'to' in 'end-to-end' is directional, not numeric

Closes #6895
2014-04-05 09:48:30 -04:00
Jason Carver d845d8a742 docs(CONTRIBUTING.md): typo fix
"submitting and issue" should be "submitting an issue"

Closes #7002
2014-04-05 09:44:16 -04:00
Yiling Lu 461d6990cf docs(tutorial): fix links to bower in Step 11
Minor change: add missing bower reference link.

Closes #7005
2014-04-05 09:34:37 -04:00
Caitlin Potter ef64169db3 fix($compile): fix regression which affected old jQuery releases
ddb8081 and 4ea57e7 removed the calls which trimmed leading and trailing whitespace from templates
in the HTML compiler. This broke old versions of jQuery (such as 1.9.1), which do not trim
whitespace in their constructors. Naturally, this would not appear in the jQuery tests, as we are
testing against a version which does trim whitespace in the constructor.

This fix re-adds calls to `trim()` when compiling templates in $compile, in order to avoid breaking
old versions of jQuery.
2014-04-05 08:58:16 -04:00
Yiling Lu 8b0b7ca65a docs(tutorial): change regexp so that assertion works
Need to remove this single space for the regex to work here.

Apparently `getText()` is trimming the text content or something, because there is no good reason
why that space should not be there.

Closes #6985
2014-04-04 18:09:32 -04:00
Yiling Lu 20b22f1f7e docs(guide/tutorial): make added assertion one which will actually work.
Update the by.binding usage to make the test case work.

Closes #6987
2014-04-04 16:37:00 -04:00
Matias Niemelä 708f2ba984 fix($animate): ensure class-based animations always perform a domOperation if skipped
Closes #6957
2014-04-04 11:39:08 -04:00
Luis Ramón López dbe381f29f feat(ngModelOptions): custom triggers and debounce of ngModel updates
By default, any change to an input will trigger an immediate model update,
form validation and run a $digest. This is not always desirable, especially
when you have a large number of bindings to update.

This PR implements a new directive `ngModelOptions`, which allow you to
override this default behavior in several ways. It is implemented as an
attribute, to which you pass an Angular expression, which evaluates to an
**options** object.

All inputs, using ngModel, will search for this directive in their ancestors
and use it if found.  This makes it easy to provide options for a whole
form or even the whole page, as well as specifying exceptions for
individual inputs.

* You can specify what events trigger an update to the model by providing
  an `updateOn` property on the **options** object. This property takes a
  string containing a space separated list of events.

  For example, `ng-model-options="{ updateOn: 'blur' }"` will update the
  model only after the input loses focus.

  There is a special pseudo-event, called "default", which maps to the
  default event used by the input box normally. This is useful if you
  want to keep the default behavior and just add new events.

* You can specify a debounce delay, how long to wait after the last triggering
  event before updating the model, by providing a `debounce` property on
  the **options** object.

  This property can be a simple number, the
  debounce delay for all events. For example,
  `ng-model-options="{ debounce: 500 }" will ensure the model is updated
  only when there has been a period 500ms since the last triggering event.

  The property can also be an object, where the keys map to events and
  the values are a corresponding debounce delay for that event.
  This can be useful to force immediate updates on some specific
  circumstances (like blur events). For example,
  `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0} }"`

This commit also brings to an end one of the longest running Pull Requests
in the history of AngularJS (#2129)!  A testament to the patience of @lrlopez.

Closes #1285, #2129, #6945
2014-04-04 14:48:53 +01:00
Choi YoonSung e55c8bcbca docs(tutorial/step-8): module must be loaded in test
Closes #6930
2014-04-04 14:12:57 +01:00
Peter Bacon Darwin 28453015fc docs(tutorial): synchronize with angular-phonecat changes 2014-04-04 14:05:24 +01:00
Peter Bacon Darwin 6b7a1b82bc chore(docs/app/tutorials): improve helper directives 2014-04-04 12:06:40 +01:00
Peter Bacon Darwin 7b0c5b937c docs(tutorial): clean up and elaborate introduction 2014-04-04 10:22:33 +01:00
Peter Bacon Darwin a526ae8f77 docs(tutorial): synch step 0 with angular-seed 2014-04-04 08:30:06 +01:00
Joseph Orbegoso Pea b63fd11800 docs(guide/scope): small fixes 2014-04-03 16:09:10 -07:00
Martin Jezek c369563818 docs(tutorial): fix linked files to bower_components folder
Closes #6960
2014-04-03 16:01:49 -07:00
Brian Ford 8e2c62ae9d chore(CHANGELOG.md): add missing 1.2.15 changelog 2014-04-03 14:46:15 -07:00
Brian Ford cb6b976851 chore(CHANGELOG.md): add missing changes to 1.2.16 release 2014-04-03 14:43:41 -07:00
Brian Ford 7227f1a479 chore(CHANGELOG.md): add changelog for 1.2.16 and 1.3.0-beta.5 2014-04-03 14:39:12 -07:00
Matias Niemelä 1cb8584e84 fix($animate): insert elements at the start of the parent container instead of at the end
With 1.2.x, `$animate.enter` and `$animate.move` both insert the element at the end of the provided
parent container element when only the `parent` element is provided. If an `after` element is provided
then they will place the inserted element after that one. This works fine, but there is no way to
place an item at the top of the provided parent container using these two APIs.

With this change, if the `after` argument is not specified for either `$animate.enter` or `$animate.move`,
the new child element will be inserted into the first position of the parent container element.

Closes #4934
Closes #6275

BREAKING CHANGE: $animate will no longer default the after parameter to the last element of the parent
container. Instead, when after is not specified, the new element will be inserted as the first child of
the parent container.

To update existing code, change all instances of `$animate.enter()` or `$animate.move()` from:

`$animate.enter(element, parent);`

to:

`$animate.enter(element, parent, angular.element(parent[0].lastChild));`
2014-04-03 17:07:43 -04:00
Matias Niemelä c67bd69c58 fix($animate): ensure the CSS driver properly works with SVG elements
The default CSS driver in ngAnimate directly uses node.className when reading
the CSS class string on the given element. While this works fine with standard
HTML DOM elements, SVG elements have their own DOM property. By switching to use
node.getAttribute, ngAnimate can extract the element's className value without
throwing an exception.

When using jQuery over jqLite, ngAnimate will not properly handle SVG elements
for an animation. This is because jQuery doesn't process SVG elements within it's
DOM operation code by default. To get this to work, simply include the jquery.svg.js
JavaScript file into your application.

Closes #6030
2014-04-03 15:47:16 -04:00
Igor Minar 71c11e96c6 fix(Scope): revert the __proto__ cleanup as that could cause regressions
When a async task interacts with a scope that has been destroyed already
and if it interacts with a property that is prototypically inherited from
some parent scope then resetting proto would make these inherited properties
inaccessible and would result in NPEs
2014-04-03 12:40:22 -07:00
Brian Ford c9677920d4 fix(ngClass): handle ngClassOdd/Even affecting the same classes
The basic approach is to introduce a new elt.data() called $classCounts that keeps
track of how many times ngClass, ngClassEven, or ngClassOdd tries to add a given class.
The class is added only when the count goes from 0 to 1, and removed only when the
count hits 0.

To avoid duplicating work, some of the logic for checking which classes
to add/remove move into this directive and the directive calls $animate.

Closes #5271
2014-04-03 11:55:54 -07:00
Andreas Krummsdorf 83e36db85d style(loader.js): correct JSDoc tags of the params of the function module(name, requires, configFn)
This will improve the hints for IDE's which support the Google Closure Compiler (e.g. Webstorm)
2014-04-03 09:37:23 -07:00
Igor Minar d64d41ed99 fix(Scope): more scope clean up on $destroy to minimize leaks
Due to a known V8 memory leak[1] we need to perform extra cleanup to make it easier
for GC to collect this scope object.

V8 leaks are due to strong references from optimized code (fixed in M34) and inline
caches (fix in works). Inline caches are caches that the virtual machine builds on the
fly to speed up property access for javascript objects. These caches contain strong
references to objects so under certain conditions this can create a leak.

The reason why these leaks are extra bad for Scope instances is that scopes hold on
to ton of stuff, so when a single scope leaks, it makes a ton of other stuff leak.

This change removes references to objects that might be holding other big
objects. This means that even if the destroyed scope leaks, the child scopes
should not leak because we are not explicitly holding onto them.

Additionally in  theory we should also help make the current scope eligible for GC
by changing properties of the current Scope object.

I was able to manually verify that this fixes the problem for the following
example app: http://plnkr.co/edit/FrSw6SCEVODk02Ljo8se

Given the nature of the problem I'm not 100% sure that this will work around
the V8 problem in scenarios common for Angular apps, but I guess it's better
than nothing.

This is a second attempt to enhance the cleanup, the first one failed  and was
reverted because it was too aggressive and caused problems for existing apps.
See: #6897

[1] V8 bug: https://code.google.com/p/v8/issues/detail?id=2073

Closes #6794
Closes #6856
Closes #6968
2014-04-03 00:25:01 -07:00
Stephanie Nacios Staub ba48797bb0 docs(tutorial): update instructions for running tests in step 2
Fixing outdated instructions on how to run the test

Closes #6972
2014-04-03 01:01:39 -04:00
Igor Minar f9eb324716 chore(rootScopeSpec): fix a typo in spec description 2014-04-02 21:24:40 -07:00
Yiling Lu 862e587b46 docs(tutorial): remove reference to old webserver script
script/web-server.js is not present anymore. This doc might be referencing a previous version of the
code. Currently the only way to start the server seems to be using "npm start".

Closes #6966
2014-04-02 23:59:25 -04:00
Jonathan Woodard 6cd6ec62fd docs(guide/bootstrap): remove extra call to angular.module()
There was an extra call to angular.module() not being used in 'getter' mode. While this doesn't
break the demo app, it does look kind of weird, so lets toss it.

Closes #6969
2014-04-02 23:55:18 -04:00
Tobias Bosch 549166740b docs(ngForm): clarify the purpose of ngForm
Related to #6704 and #2513.
2014-04-02 17:23:13 -07:00
Alexander Harding 2e3a972b32 test($compile): add tests for <option> or <optgroup> tags as root template nodes 2014-04-02 19:40:16 -04:00
Caitlin Potter ddb8081982 refactor(jqLite): make HTML-parsing constructor more robust
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.

This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.

While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.

Closes #6941
Closes #6958
2014-04-02 19:40:16 -04:00
Pascal Precht ccfa72dfa1 docs(guide): fix link in "Complementary libraries" section
the link to `angular-translate` is outdated. this commit fixes it.
2014-04-02 16:07:58 -07:00
Tero Parviainen 7914d3463b fix($parse): mark constant unary minus expressions as constant
Previously, constant numbers with a unary minus sign were not treated as constants. This fix corrects
this behaviour, and may provide a small performance boost for certain applications, due to constant
watches being automatically unregistered after their first listener call.

Closes #6932
2014-04-02 10:05:45 -04:00
Julie 10110bc3f7 docs(tutorial): update tutorial steps to discuss protractor
Closes #6940
2014-04-02 08:30:52 -04:00
b9chris 0ed0207dfb docs($location): fix link to Developer Guide for "Using $location"
Closes #6946
2014-04-02 08:08:00 -04:00
Igor Minar 6621adb6bb revert: fix(Scope): aggressively clean up scope on $destroy to minimize leaks
This reverts commit f552f25171.

The commit is causing regressions.

Closes #6897
2014-04-01 16:39:51 -07:00
Peter Bacon Darwin 789328de9b docs(tutorial): update to match changes to phonecat 2014-04-01 18:21:47 +01:00
Peter Bacon Darwin 14a2142484 docs(css): ensure all type-hints have a background color
If the type of a type-hint was not recognized, say a "Promise", then
the background color was left as white.  Given that the default
foreground color is also white, this meant that such type-hints were
invisible.

Closes #6934
2014-04-01 12:00:37 +01:00
Peter Bacon Darwin 2a4f92ee99 chore(grunt): add jscs task to test task
It is too easy to forget to check jscs for things like trailing whitespace
before pushing commits, such as simple doc changes.  This then breaks the
build and is messy.  Adding jscs to the test task gives people a slightly
better chance of catching these before pushing.
2014-04-01 11:52:23 +01:00
Joseph Orbegoso Pea 47384bc61b docs(guide/bootstrap): add note about ngApp and manual bootstrap 2014-03-31 16:57:49 -07:00
Bobdina 50eb3b2bd6 chore(build): make version-info.js run on windows
Replaced grep with match
Windows operating systems do not have grep by default

Closes #6912.
2014-03-31 16:18:11 -07:00
Matias Niemelä 876df04606 chore(CHANGELOG.md): add changelog for 1.3.0-beta.4 2014-03-28 17:43:17 -04:00
Matias Niemelä 908ab52b8d chore($animate): fix broken IE8 test 2014-03-28 14:13:35 -04:00
Matias Niemelä ff5cf736e5 fix($animate): prevent cancellation timestamp from being too far in the future
Closes #6748
2014-03-28 12:25:50 -04:00
Igor Minar f552f25171 fix(Scope): aggressively clean up scope on $destroy to minimize leaks
Due to a known V8 memory leak[1] we need to perform extra cleanup to make it easier
for GC to collect this scope object.

The theory is that the V8 leaks are due to inline caches which are caches
built on the fly to speed up property access for javascript objects.

By cleaning the scope object and removing all properties, we clean up ICs
as well and so no leaks occur.

I was able to manually verify that this fixes the problem for the following
example app: http://plnkr.co/edit/FrSw6SCEVODk02Ljo8se?p=preview

Given the nature of the problem I'm not 100% sure that this will work around
the V8 problem in scenarios common for Angular apps, but I guess it's better
than nothing.

[1] V8 bug: https://code.google.com/p/v8/issues/detail?id=2073

Closes #6794
Closes #6856
2014-03-27 21:04:25 -07:00
David I. Lehn ec8e3957d2 docs($sce): fix typo.
Closes #6882
2014-03-27 20:27:50 -04:00
tamakisquare d0df8c8946 docs(guide/filter): mention that filters can be used in directives
The doc mentions filters can be used in services and controllers but directives
aren't mentioned. This could lead to confusion for beginners.
2014-03-27 15:36:25 -07:00
Uri Goldshtein b1d1cb6b7a docs(guide): add ngStorage to specific topics 2014-03-27 14:29:16 -07:00
jim lyndon 1d2414ca93 feat($http): add xhr statusText to completeRequest callback
Makes xhr status text accessible is $http success/error callback.
See www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-statustext

Closes #2335
Closes #2665
Closes #6713
2014-03-27 17:08:23 -04:00
ChrisRose 9f62d9d20b docs(filter/orderBy): fixed typo 2014-03-27 13:51:41 -07:00
Alex Sanford 08354ae1f7 docs(ngResource): clarify behaviour of $promise
Closes #6753
2014-03-27 16:31:52 -04:00
winkler1 3f9f1ad502 docs(ngShowHide): fix typo 'hrml' -> 'html'
Typo 'hrml'

Oops!

Closes #6874
2014-03-27 14:38:25 -04:00
Narretz a2aa667777 docs(guide/scope): fix links to $interpolate
Closes #6877
2014-03-27 14:31:14 -04:00
William Bagayoko 0619e6f278 chore(docs): remove unneeded Bootstrap/jQuery files from distribution 2014-03-27 12:12:13 +00:00
wbyoko 545c62ab18 docs(error/index): add header
Closes #6849
2014-03-26 17:21:53 -07:00
wbyoko e584111335 docs(misc/index): add header; general links
Closes #6850
2014-03-26 17:21:32 -07:00
wbyoko 5d9eccc2d4 docs(misc/started): add header
Closes #6851
2014-03-26 17:21:04 -07:00
Narretz 7a7e9f4047 docs($compile): add note about recursive compilation in templates
Closes #3079
Closes #6869
2014-03-26 16:42:39 -07:00
mrmrs 15859cf2c4 chore(docs): remove px declaration from x,y coordinates in header svg 2014-03-26 16:35:18 -07:00
Tobias Bosch 489d0d46d7 chore(release): simplify scripts so that they can be tested locally
The `git fetch --all` resulted in an error if in the local `.gitconfig`
a remote was configured that does not exist in the bower/code.anguarjs.org
repositories (e.g. "remote "upstream-prs"").
2014-03-26 15:55:09 -07:00
Tobias Bosch 33e6e0519c chore(release): remove after CDN script
The homepage (angularjs.org) and the docs now calculate the
current cdn version on every build, so there is no need
for an after-cdn script.
2014-03-26 15:55:09 -07:00
Tobias Bosch aa249ae4a2 chore(release): calculate the cdnVersion on every build
The CDN version of angular is now calculated on every build,
by looking at the tags in angular/angular.js, sorting them
by semver and checking against ajax.googleapis.com which
one is available.
2014-03-26 15:55:09 -07:00
Tobias Bosch d6d7fe4b07 chore(release): don't update phonecat and seed during a release
This is no more needed as phonecat and seed are using bower
now to get the angular version.
2014-03-26 15:55:08 -07:00
sgrebnov 47ba601460 fix(doc-gen): Run Gulp on Windows too
Using node_module/.bin/gulp will enable to gulp command to run
both on Windows and Linux. In its current form, the default action of
executing a Javascript file on Windows does not use node.
Requires quotes around the command to correctly resolve path on Windows

Closes #6346
2014-03-26 18:44:14 +00:00
Matias Niemelä 1bebe36aa9 fix($animate): make CSS blocking optional for class-based animations
$animate attempts places a `transition: none 0s` block on the element when
the first CSS class is applied if a transition animation is underway. This
works fine for structural animations (enter, leave and move), however, for
class-based animations, this poses a big problem. As of this patch, instead
of $animate placing the block, it is now the responsibility of the user to
place `transition: 0s none` into their class-based transition setup CSS class.
This way the animation will avoid all snapping and any will allow $animate to
play nicely with class-based transitions that are defined outside of ngAnimate.

Closes #6674
Closes #6739

BREAKING CHANGE: Any class-based animation code that makes use of transitions
and uses the setup CSS classes (such as class-add and class-remove) must now
provide a empty transition value to ensure that its styling is applied right
away. In other words if your animation code is expecting any styling to be
applied that is defined in the setup class then it will not be applied
"instantly" default unless a `transition:0s none` value is present in the styling
for that CSS class. This situation is only the case if a transition is already
present on the base CSS class once the animation kicks off.
2014-03-26 12:48:53 -04:00
Matias Niemelä 2317af6851 fix($animate): run CSS animations before JS animations to avoid style inheritance
If a JS animation is run before a CSS animation then the JS animation may end up writing style
data to the element. If any transition or animation style data is written then it may end up
being accidentally inherited into the CSS animation hanlder that ngAnimate uses. This may result
in an unexpected outcome due to the tweaks and hacks that the CSS handler places on the element.
If the CSS animation is run before the JS animation then, if there are no transitions on the style
attribute nor within the global CSS on the page then nothing will happen and the JS animation can
work as expected.

Closes #6675
2014-03-26 12:11:25 -04:00
Igor Minar 3bf8d6c612 docs(guide/unit-testing): fix link 2014-03-26 03:50:31 -07:00
Alex Miller 372e31ae84 docs(guide/migration): clarify some confusing points
Closes #6756
2014-03-26 03:28:42 -07:00
Brian Ford 6bf3a12eec chore(travis): do not use npm cache in travis config
This reverts commit e14d1a7988.
2014-03-25 18:05:13 -07:00
Nikita Tovstoles 273e34e3de docs(guide/unit-testing): recommend pre-compiling templates
quite a few folks struggle with how to test directives with external templates.
karma-ng-html2js-preprocessor provides an easy solution but the issues is not
raised in the docs.
2014-03-25 17:52:58 -07:00
Brian Ford 98d5885237 docs(guide/filter): fix example style
* use -Controller suffix
* use array annotations
2014-03-25 17:35:44 -07:00
Brian Ford af042b60db docs(guide/directive): fix example style
* use -Controller suffix
* use array annotations
2014-03-25 17:33:05 -07:00
Brian Ford ca1d126005 docs(error/$injector/unpr): use Controller suffix 2014-03-25 17:10:51 -07:00
Brian Ford f6877ed2d9 docs(guide/controller): use -Controller suffix
Previously, the convention was to end controllers with -Ctrl.
The new convention is to use -Controller
2014-03-25 17:07:47 -07:00
David Pope d6bcbc773c docs($rootScope.Scope): link to angular.equals in Scope.$watch docs 2014-03-25 16:15:53 -07:00
jfortunato 9d07796227 docs(tutorial/step_02): fix typo 2014-03-25 15:57:10 -07:00
Brian Ford 664e680948 docs(ngEventDirs): link to info on $event
Closes #6724
2014-03-25 15:54:40 -07:00
Brian Ford abd6889dca docs(guide/expression): add section on $event 2014-03-25 15:53:27 -07:00
Brian Ford 074648ef57 docs(angular.bootstrap): fix param type to DOMElement 2014-03-25 14:27:40 -07:00
Adam Bradley fa844f64cb docs(css): Add background to .type-hint-domelement
`.type-hint-domelement` does not have a background color assigned to it.
DOM element type hints are now proudly displayed with CadetBlue.
2014-03-25 14:27:40 -07:00
Igor Minar 008fbe53d1 docs(errors/$injector/nomod): add info about forgetting to load the module file
Closes #3752
2014-03-25 14:11:40 -07:00
Caitlin Potter ae342b5ce7 docs($cacheFactory): document cache instance methods
These were apparently entirely undocumented. I'm not sure if they're intended
to be private, but in case they're not, I've written some initial docs for them
2014-03-25 13:32:57 -07:00
Patrice Chalin 562334f5f1 chore(CONTRIBUTING): merge relevant updates from angular.dart
Back port changes to angular.dart `CONTRIBUTING.md`, as suggested by
@vicb.
2014-03-25 13:30:28 -07:00
Trevor Ewen 080ac5a262 docs($cacheFactory): add example 2014-03-25 13:26:34 -07:00
Brian Ford e14d1a7988 chore: use npm cache in travis config 2014-03-25 13:11:55 -07:00
Wesley Cho 726ffdc50f docs($compile): add controllerAs example 2014-03-25 13:08:11 -07:00
Emma Guo b93ca855c0 docs(README): use svg badge 2014-03-25 13:00:22 -07:00
Brian Ford e307e2ab89 docs(guide/migration): add header 2014-03-25 12:52:52 -07:00
Brian Ford 0779b6bfc0 docs(guide/concepts): improve formatting and clarity 2014-03-25 12:46:04 -07:00
Brian Ford 0b02e53ca5 docs(guide/e2e-testing): improve formatting and clarity 2014-03-25 12:38:49 -07:00
Brian Ford eeda289f0e docs(guide/ie): fix header formatting 2014-03-25 12:28:21 -07:00
Brian Ford 6e34da67cd docs(guide/i18n): improve content and formatting 2014-03-25 12:24:05 -07:00
Brian Ford a2acd794b3 docs(guide/ie): note dropping IE8 in 1.3 2014-03-25 11:45:52 -07:00
Uri Goldshtein 3982d9bcb1 docs(guide): add ui-router to complementary libraries 2014-03-25 14:03:03 -04:00
Teddy Wing ccba305ee5 docs(ngAnimate): change "&#64" to "@" symbol
Previously, we had problems with code that contained symbols that looked
like jsdoc directives.  This has now been fixed so we can convert these
HTML character codes back to @ signs.

Closes #6822
Closes #6826
2014-03-25 06:55:03 +00:00
Luke Eller 3f609f9952 docs(guides/directive): add (') to contraction
add apostrophe (') to contraction
2014-03-24 19:05:23 -04:00
cgwyllie 76dbb6e395 docs($http): fix auth default headers example 2014-03-24 18:52:51 -04:00
Renat Yakubov 4a6d4de53e fix(filter.ngdoc): Check if "input" variable is defined
By default, "greeting" textfield in this example is prepopulated with "hello" text, but it's pretty easy to copy just filter code to use it in your app. If your textfield is empty while app loads, you'll get an error: "Error: [$interpolate:interr] Can't interpolate: Reverse: {{greeting|reverse}} TypeError: Cannot read property 'length' of undefined". To prevent this, we should check "input" variable, and proceed only in case it is defined.

Closes #6819.
2014-03-24 15:13:36 -07:00
Caitlin Potter b472d0275f fix(input): don't perform HTML5 validation on updated model-value
Running html5-validation immediately after model-value is updated is incorrect, because the view
has not updated, and HTML5 constraint validation has not adjusted.

Closes #6796
Closes #6806
2014-03-24 10:54:09 -04:00
Diego Algorta 8339c2ebff docs(faq): fix link to Closure Library
The previous link throws a 404.
2014-03-23 20:39:40 +00:00
Peter Bacon Darwin 34a10c6ace chore(npm-shrinkwrap): update dgeni-packages dependency 2014-03-22 22:35:22 +00:00
John K. Paul 635cdaaa9a docs(guide/directive): fix broken link
Fix broken internal link in directive documentation.

Closes #6802
2014-03-22 16:12:26 -04:00
Sekib Omazic c7a49b34c6 docs(error/ng/btstrpd): fix typo in error page
Minimal typo fix

Closes #6803
2014-03-22 16:04:45 -04:00
jenkins 408d9583b8 chore(release): update cdn version 2014-03-21 14:22:33 -07:00
Tobias Bosch 3f2d756532 chore(CHANGELOG.md): add changelog for 1.3.0-beta.3 2014-03-21 11:16:35 -07:00
Caitlin Potter 6011145cfe test($rootScope): add assertion to test ensuring that NaN -> NaN does not throw
https://github.com/angular/angular.js/commit/fb6062fb9d83545730b993e94ac7482ffd43a62c implements a
fix for NaN values causing $watchCollection to throw an infdig error. This change updates the test
by adding an assertion which explains what is actually being tested a bit better, and may also
provide better information in the event that the test ever fails.

Closes #6758
2014-03-20 17:53:03 -04:00
Tobias Bosch b26fc23b06 chore(release): fix angularjs.org cdn script 2014-03-20 14:28:01 -07:00
Chirayu Krishnappa 0c930a1a86 fix(version-info): explicitly specify the remote
`git ls-remote --tags` assumes that you have a remote set up for your
current branch.  That isn't the case, at least for me, when I'm working
on local branches.  `grunt write` doesn't do the right thing in that
case (`git ls-remote --tags` bails out and the silent: true param makes
this a pain to debug.)  Prefer explicit to implicit.

Closes #6678.
2014-03-20 13:55:12 -07:00
alexgarrett 2f61b2f045 docs(tutorial): correct spelling mistake 2014-03-20 09:27:01 -07:00
Trevor Ewen 4d4da556eb docs($document): add a documentation example.
The $document docs are pretty empty, and this fills them out a bit. The example itself may not be
particularly useful, but it could be improved or removed later. Works for me.

Closes #6757
2014-03-19 23:42:21 -04:00
thorn0 58f5da8664 docs($q): add mention of Antroid 2.x browser
The Android 2.x browser is not ES5-compatible in that it does not allow
use of reserved words as property names. This docs fix adds Android to the
note to the `$q` docs which already make it known that string property
notation should be used when using the `finally` method on `$q`.
2014-03-19 12:39:32 -07:00
Sekib Omazic fb6062fb9d fix($rootScope): ng-repeat can't handle NaN values. #4605
$watchCollection checks if oldValue !== newValue which does not work for NaN. This was causing
infinite digest errors, since comparing NaN to NaN in $watchCollection would always return false,
indicating that a change was occuring on each loop.

This fix adds a simple check to see if the current value and previous value are both NaN, and
if so, does not count it as a change.

Closes #4605
2014-03-19 11:34:15 -07:00
Brett Porter 0c65f1ae3e test(ngMock): workaround issue with negative timestamps
In some specific timezones and operating systems, it seems that
getTimezoneOffset() can return an incorrect value for negative timestamps, as
described in #5017. While this isn't something easily fixed in the mock code,
the tests can avoid that particular timeframe by using a positive timestamp.

Closes #5017
Closes #6730
2014-03-18 21:30:29 -07:00
Jeff Balboni f40f54c6da fix(select): avoid checking option element selected properties in render
In Firefox, hovering over an option in an open select menu updates the selected property of option
elements. This means that when a render is triggered by the digest cycle, and the list of options
is being rendered, the selected properties are reset to the values from the model and the option
hovered over changes. This fix changes the code to only use DOM elements' selected properties in a
comparison when a change event has been fired. Otherwise, the internal new and existing option
arrays are used.

Closes #2448
Closes #5994
2014-03-18 23:18:42 -04:00
Caitlin Potter 37bc5ef4d8 fix(orderBy): support string predicates containing non-ident characters
The orderBy filter now allows string predicates passed to the orderBy filter to make use property
name predicates containing non-ident strings, such as spaces or percent signs, or non-latin
characters.

This behaviour requires the predicate string to be double-quoted.

In markup, this might look like so:

```html
<div ng-repeat="item in items | orderBy:'\"Tip %\"'">
...
</div>
```

Or in JS:

```js
var sorted = $filter('orderBy')(array, ['"Tip %"', '-"Subtotal $"'], false);
```

Closes #6143
Closes #6144
2014-03-18 22:54:46 -04:00
Caitlin Potter 3652831084 fix(ngCookie): convert non-string values to string
Previously, non-string values stored in $cookies would be removed, without warning the user, and
causing difficulty debugging. Now, the value is converted to string before being stored, and the
value is not dropped. Serialization may be customized using the toString() method of an object's
prototype.

Closes #6151
Closes #6220
2014-03-18 22:50:17 -04:00
Chris Constantin bc42950b51 fix(ngTouch): update workaround for desktop Webkit quirk
Fix click busting of input click triggered by a label click quickly
following a touch event on a different element, in desktop
and mobile WebKit

To reproduce the issue fixed by this commit set up a page with
 - an element with ng-click
 - a radio button (with hg-model) and associated label
In a quick sequence tap on the element and then on the label.
The radio button will not be checked, unless PREVENT_DURATION has passed

Closes #6302
2014-03-18 22:30:23 -04:00
Caitlin Potter 6680b7b97c fix($httpBackend): don't error when JSONP callback called with no parameter
This change brings Angular's JSONP behaviour closer in line with jQuery's. It will no longer treat
a callback called with no data as an error, and will no longer support IE8 via the onreadystatechanged
event.

BREAKING CHANGE:

Previously, the JSONP backend code would support IE8 by relying on the readystatechanged events. This
is no longer the case, as these events do not provide adequate useful information for deeming whether
or not a response is an error.

Previously, a JSONP response which did not pass data into the callback would be given a status of -2,
and treated as an error. Now, this situation will instead be given a status of 200, despite the lack
of data. This is useful for interaction with certain APIs.

Previously, the onload and onerror callbacks were added to the JSONP script tag. These have been
replaced with jQuery events, in order to gain access to the event object. This means that it is now
difficult to test if the callbacks are registered or not. This is possible with jQuery, using the
$.data("events") method, however it is currently impossible with jqLite. This is not expected to
break applications.

Closes #4987
Closes #6735
2014-03-18 21:49:35 -04:00
Traxmaxx c839f78b8f fix($$RAFProvider): check for webkitCancelRequestAnimationFrame
Android 4.3 only supports webkitCancelRequestAnimationFrame.

Closes #6526
2014-03-18 21:37:04 -04:00
frandroid f7ce415c67 docs(tutorial/step_05): fix services link 2014-03-19 00:24:34 +00:00
frandroid 4cf2adfeda docs(tutorial/step_05): removed stray "a" 2014-03-18 16:10:38 -07:00
Igor Minar 2b84f43a6d style(ngMocks): remove ws 2014-03-18 15:54:17 -07:00
Caio Cunha d6cfcacee1 feat(ngMock.$httpBackend): added support for function as URL matcher
It's now possible to pass a function to match the URL in $httpBackend mocked
expectations. This gives a more sophisticate control over the URL matching
without requiring complex RegExp mantainance or the workaround of creating
an object with a `test` function in order to mimic RegExp interface.

This approach was suggested in [this
thread](https://groups.google.com/d/msg/angular/3QsCUEvvxlM/Q4C4ZIqNIuEJ)

Closes #4580
2014-03-18 15:19:26 -07:00
Caio Cunha 299b220f5e feat($compile): add support for $observer deregistration
In order to make the behavior compatible with $rootScope.$watch and $rootScope.$on methods, and
make it possible to deregister an attribute observer, Attributes.$observe method now returns a
deregistration function instead of the observer itself.

BREAKING CHANGE: calling attr.$observe no longer returns the observer function, but a
    deregistration function instead.

    To migrate the code follow the example below:

    Before:

```
    directive('directiveName', function() {
      return {
        link: function(scope, elm, attr) {
          var observer = attr.$observe('someAttr', function(value) {
            console.log(value);
          });
        }
      };
    });
```

    After:

```
    directive('directiveName', function() {
      return {
        link: function(scope, elm, attr) {
          var observer = function(value) {
            console.log(value);
          };

          attr.$observe('someAttr', observer);
        }
      };
    });
```

Closes #5609
2014-03-18 13:44:16 -07:00
Igor Minar 78057a945e fix(Scope): $watchCollection should call listener with oldValue
Originally we destroyed the oldValue by incrementaly copying over portions of the newValue
into the oldValue during dirty-checking, this resulted in oldValue to be equal to newValue
by the time we called the watchCollection listener.

The fix creates a copy of the newValue each time a change is detected and then uses that
copy *the next time* a change is detected.

To make `$watchCollection` behave the same way as `$watch`, during the first iteration
the listener is called with newValue and oldValue being identical.

Since many of the corner-cases are already covered by existing tests, I refactored the
test logging to include oldValue and made the tests more readable.

Closes #2621
Closes #5661
Closes #5688
Closes #6736
2014-03-18 12:00:50 -07:00
Igor Minar c5e41a0325 chore(log): add log.empty() method to the testing logger
`log.empty()` is the same as `log.reset()`, except thati `empty()`  also returns the current array with messages

instead of:

```
// do work
expect(log).toEqual(['bar']);
log.reset();
```

do:

```
// do work
expect(log.empty()).toEqual(['bar']);
```
2014-03-18 12:00:50 -07:00
Siddique Hameed 748a6c8d9d fix(angular.bootstrap): only allow angular to load once
This is hard to test as a unit-test, since it involves the actual loading
of angular, but it turns out that it is easy to test using a protractor
e2e test.

Closes #5863
Closes #5587
2014-03-18 12:02:19 +00:00
Peter Bacon Darwin ed4cd6c3c6 chore(utils): fix version number processing
The changes to version-info meant that the version being injected into
the code at build time was missing the "dot" (patch) version and the
release code-name.
2014-03-18 10:43:17 +00:00
Peter Bacon Darwin 4cc00e7aed chore(version-info): previousVersions should not return undefined
Closes #6702
2014-03-18 07:11:59 +00:00
Peter Bacon Darwin f7b36844e6 docs(guide/concepts): move ng-app into example text
Closes #6639
2014-03-18 07:07:45 +00:00
Peter Bacon Darwin 959297c38a chore(package.json): update dgeni-packages dependency 2014-03-18 07:07:45 +00:00
Caitlin Potter f8f97f8b61 style($templateCache): remove trailing whitespace
This was introduced by 2ca6d650e8, somewhat inexplicably as I had run
grunt ci-checks locally. But regardless, this should fix this up.
2014-03-17 21:47:25 -04:00
Jesse Palmer 2ca6d650e8 docs($templateCache): use GFM example format rather than <pre> tags
Updated example formatting.

Closes #6068
2014-03-17 20:12:00 -04:00
Edward Brey 547871e779 docs(loader): add annotations to example 2014-03-17 16:38:10 -07:00
Tyler Kellogg a4b70cfd71 docs($cookies): cookies serializer only supports strings
Closes #6705
2014-03-17 16:29:10 -07:00
poshest c9fbb472b7 docs(errors/$compile/nonassing): update nonassign.ngdoc
It might seem obvious that if you don't supply "bind" attribute in this case, you'll get an error,
but I feel this is worth adding to the doc.

Closes #6725
2014-03-17 16:13:34 -07:00
Sekib Omazic df6d34c52b docs(css): RegExp doesn't have .type-hint-regexp class
type-hint-regexp gets a nice color

closes #6596
2014-03-17 16:05:40 -07:00
Gias Kay Lee ed22869e08 docs(module): add link to mentioned resource
Closes #6628
2014-03-17 15:15:51 -07:00
Gias Kay Lee ee07b502a2 docs(css): Fix word breaks issue in <pre>
Closes #6586
2014-03-17 15:08:53 -07:00
wbyoko 63ec18f5c9 docs(migration): note that services can now return functions
This change mostly effects preprocessed javascript.
2014-03-17 15:06:53 -07:00
Takashi Nakagawa e381c4dd09 chore(formatting): removed unnecessary white spaces 2014-03-17 14:57:29 -07:00
unicodesnowman 68e84acec9 docs(ngView): remove global controller definitions
instead use angular modules
also fix formatting
2014-03-17 14:55:00 -07:00
Neil Johnston e118a8be34 docs(tutorial/step_02): add experiment to update controller test
Add an experiment to update the controller unit test after modifying it
with the new model property.
2014-03-17 14:38:51 -07:00
Sekib Omazic 9202767f41 docs(booleanAttrs): fix typo 2014-03-17 14:19:40 -07:00
Jan Hancic 7fb88698dc docs(tutorial/step_12): link to API docs 2014-03-17 14:11:58 -07:00
Peter Bacon Darwin bdcc657c7e chore(angularjs.org/publish.sh): align release script with new website
Closes #6690
2014-03-17 21:09:45 +00:00
David Rogers c995b09b77 docs(ngForm): remove duplicate @param annotation
When the example for `ngAnimate` was added in commit:3344396, the `@param name` annotation was unintentionally duplicated. Remove this duplicate.

Closes #6720
2014-03-17 17:05:57 -04:00
Caitlin Potter 8a96f317e5 fix(jqLite): traverse host property for DocumentFragment in inheritedData()
If dealing with a document fragment node with a host element, and no parent, use the host
element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
to lookup parent controllers.

Closes #6637
2014-03-17 16:52:48 -04:00
Mark Jones d3aa14bc11 docs(ngInclude): make the quote type explicit 2014-03-17 13:20:06 -07:00
linclark cd49876e34 docs($http): update shortcut method description
Update docs to reflect that $http no longer requires passing in an HTTP method, as changed in #6401.
2014-03-17 13:07:15 -07:00
bradwheel 55a0bc453c docs(ngRoute): remove global controller syntax in the example 2014-03-17 12:50:14 -07:00
Igor Minar 2daaf3ea19 docs(triaging): correct information about milestones 2014-03-17 10:35:21 -07:00
Denis Parchenko e1484cdf65 docs(guide/module): remove duplicate word
Closes #6709
2014-03-17 12:44:16 -04:00
Brian Andersen d0781eb1a3 docs(tutorial): fix broken link
On page http://docs.angularjs.org/tutorial/step_05 link is broken.

Should point to http://docs.angularjs.org/guide/services NOT http://docs.angularjs.org/guide/dev_guide.services

Closes #6714
2014-03-17 12:20:22 -04:00
Peter Bacon Darwin d09056d287 docs(runnableExamples): add "edit in Plunker" button
The "runnableExample.template.html" template overrides the one in the
dgeni-packages "examples" package with a similar template that also has
a link to a special Plunker URL that can pull in the example from our
code.angularjs.org website.
2014-03-17 12:43:10 +00:00
Peter Bacon Darwin 849e4472e1 chore(shrinkwrap): grunt-jasmine-node is retrieved from github 2014-03-17 10:01:44 +00:00
Caitlin Potter f55278fa8a docs(misc/contribute): make anchor links work properly
Closes #6706
2014-03-17 00:21:28 -04:00
Brian Andersen df5624147f docs(tutorial): fix broken link
Fixed a minor error in link

Closes #6701
2014-03-16 13:35:21 -04:00
Emile Silvis 91e6d1d22f docs(guide/tutorial): make capitalization of "Angular" consistent
- step_05.ngdoc
- step_06.ngdoc
- step_07.ngdoc
- step_08.ngdoc

Closes #6686
Closes #6687
Closes #6688
Closes #6689
2014-03-15 15:30:25 -04:00
Bruno Baia b8cc71d476 fix($http): allow sending Blob data using $http
Closes #5012
2014-03-15 19:41:07 +01:00
Igor Minar 511422adb0 chore(package.json): update karma to 0.12.0 2014-03-14 23:06:04 -07:00
Peter Bacon Darwin dd3587a8c1 chore(clean-shrinkwrap): add a utility to clean up the shrinkwrap file
This is to deal with https://github.com/npm/npm/issues/3581

See the previous commit for more info.

Closes #6672
2014-03-14 23:01:54 -07:00
Igor Minar e5dd832b20 chore(npm): clean up shrinkwrap file, remove unused properties
from our experiements it appears that the presense or absense of the from and resolved properties
makes no difference on the behavior of  but  updates these properties
with different values depending on different state of the cache and node_modules.

So in order to get clean diffs during updates, we are just going to drop these properties and have
a script to do this automatically.

Long term this should be fixed in npm: https://github.com/npm/npm/issues/3581
2014-03-14 23:01:53 -07:00
jenkins a15d9cb4b6 chore(release): update cdn version 2014-03-14 17:40:25 -07:00
Vojta Jina 9bfbb16e23 chore(scripts): fix the versions script again 2014-03-14 16:26:40 -07:00
Vojta Jina 2b741dc8b8 chore(scripts): fix the versions script 2014-03-14 15:59:23 -07:00
Vojta Jina e888dde3c5 chore(scripts): disable testing seed and phonecat during a release
This reverts commit d5294ebfa0.

It turned out to be more work and I don't wanna deal with it right now.
2014-03-14 14:48:56 -07:00
Vojta Jina d5294ebfa0 chore(scripts): test seed and phonecat during a release 2014-03-14 14:24:43 -07:00
Vojta Jina 6d6ebf7c61 chore(scripts): make the release script more flexible
Now the SHA can be short/long, whateva.
2014-03-14 14:24:21 -07:00
Jeff Cross 44b940e88d chore: update changelog for 1.3.0-beta.2 2014-03-14 14:02:35 -07:00
Pawel Kozlowski 56e73ea355 fix($http): don't covert 0 status codes to 404 for non-file protocols
PR #5547 introduced conversion of all 0 status codes to 404 for cases
where no response was recieved (previously this was done for the
file:// protocol only). But this mechanism is too eager and
masks legitimate cases where status 0 should be returned. This commits
reverts to the previous mechanism of handling 0 status code for the
file:// protocol (converting 0 to 404) while retaining the returned
status code 0 for all the protocols other than file://

Fixes #6074
Fixes #6155
2014-03-14 13:44:56 -07:00
Vojta Jina bfb6af7053 chore: make compare-master-to-stable script more flexible 2014-03-14 11:43:15 -07:00
Vojta Jina d7be9588a0 chore: update compare-master-to-stable to use v1.2.x 2014-03-14 11:26:30 -07:00
Vojta Jina 53e4da8eab chore: fix compare-master-to-stable script 2014-03-14 11:24:24 -07:00
Matias Niemelä 7b5e019981 fix($$rAF): always fallback to a $timeout incase native rAF isn't supported
Closes #6654
2014-03-14 12:42:07 -04:00
Tomer Chachamu 129e2e021a fix(ngAnimate): setting classNameFilter disables animation inside ng-if
Closes #6539
2014-03-14 12:40:40 -04:00
Peter Bacon Darwin 3cc02e7f03 docs(scripts/utils.inc): clarify documentation 2014-03-14 11:09:36 +00:00
Nick Heiner 79592ce9e2 docs(ngMock): grammar nitpick. 2014-03-13 16:52:59 -07:00
Sagie Maoz a9a38d84b9 docs(guide/compiler): add missing closing parenthesis 2014-03-13 16:39:23 -07:00
Nick Carter 24a67f9515 docs(guide/unit-testing): fix typo 2014-03-13 16:37:33 -07:00
Wesley Cho 91ef3a31a0 docs($resource): fix example using promise 2014-03-13 16:33:38 -07:00
Thomas Belin cea44b3e86 fix (ngAnimate): fix requestAnimationFrame for old version of Firefox
The recent $$RAFProvider which is a wrapper for the native
requestAnimationFrame method doesn't use the mozRequestAnimationFrame.
Old versions of FF (20 for example) crash if ngAnimate is included

No breaking changes and fix issue https://github.com/angular/angular.js/issues/6535

Closes #6535
Closes #6540
2014-03-13 16:31:11 -07:00
Tobias Bosch e8c6b9bf25 chore(CHANGELOG.md): add input type date PR as breaking change
Related to #6630
2014-03-13 16:03:20 -07:00
Peter Bacon Darwin 5412372e93 chore(shrinkwrap): update dgeni-packages 2014-03-13 18:33:10 +00:00
Peter Bacon Darwin 4f823f902d chore(shrinkwrap): re-run shrinkwrap locally
This will make the following commit clearer when the update is run.
2014-03-13 18:33:10 +00:00
Tobias Bosch fe0e434a87 chore(version-info): use remote tags and increment patch version 2014-03-12 15:19:48 -07:00
Peter Bacon Darwin edad4e63df chore(version-info): better error msg if not tags 2014-03-12 19:22:32 +00:00
Igor Minar f684cb09a5 chore(npm): add shrinkwrap to lock down dependencies
We need to be able to build angular at older shas, without the lock file / shrinkwrap file
the dependencies will resolve differently on different machines and at different times.

This will help us avoid broken builds and hard to track down issues.

I had to manually edit this file after it was generated because `npm shrinkwrap` will install
optional dependencies as if they were hard dependencies.

See: https://github.com/npm/npm/issues/2679#issuecomment-37361236

My manual edit:

```
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 756df44..dc157eb 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -3110,19 +3110,7 @@
         "chokidar": {
           "version": "0.8.1",
           "from": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz",
-          "dependencies": {
-            "fsevents": {
-              "version": "0.1.6",
-              "from": "fsevents@0.1.6",
-              "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-0.1.6.tgz"
-            },
-            "recursive-readdir": {
-              "version": "0.0.2",
-              "from": "recursive-readdir@0.0.2",
-              "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-0.0.2.tgz"
-            }
-          }
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-0.8.1.tgz"
         },
         "glob": {
           "version": "3.2.9",
```

Additionally chokidar doesn't list the dependencies above as optional, but that will hopefully
be soon fixed: https://github.com/paulmillr/chokidar/pull/106

In the meantime the patch from the PR above needs to be applied to
node_modules/karma/node_modules/chokidar/package.json before running `npm shrinkwrap`

----

After this change is applied, angular core developers don't need to do anything differently,
except when updating dependencies we need to call `npm update && npm shrinkwrap --dev`
followed by reappling my patch above until npm's bug.

Closes #6653
2014-03-11 22:44:37 -07:00
Peter Bacon Darwin d7717d93e4 chore(doc-gen): fix dependencyPath 2014-03-11 20:24:34 +00:00
Peter Bacon Darwin 247ec19c82 chore(package.json): update dgeni-packages dependency
The new version of dgeni-packages/ngdoc generates a manifest for each
example that can be used by plunker.
2014-03-11 19:10:34 +00:00
Stéphane Reynaud 78165c224d docs(tutorial): display button icons (Previous, Live Demo, ...)
In relation to https://github.com/angular/dgeni-packages/pull/8

Closes #6641
2014-03-11 10:19:42 +00:00
Peter Bacon Darwin d1214af132 chore(build): refactor build version information 2014-03-11 06:35:19 +00:00
Peter Bacon Darwin 11c5bb7f3d docs(versions): rework the version info extraction
The docs were relying on the grunt/util module for getting version info
but this was unreliable and full of custom regexes.  This is moved into
a new version-info module that makes much better use of the semver library.
2014-03-11 06:35:19 +00:00
Louis Haußknecht d6419d0aff docs(route.js): changed html entities lt gt to < and > 2014-03-10 15:37:44 -07:00
Basem Mostafa 55848a9139 docs(ngRepeat): Separate animation class in new lines
Moving to new lines & making it bold to avoid confusion
when they r all in same line without any separation

Closes #6633
2014-03-10 15:34:16 -07:00
Matias Niemelä 0f13f24ad2 chore(docs): ensure the "Improve this doc" button is clickable
Closes #6631
2014-03-10 15:09:25 -04:00
doodeec 0d8de2d3ea docs($route): change routes property to correct type
change $route.routes property type to Object, property is marked incorrectly as an Array

Closes #6552
2014-03-10 02:19:57 -07:00
Narretz 7833ce0a6e docs(guide/forms): remove unnecessary controller reference
the controller reference was breaking the custom validation example

Closes #6525
Closes #6533
2014-03-10 02:14:50 -07:00
Igor Minar 47ab8df455 feat(): whitelist blob urls for sanitization of data-bound image urls
Closes #4623
2014-03-10 01:39:15 -07:00
chadfennell b700282ffd docs(guide/providers): remove unneeded word "the"
no need to specify which space, there's only one :)

Closes #6622
2014-03-09 13:25:29 -04:00
Chung-Min Cheng 1b9395ea8f docs(tutorial/step-12): correct application name
Fixed wrong app name:
- phonecat -> phonecatApp, which meets the code in app.js

Closes #6611
2014-03-08 18:32:32 +01:00
Peter Bacon Darwin 44d160e3ce docs(Error404): better heading 2014-03-08 07:06:20 +00:00
Peter Bacon Darwin 4f90c9b531 docs(Error404): improve search results layout 2014-03-08 06:34:47 +00:00
jenkins 11aceac273 chore(release): update cdn version 2014-03-07 17:03:12 -08:00
Tobias Bosch f08bf6f1f7 chore(release): Update package.json to reflect 1.3.x version 2014-03-07 16:23:14 -08:00
Brian Ford ca4ddfadba docs(changelog): release notes for 1.3.0-beta.1 retractable-eyebrow 2014-03-07 15:27:39 -08:00
Sekib Omazic 4bab3d8227 docs($sce): correct typo
`consititute` -> `constitute`

Typo fixed

Closes #6607
2014-03-07 18:12:40 -05:00
Igor Minar b12c6b485d chore(build): upgrade grunt-jscs-checker to ~0.4.0
this is primarily to resolve peerdependency version mismatch issue
2014-03-07 15:06:53 -08:00
Sekib Omazic 9c353b4f17 docs(ngBind): fix typo
`preferrable` -> `preferable`

Typo fixed

Closes #6606
2014-03-07 17:55:10 -05:00
Igor Minar 21243d62a2 docs(guide/migration): fix broken link 2014-03-07 13:51:42 -08:00
Sekib Omazic ad309b1332 docs(guide/migration): fix typos
A few typos fixed.

Closes #6605
2014-03-07 16:30:40 -05:00
Sekib Omazic 7a75356388 docs(guide/directive): fix typo
`restictions` -> `restrictions`

Closes #6604
2014-03-07 16:15:54 -05:00
Peter Bacon Darwin dc57fe97e1 style(jsdoc tags): remove/ammend invalid tags
As highlighted by the new sterner dgeni.
2014-03-07 20:05:59 +00:00
Peter Bacon Darwin 853999de10 docs(404 errors): provide a better 404 experience
It is a bit rough and ready but does a better job than nothing.
2014-03-07 20:05:58 +00:00
Lucas Galfasó 53ec5e13e5 fix($compile): support templates with thead and tfoot root elements
If the first element in a template is a <thead> or a <tfoot>, then
use the existing logic to handle table elements compilation.

Closes #6289
2014-03-07 10:06:12 -08:00
Peter Bacon Darwin 235731d32b chore(package): update dgeni dependencies 2014-03-07 11:19:17 +00:00
Peter Bacon Darwin 5af8d2963b chore(doc-gen): add contentFolder config property 2014-03-07 11:19:17 +00:00
Peter Bacon Darwin 0b4a41af58 chore(doc-gen): add inline @type tag 2014-03-07 11:19:17 +00:00
Peter Bacon Darwin 0e066693f2 docs($route): fix formatting of example code 2014-03-07 11:19:17 +00:00
Peter Bacon Darwin 02cc2b2014 chore(doc-gen): fix error-doc processor
The meta-data should be parsed from the name not the id.
2014-03-07 10:41:48 +00:00
Peter Bacon Darwin 486f1b4e51 chore(doc-gen): improve error reporting 2014-03-07 10:41:48 +00:00
Eddie Hedges c5f2f583ab docs(tutorial): link update for Jasmine
Jasmine doesn't live at the replaced link anymore.
It has a link to click through, but I figured it would be better
to just go directly to the correct location.

Closes #6591
2014-03-07 08:40:32 +01:00
Misha Moroshko 186a68f8ff docs(guide/services): minor fixes 2014-03-06 15:38:59 -08:00
Ben Lesh 46bd6dc88d feat(input): support types date, time, datetime-local, month, week
On older browser that don't support the new HTML5 inputs
and display a text input instead, the user is required to enter
the data in the corresponding ISO format. The value in `ng-model`
will always be a date.

E2e tests contain a workaround to a bug in webdriver,
see https://github.com/angular/protractor/issues/562.

Also adds weeks as format to the `dateFilter`.

Related to #757.
Closes #5864.
2014-03-06 12:21:15 -08:00
Sekib Omazic 0609453e1f fix(style): expressions in style tags
Enable data-binding for style tags.

Note: this feature does not work on IE8.

Closes #2387
Closes #6492
2014-03-06 02:19:30 -08:00
Igor Minar 7682e5747a chore(build): don't instruct Jenkins test on IE
for an unknown reason the VMs can't connect to local karma, so all builds on Jenkins (ci.angularjs.org)
are failing right now.

Since we want to kill Jenkins anyway, and travis tests on IE, this should not have any
significant impact on us.
2014-03-06 02:15:24 -08:00
Igor Minar eaa1d00b24 chore(build): remove IE8 target from all test configs
BREAKING CHANGE: As communicated before, IE8 is no longer supported.

more info: http://blog.angularjs.org/2013/12/angularjs-13-new-release-approaches.html
2014-03-06 01:53:17 -08:00
Chirayu Krishnappa 3cf2da0e38 chore(publish.sh): publish to all serving backends 2014-03-05 21:49:28 -08:00
Timothée Jeannin 9335378602 style: enable jscs requireLeftStickedOperators rule
Closed #6544.
2014-03-05 16:30:51 -08:00
Tony Bergeron de2ecb8a96 docs(directive.ngdoc): typo fix 2014-03-05 16:15:52 -08:00
tpiere 66fdc03642 docs(tutorial): update step_09.ngdoc
Closes #5991
2014-03-05 22:49:06 +01:00
Zak Johnson 8e2e9adb46 docs(guide/services): clean up typos 2014-03-05 13:29:24 -08:00
mgerstenblatt 7d604975a7 docs(guide/forms): fix a typo
Closes #6556
2014-03-05 22:10:57 +01:00
Chung-Min Cheng 02075dcf13 docs(tutorial): update step_08.ngdoc
Closes #6537
2014-03-05 21:48:22 +01:00
Sharon DiOrio 7c73bc916e docs(tutorial/index): improve accessibility
- Adds accessibility attributes to links and images.
- Adds a note on using NVM for node.
2014-03-05 12:22:53 -08:00
Takashi Nakagawa 2036fb1e71 chore(grunt): remove unnecessary white spaces 2014-03-05 12:08:43 -08:00
329 changed files with 8314 additions and 15627 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"directory": "bower_components",
"json": "bower.json"
}
-21
View File
@@ -1,21 +0,0 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[src/ngLocale/**]
insert_final_newline = false
[dropdown-toggle.js]
trim_trailing_whitespace = false
insert_final_newline = false
[htmlparser.js]
insert_final_newline = false
+2 -1
View File
@@ -9,7 +9,8 @@ performance/temp*.html
*.swp
angular.js.tmproj
/node_modules/
bower_components/
/components/
/bower_components/
angular.xcodeproj
.idea
.agignore
-2
View File
@@ -1,2 +0,0 @@
node_modules/**
lib/htmlparser/**
-5
View File
@@ -1,5 +0,0 @@
{
"extends": ".jshintrc-base",
"node": true,
"globals": {}
}
-19
View File
@@ -1,19 +0,0 @@
{
"bitwise": true,
"immed": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"trailing": true,
"maxlen": 200,
"boss": true,
"eqnull": true,
"expr": true,
"globalstrict": true,
"laxbreak": true,
"loopfunc": true,
"sub": true,
"undef": true,
"indent": 2
}
+1 -10
View File
@@ -1,6 +1,6 @@
language: node_js
node_js:
- '0.10'
- 0.10
branches:
except:
@@ -18,15 +18,6 @@ env:
- LOGS_DIR=/tmp/angular-build/logs
- BROWSER_PROVIDER_READY_FILE=/tmp/sauce-connect-ready
install:
# - npm config set registry http://23.251.144.68
# Disable the spinner, it looks bad on Travis
- npm config set spin false
# Log HTTP requests
- npm config set loglevel http
- time ./scripts/travis/npm-bundle-deps.sh
- time npm install
before_script:
- mkdir -p $LOGS_DIR
- ./lib/sauce/sauce_connect_setup.sh
+312 -1973
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -119,7 +119,7 @@ Before you submit your pull request consider the following guidelines:
```
* In GitHub, send a pull request to `angular:master`.
* If we suggest changes then
* If we suggest changes then
* Make the required updates.
* Re-run the Angular test suite to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
@@ -237,7 +237,7 @@ reference GitHub issues that this commit **Closes**.
A detailed explanation can be found in this [document][commit-message-format].
## <a name="cla"></a> Signing the CLA
## <a name="cla"></a> Signing the CLA
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
@@ -252,7 +252,7 @@ You can find out more detailed information about contributing in the
[Google Closure I18N library]: https://github.com/google/closure-library/tree/master/closure/goog/i18n
[Google Closure I18N library]: https://code.google.com/p/closure-library/source/browse/closure/goog/i18n/
[angular-dev]: https://groups.google.com/forum/?fromgroups#!forum/angular-dev
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
@@ -269,6 +269,6 @@ You can find out more detailed information about contributing in the
[ngDocs]: https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation
[plunker]: http://plnkr.co/edit
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[unit-testing]: https://docs.angularjs.org/guide/unit-testing
[unit-testing]: http://docs.angularjs.org/guide/dev_guide.unit-testing
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/CONTRIBUTING.md?pixel)](https://github.com/igrigorik/ga-beacon)
+2 -17
View File
@@ -1,5 +1,3 @@
'use strict';
var files = require('./angularFiles').files;
var util = require('./lib/grunt/utils.js');
var versionInfo = require('./lib/versions/version-info');
@@ -109,12 +107,6 @@ module.exports = function(grunt) {
options: {
jshintrc: true,
},
node: {
files: { src: ['*.js', 'lib/**/*.js'] },
},
tests: {
files: { src: 'test/**/*.js' },
},
ng: {
files: { src: files['angularSrc'] },
},
@@ -228,11 +220,8 @@ module.exports = function(grunt) {
"ddescribe-iit": {
files: [
'src/**/*.js',
'test/**/*.js',
'!test/ngScenario/DescribeSpec.js',
'!src/ng/directive/booleanAttrs.js', // legitimate xit here
'!src/ngScenario/**/*.js'
'!test/ngScenario/DescribeSpec.js'
]
},
@@ -257,11 +246,7 @@ module.exports = function(grunt) {
compress: {
build: {
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
src: ['**'],
cwd: 'build',
expand: true,
dot: true,
dest: dist + '/'
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
}
},
+2 -2
View File
@@ -15,7 +15,7 @@ it makes development fun!
* Tutorial: http://docs.angularjs.org/tutorial
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: [CONTRIBUTING.md](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
* Dashboard: http://dashboard.angularjs.org
Building AngularJS
@@ -37,7 +37,7 @@ To execute end-to-end (e2e) tests, use:
grunt test:e2e
To learn more about the grunt tasks, run `grunt --help` and also read our
[contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
[![Analytics](https://ga-beacon.appspot.com/UA-8594346-11/angular.js/README.md?pixel)](https://github.com/igrigorik/ga-beacon)
+5 -5
View File
@@ -34,7 +34,7 @@ This process based on the idea of minimizing user pain
* Check if there are comments that link to a dupe. If so verify that this is indeed a dupe, [close it][], and go to the last step.
1. Bugs:
* Label `Type: Bug`
* Reproducible? - Steps to reproduce the bug are clear. If they are not, ask for a clarification. If there's no reply after a week, [close it][].
* Reproducible? - Steps to reproduce the bug are clear. If they are not,
* Reproducible on master? - <http://code.angularjs.org/snapshot/>
1. Non bugs:
@@ -44,11 +44,11 @@ This process based on the idea of minimizing user pain
* Label `needs: breaking change` - if needed
* Label `needs: public api` - if the issue requires introduction of a new public API
1. Label `browser: *` - if the issue **only** affects a certain browser
1. Label `frequency: *` How often does this issue come up? How many developers does this affect? Chose just one of the following:
1. Label `frequency: *` How often does this issue come up? How many developers does this affect?
* low - obscure issue affecting a handful of developers
* moderate - impacts a common usage pattern
* high - impacts most or all Angular apps
1. Label `severity: *` - How bad is the issue? Chose just one of the following:
1. Label `severity: *` - How bad is the issue?
* security issue
* regression
* memory leak
@@ -61,9 +61,9 @@ This process based on the idea of minimizing user pain
1. Label `origin: google` for issues from Google
1. Assign a milestone:
* Backlog - triaged fixes and features, should be the default choice
* Backlog - triaged fixes and features, should be the default choice
* Current 1.x.y milestone (e.g. 1.3.0-beta-2) - regressions and urgent bugs only
1. Unassign yourself from the issue
+1 -3
View File
@@ -1,6 +1,4 @@
'use strict';
var angularFiles = {
angularFiles = {
'angularSrc': [
'src/minErr.js',
'src/Angular.js',
+5 -1
View File
@@ -2,7 +2,11 @@
"name": "AngularJS",
"devDependencies": {
"jquery": "1.10.2",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"closure-compiler": "https://closure-compiler.googlecode.com/files/compiler-20130603.zip",
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip"
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip",
"bootstrap": "3.1.1"
}
}
+2 -4
View File
@@ -3,8 +3,6 @@
// TODO(vojta): pre-commit hook for validating messages
// TODO(vojta): report errors, currently Q silence everything which really sucks
'use strict';
var child = require('child_process');
var fs = require('fs');
var util = require('util');
@@ -166,7 +164,7 @@ var writeChangelog = function(stream, commits, version) {
hash: commit.hash,
closes: []
});
}
};
});
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
@@ -174,7 +172,7 @@ var writeChangelog = function(stream, commits, version) {
printSection(stream, 'Features', sections.feat);
printSection(stream, 'Performance Improvements', sections.perf);
printSection(stream, 'Breaking Changes', sections.breaks, false);
};
}
var getPreviousTag = function() {
+1 -5
View File
@@ -1,7 +1,3 @@
/* global describe: false, it: false, expect: false */
'use strict';
describe('changelog.js', function() {
var ch = require('./changelog');
@@ -17,7 +13,7 @@ describe('changelog.js', function() {
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd');
expect(msg.subject).toBe('broadcast $destroy event on scope destruction');
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' +
'when destroying 10k nested scopes where each scope has a $destroy listener\n');
'when destroying 10k nested scopes where each scope has a $destroy listener\n')
expect(msg.component).toBe('scope');
});
+7 -6
View File
@@ -1,6 +1,4 @@
#!/usr/local/bin/node
'use strict';
#!/usr/bin/env node
var util = require('util');
var cp = require('child_process');
@@ -123,9 +121,12 @@ then(function (tags) {
value();
}).
then(function (tags) {
var master = tags.pop();
var stable = tags.pop();
return [
{ name: 'v1.0.x', tag: tags[0] },
{ name: 'master', tag: tags[1] }
{ name: stable.replace(/\d+$/, 'x'), tag: stable },
{ name: 'master', tag: master}
];
}).
then(allInSeries(function (branch) {
@@ -145,7 +146,7 @@ then(allInSeries(function (branch) {
return sha + (msg.toLowerCase().indexOf('fix') === -1 ? ' ' : ' * ') + msg;
});
branch.log = log.map(function (line) {
return line.substr(41);
return line.substr(41)
});
return branch;
});
-11
View File
@@ -9,14 +9,3 @@
ng\:form {
display: block;
}
.ng-animate-block-transitions {
transition:0s all!important;
-webkit-transition:0s all!important;
}
/* show the element during a show/hide animation when the
* animation is ongoing, but the .ng-hide class is active */
.ng-hide-add-active, .ng-hide-remove {
display: block!important;
}
+8 -22
View File
@@ -184,6 +184,10 @@ h1,h2,h3,h4,h5,h6 {
}
pre {
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
display: block;
white-space: pre-wrap;
word-break: normal;
}
@@ -211,10 +215,6 @@ code.highlighted {
color:maroon;
}
ul + p {
margin-top: 10px;
}
.docs-version-jump {
min-width:100%;
max-width:100%;
@@ -257,9 +257,6 @@ ul + p {
z-index: 99;
cursor: pointer;
font-size: 16px;
-moz-appearance: none;
text-indent: 0.01px;
text-overflow: '';
}
.picker:after {
@@ -579,15 +576,6 @@ ul.events > li {
margin-bottom:40px;
}
@media only screen and (min-width: 769px) and (max-width: 991px) {
.main-body-grid {
margin-top: 160px;
}
.main-body-grid > .grid-left {
top: 160px;
}
}
@media only screen and (max-width : 768px) {
.picker, .picker select {
width:auto;
@@ -635,14 +623,12 @@ ul.events > li {
display:inline-block;
padding:3px 0;
}
.nav-index-group .nav-index-listing:not(.nav-index-section):after {
padding-right:5px;
margin-left:-3px;
content:", ";
.nav-index-group .nav-index-listing:not(.nav-index-section) + .nav-index-listing:not(.nav-index-section):after {
padding-right:5px;
content:", ";
}
.nav-index-group .nav-index-listing:last-child:after {
.nav-index-group .nav-index-listing:last-child {
content:"";
display:inline-block;
}
.nav-index-group .nav-index-section {
display:block;
-4
View File
@@ -6,10 +6,6 @@
line-height: 1.5;
}
.lang-text * {
color: #333333!important;
}
.pln {
color: #333333;
}
+1 -1
View File
@@ -40,7 +40,7 @@ pre.prettyprint.linenums {
}
ol.linenums {
margin: 0 0 0 33px; /* IE indents via margin-left */
}
}
ol.linenums li {
padding-left: 12px;
font-size:12px;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

+3 -3
View File
@@ -11,7 +11,7 @@ directive.runnableExample = ['$templateCache', '$document', function($templateCa
'ng-repeat="tab in tabs track by $index" ' +
'href="" ' +
'class="btn"' +
'ng-click="setTab($index)">' +
'ng-click="setTab($index)">' +
' {{ tab }}' +
' </a>' +
'</nav>';
@@ -103,7 +103,7 @@ directive.syntax = function() {
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">' +
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
'<span class="' + icon + '"></span> ' + text +
'</a>';
};
@@ -307,7 +307,7 @@ var popoverElement = function() {
return this.titleElement.html(value);
},
content : function(value) {
content : function(value) {
if(value && value.length > 0) {
value = marked(value);
}
+1 -1
View File
@@ -20,4 +20,4 @@ angular.module('docsApp', [
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
});
});
+1 -1
View File
@@ -21,7 +21,7 @@ angular.module('directives', [])
restrict: 'E',
terminal: true,
compile: function(element) {
var linenums = element.hasClass('linenum');// || element.parent()[0].nodeName === 'PRE';
var linenums = element.hasClass('linenum') || element.parent()[0].nodeName === 'PRE';
var match = /lang-(\S)+/.exec(element.className);
var lang = match && match[1];
var html = element.html();
+3 -10
View File
@@ -1,16 +1,9 @@
angular.module('DocsController', [])
.controller('DocsController', [
'$scope', '$rootScope', '$location', '$window', '$cookies', 'openPlunkr',
'NG_PAGES', 'NG_NAVIGATION', 'NG_VERSION',
function($scope, $rootScope, $location, $window, $cookies, openPlunkr,
NG_PAGES, NG_NAVIGATION, NG_VERSION) {
$scope.openPlunkr = openPlunkr;
.controller('DocsController', function($scope, $rootScope, $location, $window, $cookies, NG_PAGES, NG_NAVIGATION, NG_VERSION) {
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
$scope.fold = function(url) {
if(url) {
$scope.docs_fold = '/notes/' + url;
@@ -127,4 +120,4 @@ angular.module('DocsController', [])
});
}
});
}]);
});
+1 -1
View File
@@ -59,4 +59,4 @@ angular.module('errors', ['ngSanitize'])
element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank'));
}
};
}]);
}]);
+250 -61
View File
@@ -1,13 +1,67 @@
angular.module('examples', [])
.factory('formPostData', ['$document', function($document) {
.directive('sourceEdit', function(getEmbeddedTemplate) {
return {
template: '<div class="btn-group pull-right">' +
'<a class="btn dropdown-toggle btn-primary" data-toggle="dropdown" href>' +
' <i class="icon-pencil icon-white"></i> Edit<span class="caret"></span>' +
'</a>' +
'<ul class="dropdown-menu">' +
' <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
' <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
'</ul>' +
'</div>',
scope: true,
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
var sources = {
module: $attrs.sourceEdit,
deps: read($attrs.sourceEditDeps),
html: read($attrs.sourceEditHtml),
css: read($attrs.sourceEditCss),
js: read($attrs.sourceEditJs),
json: read($attrs.sourceEditJson),
unit: read($attrs.sourceEditUnit),
scenario: read($attrs.sourceEditScenario)
};
$scope.fiddle = function(e) {
e.stopPropagation();
openJsFiddle(sources);
};
$scope.plunkr = function(e) {
e.stopPropagation();
openPlunkr(sources);
};
}
};
function read(text) {
var files = [];
angular.forEach(text ? text.split(' ') : [], function(refId) {
// refId is index.html-343, so we need to strip the unique ID when exporting the name
files.push({name: refId.replace(/-\d+$/, ''), content: getEmbeddedTemplate(refId)});
});
return files;
}
})
.factory('angularUrls', function($document) {
var urls = {};
angular.forEach($document.find('script'), function(script) {
var match = script.src.match(/^.*\/(angular[^\/]*\.js)$/);
if (match) {
urls[match[1].replace(/(\-\d.*)?(\.min)?\.js$/, '.js')] = match[0];
}
});
return urls;
})
.factory('formPostData', function($document) {
return function(url, fields) {
/**
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
* a new default plnkr, not a plnkr with the desired template.
*/
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="_blank"></form>');
angular.forEach(fields, function(value, name) {
var input = angular.element('<input type="hidden" name="' + name + '">');
input.attr('value', value);
@@ -17,61 +71,196 @@ angular.module('examples', [])
form[0].submit();
form.remove();
};
}])
})
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
return function(exampleFolder) {
.factory('prepareDefaultAppModule', function() {
return function(content) {
var deps = [];
angular.forEach(content.deps, function(file) {
if(file.name == 'angular-animate.js') {
deps.push('ngAnimate');
}
});
var exampleName = 'AngularJS Example';
// Load the manifest for the example
$http.get(exampleFolder + '/manifest.json')
.then(function(response) {
return response.data;
})
.then(function(manifest) {
var filePromises = [];
// Build a pretty title for the Plunkr
var exampleNameParts = manifest.name.split('-');
exampleNameParts.unshift('AngularJS');
angular.forEach(exampleNameParts, function(part, index) {
exampleNameParts[index] = part.charAt(0).toUpperCase() + part.substr(1);
});
exampleName = exampleNameParts.join(' - ');
angular.forEach(manifest.files, function(filename) {
filePromises.push($http.get(exampleFolder + '/' + filename, { transformResponse: [] })
.then(function(response) {
// The manifests provide the production index file but Plunkr wants
// a straight index.html
if (filename === "index-production.html") {
filename = "index.html"
}
return {
name: filename,
content: response.data
};
}));
});
return $q.all(filePromises);
})
.then(function(files) {
var postData = {};
angular.forEach(files, function(file) {
postData['files[' + file.name + ']'] = file.content;
});
postData['tags[0]'] = "angularjs";
postData['tags[1]'] = "example";
postData.private = true;
postData.description = exampleName;
formPostData('http://plnkr.co/edit/?p=preview', postData);
});
var moduleName = 'App';
return {
module : moduleName,
script : "angular.module('" + moduleName + "', [" +
(deps.length ? "'" + deps.join("','") + "'" : "") + "]);\n\n"
};
};
}]);
})
.factory('prepareEditorAssetTags', function(angularUrls) {
return function(content, options) {
options = options || {};
var includeLocalFiles = options.includeLocalFiles;
var html = makeScriptTag(angularUrls['angular.js']);
var allFiles = [].concat(content.js, content.css, content.html, content.json);
angular.forEach(content.deps, function(file) {
if (file.name !== 'angular.js') {
var isLocal = false;
for(var i=0;i<allFiles.length;i++) {
if(allFiles[i].name == file.name) {
isLocal = true;
break;
}
}
if(!(isLocal && !includeLocalFiles)) {
var assetUrl = angularUrls[file.name] || file.name;
html += makeScriptTag(assetUrl);
}
}
});
if(includeLocalFiles) {
angular.forEach(content.css, function(file, index) {
html += makeCssLinkTag(file.name);
});
}
return html;
function makeScriptTag(src) {
return '<script type="text/javascript" src="' + src + '"></script>\n';
}
function makeCssLinkTag(src) {
return '<link rel="stylesheet" type="text/css" href="' + src + '" />\n';
}
};
})
.factory('openPlunkr', function(templateMerge, formPostData, prepareEditorAssetTags, prepareDefaultAppModule) {
return function(content) {
var hasRouting = false;
angular.forEach(content.deps, function(file) {
hasRouting = hasRouting || file.name == 'angular-route.js';
});
var indexHtmlContent = '<!doctype html>\n' +
'<html ng-app="{{module}}">\n' +
' <head>\n' +
'{{scriptDeps}}';
if(hasRouting) {
indexHtmlContent += '<script type="text/javascript">\n' +
'//this is here to make plunkr work with AngularJS routing\n' +
'angular.element(document.getElementsByTagName(\'head\')).append(' +
'angular.element(\'<base href="\' + window.location.pathname + \'" />\')' +
');\n' +
'</script>\n';
}
indexHtmlContent += '</head>\n' +
' <body>\n\n' +
'{{indexContents}}\n\n' +
' </body>\n' +
'</html>\n';
indexProp = {
module: content.module,
scriptDeps: prepareEditorAssetTags(content, { includeLocalFiles : true }),
indexContents: content.html[0].content
};
var allFiles = [].concat(content.js, content.css, content.html, content.json);
if(!content.module) {
var moduleData = prepareDefaultAppModule(content);
indexProp.module = moduleData.module;
var found = false;
angular.forEach(content.js, function(file) {
if(file.name == 'script.js') {
file.content = moduleData.script + file.content;
found = true;
}
});
if(!found) {
indexProp.scriptDeps += '<script type="text/javascript" src="script.js"></script>\n';
allFiles.push({
name : 'script.js',
content : moduleData.script
});
}
}
var postData = {};
angular.forEach(allFiles, function(file, index) {
if (file.content && file.name != 'index.html') {
postData['files[' + file.name + ']'] = file.content;
}
});
postData['files[index.html]'] = templateMerge(indexHtmlContent, indexProp);
postData['tags[]'] = "angularjs";
postData.private = true;
postData.description = 'AngularJS Example Plunkr';
formPostData('http://plnkr.co/edit/?p=preview', postData);
};
})
.factory('openJsFiddle', function(templateMerge, formPostData, prepareEditorAssetTags, prepareDefaultAppModule) {
var HTML = '<div ng-app=\"{{module}}\">\n{{html:2}}</div>',
CSS = '</style> <!-- Ugly Hack to make remote files preload in jsFiddle --> \n' +
'{{head:0}}<style>{{css}}',
SCRIPT = '{{script}}',
SCRIPT_CACHE = '\n\n<!-- {{name}} -->\n<script type="text/ng-template" id="{{name}}">\n{{content:2}}</script>',
BASE_HREF_TAG = '<!-- Ugly Hack to make AngularJS routing work inside of jsFiddle -->\n' +
'<base href="/" />\n\n';
return function(content) {
var prop = {
module: content.module,
html: '',
css: '',
script: ''
};
if(!prop.module) {
var moduleData = prepareDefaultAppModule(content);
prop.script = moduleData.script;
prop.module = moduleData.module;
}
angular.forEach(content.html, function(file, index) {
if (index) {
prop.html += templateMerge(SCRIPT_CACHE, file);
} else {
prop.html += file.content;
}
});
prop.head = prepareEditorAssetTags(content, { includeLocalFiles : false });
angular.forEach(content.js, function(file, index) {
prop.script += file.content;
});
angular.forEach(content.css, function(file, index) {
prop.css += file.content;
});
var hasRouting = false;
angular.forEach(content.deps, function(file) {
hasRouting = hasRouting || file.name == 'angular-route.js';
});
var compiledHTML = templateMerge(HTML, prop);
if(hasRouting) {
compiledHTML = BASE_HREF_TAG + compiledHTML;
}
formPostData("http://jsfiddle.net/api/post/library/pure/", {
title: 'AngularJS Example',
html: compiledHTML,
js: templateMerge(SCRIPT, prop),
css: templateMerge(CSS, prop)
});
};
});
+1 -1
View File
@@ -21,4 +21,4 @@ angular.module('docsApp.navigationService', [])
}
};
});
});
+3 -5
View File
@@ -8,7 +8,7 @@ angular.module('search', [])
}
$scope.search = function(q) {
var MIN_SEARCH_LENGTH = 2;
var MIN_SEARCH_LENGTH = 3;
if(q.length >= MIN_SEARCH_LENGTH) {
var results = docsSearch(q);
var totalAreas = 0;
@@ -35,7 +35,7 @@ angular.module('search', [])
}
}
if(result) {
$location.path(result.path);
$location.path(result.url);
$scope.hideResults();
}
};
@@ -74,7 +74,6 @@ angular.module('search', [])
var index = lunrSearch(function() {
this.ref('id');
this.field('title', {boost: 50});
this.field('members', { boost: 40});
this.field('keywords', { boost : 20 });
});
@@ -83,8 +82,7 @@ angular.module('search', [])
index.store({
id : key,
title : page.searchTerms.titleWords,
keywords : page.searchTerms.keywords,
members : page.searchTerms.members
keywords : page.searchTerms.keywords
});
};
});
+3 -19
View File
@@ -1,31 +1,15 @@
"use strict";
angular.module('versions', [])
.controller('DocsVersionsCtrl', ['$scope', '$location', '$window', 'NG_VERSIONS', function($scope, $location, $window, NG_VERSIONS) {
$scope.docs_version = NG_VERSIONS[0];
for(var i=0, minor = NaN; i < NG_VERSIONS.length; i++) {
var version = NG_VERSIONS[i];
// NaN will give false here
if (minor <= version.minor) {
continue;
}
version.isLatest = true;
minor = version.minor;
}
$scope.docs_versions = NG_VERSIONS;
$scope.getGroupName = function(v) {
return v.isLatest ? 'Latest' : (v.isStable ? 'Stable' : 'Unstable');
};
$scope.docs_version = NG_VERSIONS[0];
$scope.jumpToDocsVersion = function(version) {
var currentPagePath = $location.path();
// TODO: We need to do some munging of the path for different versions of the API...
$window.location = version.docsUrl + currentPagePath;
};
}]);
}]);
+1 -2
View File
@@ -3,7 +3,6 @@ describe("DocsController", function() {
angular.module('fake', [])
.value('$cookies', {})
.value('openPlunkr', function() {})
.value('NG_PAGES', {})
.value('NG_NAVIGATION', {})
.value('NG_VERSION', {});
@@ -31,4 +30,4 @@ describe("DocsController", function() {
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
}));
});
});
});
-10
View File
@@ -1,10 +0,0 @@
{
"name": "AngularJS-docs-app",
"dependencies": {
"jquery": "2.1.1",
"lunr.js": "0.4.3",
"open-sans-fontface": "1.0.4",
"google-code-prettify": "1.0.1",
"bootstrap": "3.1.1"
}
}
+2 -7
View File
@@ -9,7 +9,7 @@ module.exports = function(config) {
config = basePackage(config);
config = examplesPackage(config);
config.append('processing.processors', [
require('./processors/git-data'),
require('./processors/error-docs'),
@@ -22,12 +22,7 @@ module.exports = function(config) {
]);
config.append('processing.tagDefinitions', [
require('./tag-defs/tutorial-step'),
require('./tag-defs/sortOrder')
]);
config.append('processing.defaultTagTransforms', [
require('dgeni-packages/jsdoc/tag-defs/transforms/trim-whitespace')
require('./tag-defs/tutorial-step')
]);
config.append('processing.inlineTagDefinitions', [
+8 -15
View File
@@ -1,33 +1,26 @@
var fs = require('q-io/fs');
var writer = require('dgeni/lib/utils/doc-writer');
var log = require('winston');
var util = require("util");
var filter, outputPath, depth;
module.exports = {
name: 'debug-dump',
runBefore: ['write-files'],
description: 'This processor dumps docs that match a filter to a file',
process: function(docs, config) {
var filter, outputPath, depth;
init: function(config, injectables) {
filter = config.get('processing.debug-dump.filter');
outputPath = config.get('processing.debug-dump.outputPath');
depth = config.get('processing.debug-dump.depth', 2);
},
process: function(docs) {
if ( filter && outputPath ) {
log.info('Dumping docs:', filter, outputPath);
var filteredDocs = filter(docs);
var dumpedDocs = util.inspect(filteredDocs, depth);
return writeFile(outputPath, dumpedDocs).then(function() {
return writer.writeFile(outputPath, dumpedDocs).then(function() {
return docs;
});
}
}
};
function writeFile(file, content) {
return fs.makeTree(fs.directory(file)).then(function() {
return fs.write(file, content, 'wb');
});
}
};
+11 -13
View File
@@ -5,18 +5,16 @@ var path = require('canonical-path');
module.exports = {
name: 'error-docs',
description: 'Compute the various fields for docs in the Error area',
runAfter: ['tags-extracted', 'compute-path'],
runBefore: ['extra-docs-added'],
exports: {
errorNamespaces: ['factory', function() { return {}; }],
minerrInfo: ['factory', function(config) {
var minerrInfoPath = config.get('processing.errors.minerrInfoPath');
if ( !minerrInfoPath ) {
throw new Error('Error in configuration: Please provide a path to the minerr info file (errors.json) ' +
'in the `config.processing.errors.minerrInfoPath` property');
}
return require(minerrInfoPath);
}]
runAfter: ['tags-extracted'],
init: function(config, injectables) {
injectables.value('errorNamespaces', {});
var minerrInfoPath = config.get('processing.errors.minerrInfoPath');
if ( !minerrInfoPath ) {
throw new Error('Error in configuration: Please provide a path to the minerr info file (errors.json) ' +
'in the `config.processing.errors.minerrInfoPath` property');
}
injectables.value('minerrInfo', require(minerrInfoPath));
},
process: function(docs, partialNames, errorNamespaces, minerrInfo) {
@@ -56,4 +54,4 @@ module.exports = {
return docs.concat(_.values(errorNamespaces));
}
};
};
+8 -10
View File
@@ -3,18 +3,16 @@ var versionInfo = require('../../../lib/versions/version-info');
module.exports = {
name: 'git-data',
runBefore: ['reading-files'],
runBefore: ['loading-files'],
description: 'This processor adds information from the local git repository to the extraData injectable',
exports: {
gitData: ['factory', function() {
return {
version: versionInfo.currentVersion,
versions: versionInfo.previousVersions,
info: versionInfo.gitRepoInfo
};
}]
init: function(config, injectables) {
injectables.value('gitData', {
version: versionInfo.currentVersion,
versions: versionInfo.previousVersions,
info: versionInfo.gitRepoInfo
});
},
process: function(extraData, gitData) {
extraData.git = gitData;
}
};
};
+5 -3
View File
@@ -1,18 +1,20 @@
var _ = require('lodash');
var log = require('winston');
var path = require('canonical-path');
var deployment;
module.exports = {
name: 'index-page',
runAfter: ['adding-extra-docs'],
runBefore: ['extra-docs-added'],
description: 'This processor creates docs that will be rendered as the index page for the app',
process: function(docs, config) {
var deployment = config.deployment;
init: function(config) {
deployment = config.deployment;
if ( !deployment || !deployment.environments ) {
throw new Error('No deployment environments found in the config.');
}
},
process: function(docs) {
// Collect up all the areas in the docs
var areas = {};
+16 -25
View File
@@ -1,23 +1,22 @@
"use strict";
var _ = require('lodash');
var log = require('winston');
var fs = require('fs');
var path = require('canonical-path');
// Keywords to ignore
var wordsToIgnore = [];
var propertiesToIgnore;
var areasToSearch;
// Keywords start with "ng:" or one of $, _ or a letter
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
module.exports = {
name: 'keywords',
runAfter: ['docs-processed', 'api-docs'],
runAfter: ['docs-processed'],
runBefore: ['adding-extra-docs'],
description: 'This processor extracts all the keywords from the document',
process: function(docs, config) {
// Keywords to ignore
var wordsToIgnore = [];
var propertiesToIgnore;
var areasToSearch;
// Keywords start with "ng:" or one of $, _ or a letter
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
init: function(config) {
// Load up the keywords to ignore, if specified in the config
if ( config.processing.search && config.processing.search.ignoreWordsFile ) {
@@ -35,6 +34,9 @@ module.exports = {
propertiesToIgnore = _.indexBy(config.get('processing.search.propertiesToIgnore', []));
log.debug('Properties to ignore', propertiesToIgnore);
},
process: function(docs) {
var ignoreWordsMap = _.indexBy(wordsToIgnore);
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
@@ -53,7 +55,7 @@ module.exports = {
_.forEach(tokens, function(token){
var match = token.match(KEYWORD_REGEX);
if (match){
var key = match[1];
key = match[1];
if ( !keywordMap[key]) {
keywordMap[key] = true;
words.push(key);
@@ -70,31 +72,20 @@ module.exports = {
var words = [];
var keywordMap = _.clone(ignoreWordsMap);
var members = [];
var membersMap = {};
// Search each top level property of the document for search terms
_.forEach(doc, function(value, key) {
if ( _.isString(value) && !propertiesToIgnore[key] ) {
extractWords(value, words, keywordMap);
}
if ( key === 'methods' || key === 'properties' || key === 'events' ) {
_.forEach(value, function(member) {
extractWords(member.name, members, membersMap);
});
}
});
doc.searchTerms = {
titleWords: extractTitleWords(doc.name),
keywords: _.sortBy(words).join(' '),
members: _.sortBy(members).join(' ')
keywords: _.sortBy(words).join(' ')
};
});
}
};
};
+15 -19
View File
@@ -119,32 +119,28 @@ var navGroupMappers = {
})];
},
pages: function(pages, area) {
return [getNavGroup(
pages,
area,
function(page) {
return page.sortOrder || page.path;
},
function(page) {
return {
name: page.name,
href: page.path,
type: 'page'
};
}
)];
return [getNavGroup(pages, area, 'path', function(page) {
return {
name: page.name,
href: page.path,
type: 'page'
};
})];
}
};
var outputFolder;
module.exports = {
name: 'pages-data',
description: 'This plugin will create a new doc that will be rendered as an angularjs module ' +
'which will contain meta information about the pages and navigation',
runAfter: ['adding-extra-docs', 'component-groups-generate', 'compute-path'],
runAfter: ['adding-extra-docs', 'component-groups-generate'],
runBefore: ['extra-docs-added'],
process: function(docs, config) {
var outputFolder = config.rendering.outputFolder;
init: function(config) {
outputFolder = config.rendering.outputFolder;
},
process: function(docs) {
_(docs)
.filter(function(doc) { return doc.area === 'api'; })
@@ -195,7 +191,7 @@ module.exports = {
area.navGroups = navGroupMapper(pages, area);
});
// Extract a list of basic page information for mapping paths to partials and for client side searching
// Extract a list of basic page information for mapping paths to paritals and for client side searching
var pages = _(docs)
.map(function(doc) {
var page = _.pick(doc, [
+29 -27
View File
@@ -1,20 +1,45 @@
var _ = require('lodash');
var log = require('winston');
var path = require('canonical-path');
var trimIndentation = require('dgeni/lib/utils/trim-indentation');
var code = require('dgeni/lib/utils/code');
var protractorFolder;
function createProtractorDoc(example, file, env) {
var protractorDoc = {
docType: 'e2e-test',
id: 'protractorTest' + '-' + example.id,
template: 'protractorTests.template.js',
outputPath: path.join(protractorFolder, example.id, env + '_test.js'),
innerTest: file.fileContents,
pathPrefix: '.', // Hold for if we test with full jQuery
exampleId: example.id,
description: example.doc.id
};
if (env === 'jquery') {
protractorDoc.examplePath = example.outputFolder + '/index-jquery.html'
} else {
protractorDoc.examplePath = example.outputFolder + '/index.html'
}
return protractorDoc;
}
module.exports = {
name: 'protractor-generate',
description: 'Generate a protractor test file from the e2e tests in the examples',
runAfter: ['adding-extra-docs'],
runBefore: ['extra-docs-added'],
process: function(docs, examples, config) {
var protractorFolder = config.get('rendering.protractor.outputFolder', 'ptore2e');
init: function(config, injectables) {
protractorFolder = config.get('rendering.protractor.outputFolder', 'ptore2e');
},
process: function(docs, examples) {
_.forEach(examples, function(example) {
_.forEach(example.files, function(file) {
// Check if it's a Protractor test.
if (file.type !== 'protractor') {
if (!(file.type == 'protractor')) {
return;
}
@@ -23,28 +48,5 @@ module.exports = {
docs.push(createProtractorDoc(example, file, 'jqlite'));
});
});
function createProtractorDoc(example, file, env) {
var protractorDoc = {
docType: 'e2e-test',
id: 'protractorTest' + '-' + example.id,
template: 'protractorTests.template.js',
outputPath: path.join(protractorFolder, example.id, env + '_test.js'),
innerTest: file.fileContents,
pathPrefix: '.', // Hold for if we test with full jQuery
exampleId: example.id,
description: example.doc.id,
'ng-app-included': example['ng-app-included']
};
if (env === 'jquery') {
protractorDoc.examplePath = example.outputFolder + '/index-jquery.html';
} else {
protractorDoc.examplePath = example.outputFolder + '/index.html';
}
return protractorDoc;
}
}
};
+1 -1
View File
@@ -35,4 +35,4 @@ module.exports = {
docs.push(versionDoc);
}
};
};
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
name: 'sortOrder',
transforms: function(doc, tag, value) {
return parseInt(value, 10);
}
};
+2 -2
View File
@@ -1,9 +1,9 @@
module.exports = {
name: 'step',
transforms: function(doc, tag, value) {
transformFn: function(doc, tag) {
if ( doc.docType !== 'tutorial' ) {
throw new Error('Invalid tag, step. You should only use this tag on tutorial docs');
}
return parseInt(value,10);
return parseInt(tag.description,10);
}
};
+1 -1
View File
@@ -14,4 +14,4 @@
{$ doc.description | marked $}
</div>
{% endblock %}
{% endblock %}
@@ -25,4 +25,4 @@
</div>
</div>
{% endblock %}
{% endblock %}
@@ -175,7 +175,7 @@
<div class="container main-grid main-header-grid">
<div class="grid-left">
<div ng-controller="DocsVersionsCtrl" class="picker version-picker">
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by getGroupName(v) for v in docs_versions"
<select ng-options="v as ('v' + v.version + (v.isSnapshot ? ' (snapshot)' : '')) group by (v.isStable?'Stable':'Unstable') for v in docs_versions"
ng-model="docs_version"
ng-change="jumpToDocsVersion(docs_version)"
class="docs-version-jump">
@@ -1,10 +1,7 @@
describe("{$ doc.description $}", function() {
var rootEl;
beforeEach(function() {
rootEl = browser.rootEl;{% if doc['ng-app-included'] %}
browser.rootEl = '[ng-app]';{% endif %}
browser.get("{$ doc.pathPrefix $}/{$ doc.examplePath $}");
});
{% if doc['ng-app-included'] %}afterEach(function() { browser.rootEl = rootEl; });{% endif %}
{$ doc.innerTest $}
});
});
@@ -2,7 +2,7 @@
is HTML and wrap each line in a <p> - thus breaking the HTML #}
<div>
<a ng-click="openPlunkr('{$ doc.example.outputFolder $}')" class="btn pull-right">
<a ng-href="http://plnkr.co/edit/ngdoc:{$ doc.example.id $}@{{docsVersion}}?p=preview" class="btn pull-right" target="_blank">
<i class="glyphicon glyphicon-edit">&nbsp;</i>
Edit in Plunker</a>
<div class="runnable-example"
@@ -15,7 +15,7 @@
{$ attrName $}="{$ attrValue $}"{% endfor %}>
{% code -%}
{$ file.fileContents $}
{%- endcode %}
{%- endcode %}
</div>
{% endfor %}
@@ -24,4 +24,4 @@
</div>
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
+1 -1
View File
@@ -1 +1 @@
{% include 'overview.template.html' %}
{% include 'overview.template.html' %}
+3 -3
View File
@@ -6,7 +6,7 @@
Welcome to the AngularJS API docs page. These pages contain the AngularJS reference materials for version <strong ng-bind="version"></strong>.
The documentation is organized into **{@link guide/module modules}** which contain various components of an AngularJS application.
These components are {@link guide/directive directives}, {@link guide/services services}, {@link guide/filter filters}, {@link guide/providers providers}, {@link guide/templates templates}, global APIs, and testing mocks.
These components are {@link guide/directive directives}, {@link guide/services services}, {@link guide/filter filters}, {@link guide/providers providers}, {@link guide/templates types}, global APIs and testing mocks.
<div class="alert alert-info">
**Angular Namespaces `$` and `$$`**
@@ -212,7 +212,7 @@ Use ngTouch when developing for mobile browsers/devices.
{@link ngTouch#service Services / Factories}
</td>
<td>
The {@link ngTouch.$swipe $swipe} service is used to register and manage mobile DOM events.
The {@link ngTouch.$swipe $swipe} service is used to register and manage mobile DOM events.
</td>
</tr>
<tr>
@@ -252,7 +252,7 @@ Use ngSanitize to securely parse and manipulate HTML data in your application.
## {@link ngMock ngMock}
Use ngMock to inject and mock modules, factories, services and providers within your unit tests
Use ngMock to inject and mock modules, factories, services and providers within your unit tests
<div class="alert alert-info">Include the **angular-mocks.js** file into your test runner for this to work.</div>
+1 -1
View File
@@ -8,7 +8,7 @@ but the required directive controller is not present on the current DOM element
To resolve this error ensure that there is no typo in the required controller name and that the required directive controller is present on the current element.
If the required controller is expected to be on a ancestor element, make sure that you prefix the controller name in the `require` definition with `^`.
If the required controller is expected to be on a ancestor element, make ensure that you prefix the controller name in the `require` definition with `^`.
If the required controller is optionally requested, use `?` or `^?` to specify that.
+1 -1
View File
@@ -16,7 +16,7 @@ myModule.directive('myDirective', function factory() {
return {
...
scope: {
localValue: '=bind'
'bind': '=localValue'
}
...
}
-14
View File
@@ -37,17 +37,3 @@ elements. For example:
```
<b>Hello</b> World!
```
Watch out for html comments at the beginning or end of templates, as these can cause this error as
well. Consider the following template:
```
<div class='container'>
<div class='wrapper>
...
</div> <!-- wrapper -->
</div> <!-- container -->
```
The `<!-- container -->` comment is interpreted as a second root element and causes the template to
be invalid.
+1 -1
View File
@@ -23,4 +23,4 @@ When an instance of `MyCtrl` is created, the service `myService` will be created
by the `$injector`. `myService` depends on itself, which causes the `$injector`
to detect a circular dependency and throw the error.
For more information, see the {@link guide/di Dependency Injection Guide}.
For more information, see the {@link guide/di Dependency Injection Guide}.
+1 -1
View File
@@ -23,4 +23,4 @@ To avoid the error, always use string literals for dependency injection annotati
tokens.
For an explanation of what injection annotations are and how to use them, refer
to the {@link guide/di Dependency Injection Guide}.
to the {@link guide/di Dependency Injection Guide}.
+1 -1
View File
@@ -23,4 +23,4 @@ angular.module("myApp", [])
```
For more information, refer to the {@link auto.$provide#provider
$provide.provider} api doc.
$provide.provider} api doc.
@@ -0,0 +1,54 @@
@ngdoc error
@name $injector:strictdi
@fullName Explicit annotation required
@description
This error occurs when attempting to invoke a function or provider which
has not been explicitly annotated, while the application is running with
strict-di mode enabled.
For example:
```
angular.module("myApp", [])
// BadController cannot be invoked, because
// the dependencies to be injected are not
// explicitly listed.
.controller("BadController", function($scope, $http, $filter) {
// ...
});
```
To fix the error, explicitly annotate the function using either the inline
bracket notation, or with the $inject property:
```
function GoodController1($scope, $http, $filter) {
// ...
}
GoodController1.$inject = ["$scope", "$http", "$filter"];
angular.module("myApp", [])
// GoodController1 can be invoked because it
// had an $inject property, which is an array
// containing the dependency names to be
// injected.
.controller("GoodController1", GoodController1)
// GoodController2 can also be invoked, because
// the dependencies to inject are listed, in
// order, in the array, with the function to be
// invoked trailing on the end.
.controller("GoodController2", [
"$scope",
"$http",
"$filter",
function($scope, $http, $filter) {
// ...
}
]);
```
For more information about strict-di mode, see {@link ng.directive:ngApp ngApp}
and {@link api/angular.bootstrap angular.bootstrap}.
+2 -33
View File
@@ -14,9 +14,8 @@ angular.module('myApp', [])
}]);
```
The above code will fail with `$injector:unpr` if `myService` is not defined.
Making sure each dependency is defined will fix the problem, as noted below.
This code will fail with `$injector:unpr` if `myService` is not defined. Making
sure each dependency is defined will fix the problem.
```
angular.module('myApp', [])
@@ -24,34 +23,4 @@ angular.module('myApp', [])
.controller('MyController', ['myService', function (myService) {
// Do something with myService
}]);
```
An unknown provider error can also be caused by accidentally redefining a
module using the `angular.module` API, as shown in the following example.
```
angular.module('myModule', [])
.service('myCoolService', function () { /* ... */ });
angular.module('myModule', [])
// myModule has already been created! This is not what you want!
.directive('myDirective', ['myCoolService', function (myCoolService) {
// This directive definition throws unknown provider, because myCoolService
// has been destroyed.
}]);
```
To fix this problem, make sure you only define each module with the
`angular.module(name, [requires])` syntax once across your entire project.
Retrieve it for subsequent use with `angular.module(name)`. The fixed example
is shown below.
```
angular.module('myModule', [])
.service('myCoolService', function () { /* ... */ });
angular.module('myModule')
.directive('myDirective', ['myCoolService', function (myCoolService) {
// This directive definition does not throw unknown provider.
}]);
```
@@ -9,4 +9,4 @@ it hard to reason about whether some combination of concatenated values are
unsafe to use and could easily lead to XSS.
For more information about how AngularJS helps keep your app secure, refer to
the {@link ng.$sce $sce} API doc.
the {@link ng.$sce $sce} API doc.
-31
View File
@@ -14,34 +14,3 @@ perform this check - it's up to the developer to not expose such sensitive and p
directly on the scope chain.
To resolve this error, avoid access to DOM nodes.
# Event Handlers and Return Values
The `$parse:isecdom` error also occurs when an event handler invokes a function that returns a DOM
node.
```html
<button ng-click="iWillReturnDOM()">click me</button>
```
```js
$scope.iWillReturnDOM = function() {
return someDomNode;
}
```
To fix this issue, avoid returning DOM nodes from event handlers.
*Note: This error often means that you are accessing DOM from your controllers, which is usually
a sign of poor coding style that violates separation of concerns.*
# Implicit Returns in CoffeeScript
This error can occur more frequently when using CoffeeScript, which has a feature called implicit
returns. This language feature returns the last dereferenced object in the function when the
function has no explicit return statement.
The solution in this scenario is to add an explicit return statement. For example `return false` to
the function.
-17
View File
@@ -1,17 +0,0 @@
@ngdoc error
@name $parse:isecff
@fullName Referencing 'call', 'apply' and 'bind' Disallowed
@description
Occurs when an expression attempts to invoke Function's 'call', 'apply' or 'bind'.
Angular bans the invocation of 'call', 'apply' and 'bind' from within expressions
since access is a known way to modify the behaviour of existing functions.
To resolve this error, avoid using these methods in expressions.
Example expression that would result in this error:
```
<div>{{user.sendInfo.call({}, true)}}</div>
```
+8 -17
View File
@@ -1,27 +1,18 @@
@ngdoc error
@name $parse:isecfld
@fullName Referencing Disallowed Field in Expression
@fullName Referencing 'constructor' Field in Expression
@description
Occurs when an expression attempts to access one of the following fields:
Occurs when an expression attempts to access an objects constructor field.
* __proto__
* __defineGetter__
* __defineSetter__
* __lookupGetter__
* __lookupSetter__
AngularJS bans constructor access from within expressions since constructor
access is a known way to execute arbitrary Javascript code.
AngularJS bans access to these fields from within expressions since
access is a known way to mess with native objects or
to execute arbitrary Javascript code.
To resolve this error, avoid constructor access. As a last resort, alias
the constructor and access it through the alias instead.
To resolve this error, avoid using these fields in expressions. As a last resort,
alias their value and access them through the alias instead.
Example expressions that would result in this error:
Example expression that would result in this error:
```
<div>{{user.__proto__.hasOwnProperty = $emit}}</div>
<div>{{user.__defineGetter__('name', noop)}}</div>
<div>{{user.constructor.name}}</div>
```
-11
View File
@@ -1,11 +0,0 @@
@ngdoc error
@name $parse:isecobj
@fullName Referencing Object Disallowed
@description
Occurs when an expression attempts to access the 'Object' object (Root object in JavaScript).
Angular bans access to Object from within expressions since access is a known way to modify
the behaviour of existing objects.
To resolve this error, avoid Object access.
+1 -1
View File
@@ -5,4 +5,4 @@
Occurs when you try to use the name `hasOwnProperty` as a name of a parameter.
Generally, a name cannot be `hasOwnProperty` because it is used, internally, on a object
and allowing such a name would break lookups on this object.
and allowing such a name would break lookups on this object.
+36 -274
View File
@@ -3,310 +3,72 @@
@fullName Action Already In Progress
@description
At any point in time there can be only one `$digest` or `$apply` operation in progress. This is to
prevent very hard to detect bugs from entering your application. The stack trace of this error
allows you to trace the origin of the currently executing `$apply` or `$digest` call, which caused
the error.
At any point in time there can be only one `$digest` or $apply operation in progress.
The stack trace of this error allows you to trace the origin of the currently executing $apply or $digest call.
## Background
`$digest` or `$apply` are processing operational states of the Scope - data-structure in Angular that provides context for models and enables model mutation observation.
Angular uses a dirty-checking digest mechanism to monitor and update values of the scope during
the processing of your application. The digest works by checking all the values that are being
watched against their previous value and running any watch handlers that have been defined for those
values that have changed.
This digest mechanism is triggered by calling `$digest` on a scope object. Normally you do not need
to trigger a digest manually, because every external action that can trigger changes in your
application, such as mouse events, timeouts or server responses, wrap the Angular application code
in a block of code that will run `$digest` when the code completes.
You wrap Angular code in a block that will be followed by a `$digest` by calling `$apply` on a scope
object. So, in pseudo-code, the process looks like this:
```
element.on('mouseup', function() {
scope.$apply(function() {
$scope.doStuff();
});
});
```
where `$apply()` looks something like:
```
$apply = function(fn) {
try {
fn();
} finally() {
$digest();
}
}
```
## Digest Phases
Angular keeps track of what phase of processing we are in, the relevant ones being `$apply` and
`$digest`. Trying to reenter a `$digest` or `$apply` while one of them is already in progress is
typically a sign of programming error that needs to be fixed. So Angular will throw this error when
that occurs.
In most situations it should be well defined whether a piece of code will be run inside an `$apply`,
in which case you should not be calling `$apply` or `$digest`, or it will be run outside, in which
case you should wrap any code that will be interacting with Angular scope or services, in a call to
`$apply`.
As an example, all Controller code should expect to be run within Angular, so it should have no need
to call `$apply` or `$digest`. Conversely, code that is being trigger directly as a call back to
some external event, from the DOM or 3rd party library, should expect that it is never called from
within Angular, and so any Angular application code that it calls should first be wrapped in a call
to $apply.
## Common Causes
Apart from simply incorrect calls to `$apply` or `$digest` there are some cases when you may get
this error through no fault of your own.
### Inconsistent API (Sync/Async)
Trying to reenter a `$digest` or `$apply` while one of them is already in progress is typically a sign of programming error that needs to be fixed.
This error is often seen when interacting with an API that is sometimes sync and sometimes async.
For example, imagine a 3rd party library that has a method which will retrieve data for us. Since it
may be making an asynchronous call to a server, it accepts a callback function, which will be called
when the data arrives.
For example:
```
function MyController($scope, thirdPartyComponent) {
function MyController() {
thirdPartyComponent.getData(function(someData) {
$scope.$apply(function() {
$scope.someData = someData;
scope.$apply(function() {
scope.someData = someData;
});
});
}
```
We expect that our callback will be called asynchronously, and so from outside Angular. Therefore, we
correctly wrap our application code that interacts with Angular in a call to `$apply`.
The controller constructor is always instantiated from within an $apply cycle, so if the third-party component called our callback synchronously, we'd be trying to enter the $apply again.
The problem comes if `getData()` decides to call the callback handler synchronously; perhaps it has
the data already cached in memory and so it immediately calls the callback to return the data,
synchronously.
To resolve this type of issue, either fix the api to be always synchronous or asynchronous or wrap the call to the api with setTimeout call to make it always asynchronous.
Since, the `MyController` constructor is always instantiated from within an `$apply` call, our
handler is trying to enter a new `$apply` block from within one.
This is not an ideal design choice on the part of the 3rd party library.
Other situation that leads to this error is when you are trying to reuse a function to by using it as a callback for code that is called by various apis inside and outside of $apply.
To resolve this type of issue, either fix the api to be always synchronous or asynchronous or force
your callback handler to always run asynchronously by using the `$timeout` service.
For example:
```
function MyController($scope, thirdPartyComponent) {
thirdPartyComponent.getData(function(someData) {
$timeout(function() {
$scope.someData = someData;
}, 0);
});
}
```
Here we have used `$timeout` to schedule the changes to the scope in a future call stack.
By providing a timeout period of 0ms, this will occur as soon as possible and `$timeout` will ensure
that the code will be called in a single `$apply` block.
### Triggering Events Programmatically
The other situation that often leads to this error is when you trigger code (such as a DOM event)
programmatically (from within Angular), which is normally called by an external trigger.
For example, consider a directive that will set focus on an input control when a value in the scope
is true:
```
myApp.directive('setFocusIf', function() {
myApp.directive('myDirective', function() {
return {
link: function($scope, $element, $attr) {
$scope.$watch($attr.setFocusIf, function(value) {
if ( value ) { $element[0].focus(); }
});
}
};
});
```
link: function($scope, $element) {
function doSomeWork() {
$scope.$apply(function() {
// do work here, and update the model
};
}
If we applied this directive to an input which also used the `ngFocus` directive to trigger some
work when the element receives focus we will have a problem:
```
<input set-focus-if="hasFocus" ng-focus="msg='has focus'">
<button ng-click="hasFocus = true">Focus</button>
```
In this setup, there are two ways to trigger ngFocus. First from a user interaction:
* Click on the input control
* The input control gets focus
* The `ngFocus` directive is triggered, setting `$scope.msg='has focus'` from within a new call to
`$apply()`
Second programmatically:
* Click the button
* The `ngClick` directive sets the value of `$scope.hasFocus` to true inside a call to `$apply`
* The `$digest` runs, which triggers the watch inside the `setFocusIf` directive
* The watch's handle runs, which gives the focus to the input
* The `ngFocus` directive is triggered, setting `$scope.msg='has focus'` from within a new call to
`$apply()`
In this second scenario, we are already inside a `$digest` when the ngFocus directive makes another
call to `$apply()`, causing this error to be thrown.
It is possible to workaround this problem by moving the call to set the focus outside of the digest,
by using `$timeout(fn, 0, false)`, where the `false` value tells Angular not to wrap this `fn` in a
`$apply` block:
```
myApp.directive('setFocusIf', function($timeout) {
return {
link: function($scope, $element, $attr) {
$scope.$watch($attr.setFocusIf, function(value) {
if ( value ) {
$timeout(function() {
// We must reevaluate the value in case it was changed by a subsequent
// watch handler in the digest.
if ( $scope.$eval($attr.setFocusIf) ) {
$element[0].focus();
}
}, 0, false);
}
});
$element.on('click', doSomeWork);
doSomeWork(); // << this will throw an exception because templates are compiled within $apply
}
}
});
```
## Diagnosing This Error
When you get this error it can be rather daunting to diagnose the cause of the issue. The best
course of action is to investigate the stack trace from the error. You need to look for places
where `$apply` or `$digest` have been called and find the context in which this occurred.
There should be two calls:
* The first call is the good `$apply`/`$digest` and would normally be triggered by some event near
the top of the call stack.
* The second call is the bad `$apply`/`$digest` and this is the one to investigate.
Once you have identified this call you work your way up the stack to see what the problem is.
* If the second call was made in your application code then you should look at why this code has been
called from within a `$apply`/`$digest`. It may be a simple oversight or maybe it fits with the
sync/async scenario described earlier.
* If the second call was made inside an Angular directive then it is likely that it matches the second
programmatic event trigger scenario described earlier. In this case you may need to look further up
the tree to what triggered the event in the first place.
### Example Problem
Let's look at how to investigate this error using the `setFocusIf` example from above. This example
defines a new `setFocusIf` directive that sets the focus on the element where it is defined when the
value of its attribute becomes true.
<example name="error-$rootScope-inprog" module="app">
<file name="index.html">
<button ng-click="focusInput = true">Focus</button>
<input ng-focus="count = count + 1" set-focus-if="focusInput" />
</file>
<file name="app.js">
angular.module('app', []).directive('setFocusIf', function() {
return function link($scope, $element, $attr) {
$scope.$watch($attr.setFocusIf, function(value) {
if ( value ) { $element[0].focus(); }
});
};
});
</file>
</example>
When you click on the button to cause the focus to occur we get our `$rootScope:inprog` error. The
stacktrace looks like this:
```
Error: [$rootScope:inprog]
at Error (native)
at angular.min.js:6:467
at n (angular.min.js:105:60)
at g.$get.g.$apply (angular.min.js:113:195)
at HTMLInputElement.<anonymous> (angular.min.js:198:401)
at angular.min.js:32:32
at Array.forEach (native)
at q (angular.min.js:7:295)
at HTMLInputElement.c (angular.min.js:32:14)
at Object.fn (app.js:12:38) angular.js:10111
(anonymous function) angular.js:10111
$get angular.js:7412
$get.g.$apply angular.js:12738 <--- $apply
(anonymous function) angular.js:19833 <--- called here
(anonymous function) angular.js:2890
q angular.js:320
c angular.js:2889
(anonymous function) app.js:12
$get.g.$digest angular.js:12469
$get.g.$apply angular.js:12742 <--- $apply
(anonymous function) angular.js:19833 <--- called here
(anonymous function) angular.js:2890
q angular.js:320
The fix for the example above looks like this:
```
myApp.directive('myDirective', function() {
return {
link: function($scope, $element) {
function doSomeWork() {
// do work here, and update the model
}
We can see (even though the Angular code is minified) that there were two calls to `$apply`, first
on line `19833`, then on line `12738` of `angular.js`.
$element.on('click', function() {
$scope.$apply(doSomeWork); // <<< the $apply call was moved to the callsite that doesn't execute in $apply call already
});
It is this second call that caused the error. If we look at the angular.js code, we can see that
this call is made by an Angular directive.
```
var ngEventDirectives = {};
forEach(
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
function(name) {
var directiveName = directiveNormalize('ng-' + name);
ngEventDirectives[directiveName] = ['$parse', function($parse) {
return {
compile: function($element, attr) {
var fn = $parse(attr[directiveName]);
return function(scope, element, attr) {
element.on(lowercase(name), function(event) {
scope.$apply(function() {
fn(scope, {$event:event});
});
});
};
}
};
}];
doSomeWork();
}
}
);
```
It is not possible to tell which from the stack trace, but we happen to know in this case that it is
the `ngFocus` directive.
Now look up the stack to see that our application code is only entered once in `app.js` at line `12`.
This is where our problem is:
});
```
10: link: function($scope, $element, $attr) {
11: $scope.$watch($attr.setFocusIf, function(value) {
12: if ( value ) { $element[0].focus(); } <---- This is the source of the problem
13: });
14: }
```
We can now see that the second `$apply` was caused by us programmatically triggering a DOM event
(i.e. focus) to occur. We must fix this by moving the code outside of the $apply block using
`$timeout` as described above.
## Further Reading
To learn more about Angular processing model please check out the
{@link guide/concepts concepts doc} as well as the {@link ng.$rootScope.Scope api} doc.
To learn more about Angular processing model please check out the {@link guide/concepts concepts doc} as well as the {@link ng.$rootScope.Scope api} doc.
+3 -3
View File
@@ -15,9 +15,9 @@ By default, only URLs that belong to the same origin are trusted. These are urls
The {@link ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
To load templates from other domains and/or protocols, either adjust the {@link
ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
api/ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
api/ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
api/ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
**Note**: The browser's [Same Origin
Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) and
+2 -3
View File
@@ -10,7 +10,6 @@ Angular's {@link ng.$sce Strict Contextual Escaping (SCE)} mode
contexts to result in a value that is trusted as safe for use in such a context. (e.g. loading an
Angular template from a URL requires that the URL is one considered safe for loading resources.)
This helps prevent XSS and other security issues. Read more at
{@link ng.$sce Strict Contextual Escaping (SCE)}
This helps prevent XSS and other security issues. Read more at {@link
api/ng.$sce Strict Contextual Escaping (SCE)}
You may want to include the ngSanitize module to use the automatic sanitizing.
+1 -1
View File
@@ -5,4 +5,4 @@
AngularJS often asserts that certain values will be present and truthy using a
helper function. If the assertion fails, this error is thrown. To fix this problem,
make sure that the value the assertion expects is defined and truthy.
make sure that the value the assertion expects is defined and truthy.
+1 -1
View File
@@ -5,4 +5,4 @@
Occurs when you try to use the name `hasOwnProperty` in a context where it is not allow.
Generally, a name cannot be `hasOwnProperty` because it is used, internally, on a object
and allowing such a name would break lookups on this object.
and allowing such a name would break lookups on this object.
+1 -1
View File
@@ -49,4 +49,4 @@ You can also get this error if you accidentally load AngularJS itself more than
<script src="angular.js"></script>
</body>
</html>
```
```
+1 -1
View File
@@ -7,4 +7,4 @@ This error occurs when attempting to copy an object to itself. Calling {@link
api/angular.copy angular.copy} with a `destination` object deletes
all of the elements or properties on `destination` before copying to it. Copying
an object to itself is not supported. Make sure to check your calls to
`angular.copy` and avoid copying objects or arrays to themselves.
`angular.copy` and avoid copying objects or arrays to themselves.
+1 -1
View File
@@ -7,4 +7,4 @@ Copying Window or Scope instances is not supported because of cyclical and self
references. Avoid copying windows and scopes, as well as any other cyclical or
self-referential structures. Note that trying to deep copy an object containing
cyclical references that is neither a window nor a scope will cause infinite
recursion and a stack overflow.
recursion and a stack overflow.
+140 -320
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Using $location
@sortOrder 500
@description
# What does it do?
@@ -50,7 +49,7 @@ changes to $location are reflected into the browser address bar.
<tr>
<td class="head">integration with angular application life-cycle</td>
<td>none</td>
<td>knows about all internal life-cycle phases, integrates with {@link ng.$rootScope.Scope#$watch $watch}, ...</td>
<td>knows about all internal life-cycle phases, integrates with $watch, ...</td>
</tr>
<tr>
@@ -61,7 +60,7 @@ changes to $location are reflected into the browser address bar.
<tr>
<td class="head">aware of docroot/context from which the application is loaded</td>
<td>no - window.location.pathname returns "/docroot/actual/path"</td>
<td>no - window.location.path returns "/docroot/actual/path"</td>
<td>yes - $location.path() returns "/actual/path"</td>
</tr>
@@ -238,6 +237,20 @@ it('should show example', inject(
));
```
### Crawling your app
To allow indexing of your AJAX application, you have to add special meta tag in the head section of
your document:
```html
<meta name="fragment" content="!" />
```
This will cause crawler bot to request links with `_escaped_fragment_` param so that your server
can recognize the crawler and serve a HTML snapshots. For more information about this technique,
see [Making AJAX Applications
Crawlable](http://code.google.com/web/ajaxcrawling/docs/specification.html).
## HTML5 mode
In HTML5 mode, the `$location` service getters and setters interact with the browser URL address
@@ -331,6 +344,20 @@ are not prefixed with `.` and will not be intercepted by the `otherwise` rule in
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
to entry point of your application (e.g. index.html)
### Crawling your app
If you want your AJAX application to be indexed by web crawlers, you will need to add the following
meta tag to the HEAD section of your document:
```html
<meta name="fragment" content="!" />
```
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 [Making AJAX
Applications Crawlable](http://code.google.com/web/ajaxcrawling/docs/specification.html).
### Relative links
Be sure to check all relative links, images, scripts etc. You must either specify the url base in
@@ -359,309 +386,119 @@ Note that when you type hashbang url into first browser (or vice versa) it doesn
redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL
= on page reload.
In these examples we use `<base href="/base/index.html" />`
#### Browser in HTML5 mode
<example module="html5-mode" name="location-html5-mode">
In this examples we use `<base href="/base/index.html" />`
<example>
<file name="index.html">
<div ng-controller="LocationController">
<div ng-address-bar></div><br><br>
<div>
$location.protocol() = <span ng-bind="$location.protocol()"></span> <br>
$location.host() = <span ng-bind="$location.host()"></span> <br>
$location.port() = <span ng-bind="$location.port()"></span> <br>
$location.path() = <span ng-bind="$location.path()"></span> <br>
$location.search() = <span ng-bind="$location.search()"></span> <br>
$location.hash() = <span ng-bind="$location.hash()"></span> <br>
</div>
<div id="navigation">
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
<div id="html5-mode" ng-controller="Html5Cntl">
<h3>Browser with History API</h3>
<div ng-address-bar browser="html5"></div><br><br>
$location.protocol() = {{$location.protocol()}}<br>
$location.host() = {{$location.host()}}<br>
$location.port() = {{$location.port()}}<br>
$location.path() = {{$location.path()}}<br>
$location.search() = {{$location.search()}}<br>
$location.hash() = {{$location.hash()}}<br>
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
<div id="hashbang-mode" ng-controller="HashbangCntl">
<h3>Browser without History API</h3>
<div ng-address-bar browser="hashbang"></div><br><br>
$location.protocol() = {{$location.protocol()}}<br>
$location.host() = {{$location.host()}}<br>
$location.port() = {{$location.port()}}<br>
$location.path() = {{$location.path()}}<br>
$location.search() = {{$location.search()}}<br>
$location.hash() = {{$location.hash()}}<br>
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
</file>
<file name="app.js">
angular.module('html5-mode', ['fake-browser', 'address-bar'])
.constant('initUrl', 'http://www.example.com/base/path?a=b#h')
.constant('baseHref', '/base/index.html')
.value('$sniffer', { history: true })
.controller("LocationController", function($scope, $location) {
$scope.$location = {};
angular.forEach("protocol host port path search hash".split(" "), function(method){
$scope.$location[method] = function(){
var result = $location[method].call($location);
return angular.isObject(result) ? angular.toJson(result) : result;
};
});
})
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
.run(function($rootElement) {
$rootElement.on('click', function(e) { e.stopPropagation(); });
});
</file>
<file name="fakeBrowser.js">
angular.module('fake-browser', [])
.config(function($provide) {
$provide.decorator('$browser', function($delegate, baseHref, initUrl) {
$delegate.onUrlChange = function(fn) {
this.urlChange = fn;
};
$delegate.url = function() {
return initUrl;
<file name="script.js">
function FakeBrowser(initUrl, baseHref) {
this.onUrlChange = function(fn) {
this.urlChange = fn;
};
$delegate.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
this.url = function() {
return initUrl;
};
$delegate.baseHref = function() {
return baseHref;
};
this.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
return $delegate;
});
});
</file>
this.baseHref = function() {
return baseHref;
};
<file name="addressBar.js">
angular.module('address-bar', [])
.directive('ngAddressBar', function($browser, $timeout) {
return {
template: 'Address: <input id="addressBar" type="text" style="width: 400px" >',
link: function(scope, element, attrs){
var input = element.children("input"), delay;
this.notifyWhenOutstandingRequests = angular.noop;
}
input.on('keypress keyup keydown', function(event) {
delay = (!delay ? $timeout(fireUrlChange, 250) : null);
event.stopPropagation();
})
.val($browser.url());
var browsers = {
html5: new FakeBrowser('http://www.example.com/base/path?a=b#h', '/base/index.html'),
hashbang: new FakeBrowser('http://www.example.com/base/index.html#!/path?a=b#h', '/base/index.html')
};
$browser.url = function(url) {
return url ? input.val(url) : input.val();
function Html5Cntl($scope, $location) {
$scope.$location = $location;
}
function HashbangCntl($scope, $location) {
$scope.$location = $location;
}
function initEnv(name) {
var root = angular.element(document.getElementById(name + '-mode'));
// We must kill a link to the injector for this element otherwise angular will
// complain that it has been bootstrapped already.
root.data('$injector', null);
angular.bootstrap(root, [function($compileProvider, $locationProvider, $provide){
$locationProvider.html5Mode(true).hashPrefix('!');
$provide.value('$browser', browsers[name]);
$provide.value('$sniffer', {history: name == 'html5'});
$compileProvider.directive('ngAddressBar', function() {
return function(scope, elm, attrs) {
var browser = browsers[attrs.browser],
input = angular.element('<input type="text" style="width: 400px">').val(browser.url()),
delay;
input.on('keypress keyup keydown', function() {
if (!delay) {
delay = setTimeout(fireUrlChange, 250);
}
});
browser.url = function(url) {
return input.val(url);
};
elm.append('Address: ').append(input);
function fireUrlChange() {
delay = null;
browser.urlChange(input.val());
}
};
function fireUrlChange() {
delay = null;
$browser.urlChange(input.val());
}
}
};
});
</file>
<file name="protractor.js" type="protractor">
var addressBar = element(by.css("#addressBar")),
url = 'http://www.example.com/base/path?a=b#h';
it("should show fake browser info on load", function(){
expect(addressBar.getAttribute('value')).toBe(url);
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/path');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('h');
});
it("should change $location accordingly", function(){
var navigation = element.all(by.css("#navigation a"));
navigation.get(0).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/first?a=b");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/first');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('');
navigation.get(1).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/sec/ond?flag#hash");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
});
</file>
</example>
####Browser in HTML5 Fallback mode (Hashbang mode)
<example module="hashbang-mode" name="location-hashbang-mode">
<file name="index.html">
<div ng-controller="LocationController">
<div ng-address-bar></div><br><br>
<div>
$location.protocol() = <span ng-bind="$location.protocol()"></span> <br>
$location.host() = <span ng-bind="$location.host()"></span> <br>
$location.port() = <span ng-bind="$location.port()"></span> <br>
$location.path() = <span ng-bind="$location.path()"></span> <br>
$location.search() = <span ng-bind="$location.search()"></span> <br>
$location.hash() = <span ng-bind="$location.hash()"></span> <br>
</div>
<div id="navigation">
<a href="http://www.example.com/base/first?a=b">/base/first?a=b</a> |
<a href="http://www.example.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> |
<a href="/other-base/another?search">external</a>
</div>
</div>
</file>
<file name="app.js">
angular.module('hashbang-mode', ['fake-browser', 'address-bar'])
.constant('initUrl', 'http://www.example.com/base/index.html#!/path?a=b#h')
.constant('baseHref', '/base/index.html')
.value('$sniffer', { history: false })
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
.controller("LocationController", function($scope, $location) {
$scope.$location = {};
angular.forEach("protocol host port path search hash".split(" "), function(method){
$scope.$location[method] = function(){
var result = $location[method].call($location);
return angular.isObject(result) ? angular.toJson(result) : result;
};
});
})
.run(function($rootElement) {
$rootElement.on('click', function(e) {
});
}]);
root.on('click', function(e) {
e.stopPropagation();
});
});
}
initEnv('html5');
initEnv('hashbang');
</file>
<file name="fakeBrowser.js">
angular.module('fake-browser', [])
.config(function($provide) {
$provide.decorator('$browser', function($delegate, baseHref, initUrl) {
$delegate.onUrlChange = function(fn) {
this.urlChange = fn;
};
$delegate.url = function() {
return initUrl;
};
$delegate.defer = function(fn, delay) {
setTimeout(function() { fn(); }, delay || 0);
};
$delegate.baseHref = function() {
return baseHref;
};
return $delegate;
});
});
</file>
<file name="addressBar.js">
angular.module('address-bar', [])
.directive('ngAddressBar', function($browser, $timeout) {
return {
template: 'Address: <input id="addressBar" type="text" style="width: 400px" >',
link: function(scope, element, attrs){
var input = element.children("input"), delay;
input.on('keypress keyup keydown', function(event) {
delay = (!delay ? $timeout(fireUrlChange, 250) : null);
event.stopPropagation();
})
.val($browser.url());
$browser.url = function(url) {
return url ? input.val(url) : input.val();
};
function fireUrlChange() {
delay = null;
$browser.urlChange(input.val());
}
}
};
});
</file>
<file name="protractor.js" type="protractor">
var addressBar = element(by.css("#addressBar")),
url = 'http://www.example.com/base/index.html#!/path?a=b#h';
it("should show fake browser info on load", function(){
expect(addressBar.getAttribute('value')).toBe(url);
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/path');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('h');
});
it("should change $location accordingly", function(){
var navigation = element.all(by.css("#navigation a"));
navigation.get(0).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/first?a=b");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/first');
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
expect(element(by.binding('$location.hash')).getText()).toBe('');
navigation.get(1).click();
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/sec/ond?flag#hash");
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
expect(element(by.binding('$location.port')).getText()).toBe('80');
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
});
</file>
</example>
# Caveats
## Page reload navigation
@@ -673,12 +510,10 @@ use a lower level API, {@link ng.$window $window.location.href}.
## Using $location outside of the scope life-cycle
`$location` knows about Angular's {@link ng.$rootScope.Scope scope} life-cycle. When a URL changes in
the browser it updates the `$location` and calls `$apply` so that all
{@link ng.$rootScope.Scope#$watch $watchers} /
{@link ng.$compile.directive.Attributes#$observe $observers} are notified.
the browser it updates the `$location` and calls `$apply` so that all $watchers / $observers are
notified.
When you change the `$location` inside the `$digest` phase everything is ok; `$location` will
propagate this change into browser and will notify all the {@link ng.$rootScope.Scope#$watch $watchers} /
{@link ng.$compile.directive.Attributes#$observe $observers}.
propagate this change into browser and will notify all the $watchers / $observers.
When you want to change the `$location` from outside Angular (for example, through a DOM Event or
during testing) - you must call `$apply` to propagate the changes.
@@ -690,20 +525,6 @@ forward slash if it is missing.
Note that the `!` prefix in the hashbang mode is not part of `$location.path()`; it is actually
hashPrefix.
## Crawling your app
To allow indexing of your AJAX application, you have to add special meta tag in the head section of
your document:
```html
<meta name="fragment" content="!" />
```
This will cause crawler bot to request links with `_escaped_fragment_` param so that your server
can recognize the crawler and serve a HTML snapshots. For more information about this technique,
see [Making AJAX Applications
Crawlable](http://code.google.com/web/ajaxcrawling/docs/specification.html).
# Testing with the $location service
@@ -811,26 +632,25 @@ then uses the information it obtains to compose hashbang URLs (such as
The Angular's compiler currently does not support two-way binding for methods (see [issue](https://github.com/angular/angular.js/issues/404)). If you should require two-way binding
to the $location object (using {@link input[text] ngModel} directive on an input
field), you will need to specify an extra model property (e.g. `locationPath`) with two {@link ng.$rootScope.Scope#$watch $watchers}
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 module="locationExample">
<example>
<file name="index.html">
<div ng-controller="LocationController">
<input type="text" ng-model="locationPath" />
</div>
</file>
<file name="script.js">
angular.module('locationExample', [])
.controller('LocationController', ['$scope', '$location', function ($scope, $location) {
$scope.$watch('locationPath', function(path) {
$location.path(path);
});
$scope.$watch(function() {
return $location.path();
}, function(path) {
$scope.locationPath = path;
});
}]);
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>
+9 -13
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Animations
@sortOrder 310
@description
@@ -252,18 +251,15 @@ Although the CSS is a little different then what we saw before, the idea is the
A handful of common AngularJS directives support and trigger animation hooks whenever any major event occurs during its life cycle.
The table below explains in detail which animation events are triggered
-| Directive | Supported Animations |
-|-----------------------------------------------------------------|--------------------------------------------------------------------------|
-| {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
-| {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
-| {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
-| {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
-| {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
-| {@link ng.directive:ngClass#usage_animations ngClass} | add and remove |
-| {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
-| {@link ng.directive:form#usage_animations form} | add and remove (dirty, pristine, valid, invalid & all other validations) |
-| {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
| Directive | Supported Animations |
|-------------------------------------------------------------------------------------|------------------------------------------|
| {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave, and move |
| {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
| {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
| {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
| {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
| {@link ng.directive:ngClass#usage_animations ngClass or &#123;&#123;class&#125;&#125;} | add and remove |
| {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
For a full breakdown of the steps involved during each animation event, refer to the {@link ngAnimate.$animate API docs}.
+2 -3
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Bootstrap
@sortOrder 350
@description
# Bootstrap
@@ -91,8 +90,8 @@ Here is an example of manually initializing Angular:
<!doctype html>
<html>
<body>
Hello {{greetMe}}!
<script src="http://code.angularjs.org/snapshot/angular.js"></script>
Hello {{'World'}}!
<script src="http://code.angularjs.org/angular.js"></script>
<script>
angular.module('myApp', [])
+3 -4
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name HTML Compiler
@sortOrder 330
@description
<div class="alert alert-warning">
@@ -199,7 +198,7 @@ This should help give you an idea of what Angular does internally.
// Step 3: link the compiled template with the scope.
var element = linkFn(scope);
// Step 4: Append to DOM (optional)
parent.appendChild(element);
```
@@ -227,7 +226,7 @@ moved to the compile function for performance reasons.
To understand, let's look at a real-world example with `ngRepeat`:
```html
Hello {{user.name}}, you have these actions:
Hello {{user}}, you have these actions:
<ul>
<li ng-repeat="action in user.actions">
{{action.description}}
@@ -237,7 +236,7 @@ Hello {{user.name}}, you have these actions:
When the above example is compiled, the compiler visits every node and looks for directives.
`{{user.name}}` matches the {@link ng.$interpolate interpolation directive}
`{{user}}` matches the {@link ng.$interpolate interpolation directive}
and `ng-repeat` matches the {@link ng.directive:ngRepeat `ngRepeat` directive}.
But {@link ng.directive:ngRepeat ngRepeat} has a dilemma.
+12 -10
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Conceptual Overview
@sortOrder 200
@description
# Conceptual Overview
@@ -12,7 +11,7 @@ For a more in-depth explanation, see the {@link tutorial/ tutorial}.
|------------------|------------------------------------------|
|{@link concepts#template Template} | HTML with additional markup |
|{@link concepts#directive Directives} | extend HTML with custom attributes and elements |
|{@link concepts#model Model} | the data shown to the user in the view and with which the user interacts |
|{@link concepts#model Model} | the data that is shown to the user and with which the user interacts |
|{@link concepts#scope Scope} | context where the model is stored so that controllers, directives and expressions can access it |
|{@link concepts#expression Expressions} | access variables and functions from the scope |
|{@link concepts#compiler Compiler} | parses the template and instantiates directives and expressions |
@@ -20,9 +19,9 @@ For a more in-depth explanation, see the {@link tutorial/ tutorial}.
|{@link concepts#view View} | what the user sees (the DOM) |
|{@link concepts#databinding Data Binding} | sync data between the model and the view |
|{@link concepts#controller Controller} | the business logic behind views |
|{@link concepts#di Dependency Injection} | Creates and wires objects and functions |
|{@link concepts#di Dependency Injection} | Creates and wires objects / functions |
|{@link concepts#injector Injector} | dependency injection container |
|{@link concepts#module Module} | a container for the different parts of an app including controllers, services, filters, directives which configures the Injector |
|{@link concepts#module Module} | configures the Injector |
|{@link concepts#service Service} | reusable business logic independent of views |
@@ -38,10 +37,10 @@ Let's start with input fields for quantity and cost whose values are multiplied
<div ng-app ng-init="qty=1;cost=2">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="qty">
Quantity: <input type="number" ng-model="qty" required >
</div>
<div>
Costs: <input type="number" ng-model="cost">
Costs: <input type="number" ng-model="cost" required >
</div>
<div>
<b>Total:</b> {{qty * cost | currency}}
@@ -63,8 +62,11 @@ The first kind of new markup are the so called <a name="directive">"{@link direc
They apply special behavior to attributes or elements in the HTML. In the example above we use the
{@link ng.directive:ngApp `ng-app`} attribute, which is linked to a directive that automatically
initializes our application. Angular also defines a directive for the {@link ng.directive:input `input`}
element that adds extra behavior to the element. The {@link ng.directive:ngModel `ng-model`} directive
stores/updates the value of the input field into/from a variable.
element that adds extra behavior to the element. E.g. it is able to automatically validate that the entered
text is non empty by evaluating the `required` attribute.
The {@link ng.directive:ngModel `ng-model`} directive stores/updates
the value of the input field into/from a variable and shows the validation state of the input field by
adding css classes. In the example we use these css classes to mark an empty input field with a red border.
<div class="alert alert-info">
**Custom directives to access the DOM**: In Angular, the only place where an application touches the DOM is
@@ -252,7 +254,7 @@ Let's refactor our example and move the currency conversion into a service in an
What changed?
We moved the `convertCurrency` function and the definition of the existing currencies
into the new file `finance2.js`. But how does the controller
into the new file `finance.js`. But how does the controller
get a hold of the now separated function?
This is where <a name="di">"{@link di Dependency Injection}"</a> comes into play.
@@ -321,7 +323,7 @@ The following example shows how this is done with Angular:
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'//query.yahooapis.com/v1/public/yql?q=select * from '+
'http://query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
var currencies = ['USD', 'EUR', 'CNY'];
+28 -22
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Controllers
@sortOrder 220
@description
# Understanding Controllers
@@ -38,8 +37,27 @@ The properties contain the **view model** (the model that will be presented by t
`$scope` properties will be available to the template at the point in the DOM where the Controller
is registered.
The following example demonstrates creating a `GreetingController`, which attaches a `greeting`
property containing the string `'Hola!'` to the `$scope`:
The following example shows a very simple constructor function for a Controller, `GreetingController`,
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
```js
function GreetingController($scope) {
$scope.greeting = 'Hola!';
}
```
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
template:
```js
<div ng-controller="GreetingController">
{{ greeting }}
</div>
```
**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is
not recommended. In a real application you should use the `.controller` method of your
{@link module Angular Module} for your application as follows:
```js
var myApp = angular.module('myApp',[]);
@@ -49,24 +67,9 @@ myApp.controller('GreetingController', ['$scope', function($scope) {
}]);
```
We create an {@link module Angular Module}, `myApp`, for our application. Then we add the controller's
constructor function to the module using the `.controller()` method. This keeps the controller's
constructor function out of the global scope.
<div class="alert alert-info">
We have used an **inline injection annotation** to explicitly specify the dependency
of the Controller on the `$scope` service provided by Angular. See the guide on
{@link guide/di Dependency Injection} for more information.
</div>
We attach our controller to the DOM using the `ng-controller` directive. The `greeting` property can
now be data-bound to the template:
```js
<div ng-controller="GreetingController">
{{ greeting }}
</div>
```
[Dependency Injection](http://docs.angularjs.org/guide/di) for more information.
# Adding Behavior to a Scope Object
@@ -240,7 +243,7 @@ more information about scope inheritance.
}]);
myApp.controller('GrandChildController', ['$scope', function($scope) {
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbread Baby';
$scope.name = 'Gingerbreak Baby';
}]);
</file>
</example>
@@ -270,8 +273,8 @@ involves injecting the {@link ng.$rootScope $rootScope} and {@link ng.$controlle
myApp.controller('MyController', function($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiciness":"hot hot hot!"},
{"name":"habanero", "spiciness":"LAVA HOT!!"}];
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
$scope.spice = "habanero";
});
```
@@ -330,3 +333,6 @@ describe('state', function() {
});
});
```
+1 -2
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Working With CSS
@sortOrder 510
@description
@@ -9,7 +8,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s
# CSS classes used by angular
* `ng-scope`
- **Usage:** angular applies this class to any element for which a new {@link api/ng.$rootScope.Scope scope}
- **Usage:** angular applies this class to any element that where a new {@link ng.$rootScope.Scope scope}
is defined. (see {@link guide/scope scope} guide for more information about scopes)
* `ng-binding`
+2 -3
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Data Binding
@sortOrder 210
@description
Data-binding in Angular apps is the automatic synchronization of data between the model and view
@@ -10,7 +9,7 @@ When the model changes, the view reflects the change, and vice versa.
## Data Binding in Classical Template Systems
<img class="right" src="img/One_Way_Data_Binding.png"/><br />
<img class="right" src="img/One_Way_Data_Binding.png"/>
Most templating systems bind data in only one direction: they merge template and model components
together into a view. After the merge occurs, changes to the model
or related sections of the view are NOT automatically reflected in the view. Worse, any changes
@@ -19,7 +18,7 @@ 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"/><br />
<img class="right" src="img/Two_Way_Data_Binding.png"/>
Angular templates work differently. First the template (which is the uncompiled HTML along with
any additional markup or directives) is compiled on the browser. The compilation step produces a
live view. Any changes to the view are immediately reflected in the model, and any changes in
+16 -24
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Dependency Injection
@sortOrder 250
@description
# Dependency Injection
@@ -110,7 +109,7 @@ asks the injector to create an instance of the controller and its dependencies.
injector.instantiate(MyController);
```
This is all done behind the scenes. Notice that by having the `ng-controller` ask the injector to
This is all done behinds the scenes. Notice that by having the `ng-controller` ask the injector to
instantiate the class, it can satisfy all of the dependencies of `MyController` without the
controller ever knowing about the injector.
@@ -136,7 +135,7 @@ These can be used interchangeably as you see fit and are equivalent.
### Implicit Dependencies
The simplest way to get hold of the dependencies is to assume that the function parameter names
The simplest way to get hold of the dependencies, is to assume that the function parameter names
are the names of the dependencies.
```js
@@ -145,7 +144,7 @@ function MyController($scope, greeter) {
}
```
Given a function the injector can infer the names of the services to inject by examining the
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.
@@ -155,7 +154,7 @@ rename the method parameter names. This makes this way of annotating only useful
### `$inject` Property Annotation
To allow the minifiers to rename the function parameters and still be able to inject the right services,
To allow the minifers to rename the function parameters and still be able to inject right services,
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
of service names to inject.
@@ -167,7 +166,7 @@ MyController['$inject'] = ['$scope', 'greeter'];
```
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
arguments to inject. Using the above code snippet as an example, `$scope` will be injected into
arguments to inject. Using above code snippet as an example, `$scope` will be injected into
`renamed$scope` and `greeter` into `renamedGreeter`. Care must be taken that the `$inject`
annotation is kept in sync with the actual arguments in the function declaration.
@@ -207,8 +206,8 @@ someModule.factory('greeter', ['$window', function(renamed$window) {
}]);
```
Here, instead of simply providing the factory function, we pass an array whose elements consist of
a list of strings (the names of the dependencies) followed by the function itself.
Here, instead of simply providing the factory function, we pass an array, whose elements consist of
a list of strings (the names of the depenendencies) followed by the function itself.
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
where injection is supported.
@@ -219,22 +218,15 @@ DI is pervasive throughout Angular. You can use it when defining components or w
and `config` blocks for a module.
- Components such as services, directives, filters and animations are defined by an injectable factory
method or constructor function. These components can be injected with "service" and "value"
method or constructor function. These components can be injected with "service" components as
dependencies.
- The `run` and `config` methods accept a function, which can also be injected with "service"
components as dependencies.
- The `run` method accepts a function, which can be injected with "service", "value" and "constant"
components as dependencies. Note that you cannot inject "providers" into `run` blocks.
- The `config` method accepts a function, which can be injected with "provider" and "constant"
components as dependencies. Note that you cannot inject "service" or "value" components into
configuration
- Controllers are defined by a constructor function, which can be injected with any of the "service"
and "value" components as dependencies, but they can also be provided with special dependencies. See
{@link di#controllers Controllers} below for a list of these special dependencies.
See {@link module#module-loading-dependencies Modules} for more details about injecting dependencies
into `run` and `config` blocks.
- Controllers are defined by an constructor function, which can be injected with any of the "service"
components as dependencies, but they can also be provided with special dependencies. See "DI in
Controllers" below.
### Factory Methods
@@ -296,7 +288,7 @@ application. For example, there would be one instance for every `ng-controller`
Moreover, additional dependencies are made available to Controllers:
* {@link scope `$scope`}: Controllers are always associated with a point in the DOM and so are provided with
access to the {@link scope scope} at that point. Other components, such as services only have access to the
access to the {@link scope scope} at that point. Other components, such as servies only have access to the
singleton {@link $rootScope} service.
* {@link $route} resolves: If a controller is instantiated as part of a route, then any values that
are resolved as part of the route are made available for injection into the controller.
are resolved as part of the route are made available for injection into the controller.
+6 -35
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Directives
@sortOrder 300
@description
# Creating Custom Directives
@@ -283,7 +282,7 @@ using `templateUrl` instead:
Great! But what if we wanted to have our directive match the tag name `<my-customer>` instead?
If we simply put a `<my-customer>` element into the HTML, it doesn't work.
<div class="alert alert-warning">
<div class="alert alert-waring">
**Note:** When you create a directive, it is restricted to attribute only by default. In order to
create directives that are triggered by element or class name, you need to use the `restrict` option.
</div>
@@ -353,7 +352,7 @@ element as a customer component.
Our `myCustomer` directive above is great, but it has a fatal flaw. We can only use it once within a
given scope.
In its current implementation, we'd need to create a different controller each time in order to
In its current implementation, we'd need to create a different controller each time In order to
re-use such a directive:
<example module="docsScopeProblemExample">
@@ -476,6 +475,7 @@ within our directive's template:
angular.module('docsIsolationExample', [])
.controller('Controller', ['$scope', function($scope) {
$scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
$scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
}])
.directive('myCustomer', function() {
@@ -510,8 +510,8 @@ that you explicitly pass in.
<div class="alert alert-warning">
**Note:** Normally, a scope prototypically inherits from its parent. An isolated scope does not.
See the {@link api/ng/service/$compile#directive-definition-object
"Directive Definition Object - scope"} section for more information about isolate scopes.
See the {@link guide/directive#isolating-the-scope-of-a-directive
"Isolating the Scope of a Directive"} section for more information about isolate scopes.
</div>
<div class="alert alert-success">
@@ -537,7 +537,7 @@ where:
In our `link` function, we want to update the displayed time once a second, or whenever a user
changes the time formatting string that our directive binds to. We will use the `$interval` service
to call a handler on a regular basis. This is easier than using `$timeout` but also works better with
end-to-end testing, where we want to ensure that all `$timeout`s have completed before completing the test.
end-to-end testing, where we want to ensure that all $timeouts have completed before completing the test.
We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak.
<example module="docsTimeDirective">
@@ -901,39 +901,10 @@ So where does this `myTabs` controller come from? Directives can specify control
the unsurprisingly named `controller` option. As you can see, the `myTabs` directive uses this
option. Just like `ngController`, this option attaches a controller to the template of the directive.
If it is necessary to reference the controller or any functions bound to the controller's scope in
the template, you can use the option `controllerAs` to specify the name of the controller as an alias.
The directive needs to define a scope for this configuration to be used. This is particularly useful
in the case when the directive is used as a component.
Looking back at `myPane`'s definition, notice the last argument in its `link` function: `tabsCtrl`.
When a directive requires a controller, it receives that controller as the fourth argument of its
`link` function. Taking advantage of this, `myPane` can call the `addPane` function of `myTabs`.
If multiple controllers are required, the `require` option of the directive can take an array argument.
The corresponding parameter being sent to the `link` function will also be an array.
```js
angular.module('docsTabsExample', [])
.directive('myPane', function() {
return {
require: ['^myTabs', '^ngModel'],
restrict: 'E',
transclude: true,
scope: {
title: '@'
},
link: function(scope, element, attrs, controllers) {
var tabsCtrl = controllers[0],
modelCtrl = controllers[1];
tabsCtrl.addPane(scope);
},
templateUrl: 'my-pane.html'
};
});
```
Savvy readers may be wondering what the difference is between `link` and `controller`.
The basic difference is that `controller` can expose an API, and `link` functions can interact with
controllers using `require`.
+2 -2
View File
@@ -1,6 +1,6 @@
@workInProgress
@ngdoc overview
@name E2E Testing
@sortOrder 420
@description
# E2E Testing
@@ -12,7 +12,7 @@ is now in maintenance mode.
</div>
As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to
verify the correctness of new features, catch bugs and notice regressions. End to end tests
verify the correctness of new features, catch bugs and notice regressions. Unit tests
are the first line of defense for catching bugs, but sometimes issues come up with integration
between components which can't be captured in a unit test. End to end tests are made to find
these problems.
+29 -37
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Expressions
@sortOrder 270
@description
# Angular Expressions
@@ -39,9 +38,7 @@ the method from your view. If you want to `eval()` an Angular expression yoursel
## Example
<example>
<file name="index.html">
<span>
1+2={{1+2}}
</span>
1+2={{1+2}}
</file>
<file name="protractor.js" type="protractor">
@@ -53,9 +50,9 @@ the method from your view. If you want to `eval()` an Angular expression yoursel
You can try evaluating different expressions here:
<example module="expressionExample">
<example>
<file name="index.html">
<div ng-controller="ExampleController" class="expressions">
<div ng-controller="Cntl2" class="expressions">
Expression:
<input type='text' ng-model="expr" size="80"/>
<button ng-click="addExp(expr)">Evaluate</button>
@@ -69,24 +66,23 @@ You can try evaluating different expressions here:
</file>
<file name="script.js">
angular.module('expressionExample', [])
.controller('ExampleController', ['$scope', function($scope) {
var exprs = $scope.exprs = [];
$scope.expr = '3*10|currency';
$scope.addExp = function(expr) {
exprs.push(expr);
};
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);
};
}]);
$scope.removeExp = function(index) {
exprs.splice(index, 1);
};
}
</file>
<file name="protractor.js" type="protractor">
it('should allow user expression testing', function() {
element(by.css('.expressions button')).click();
var lis = element(by.css('.expressions ul')).all(by.repeater('expr in exprs'));
var lis = element(by.css('.expressions ul')).element.all(by.repeater('expr in exprs'));
expect(lis.count()).toBe(1);
expect(lis.get(0).getText()).toEqual('[ X ] 3*10|currency => $30.00');
});
@@ -99,30 +95,27 @@ You can try evaluating different expressions here:
Angular does not use JavaScript's `eval()` to evaluate expressions. Instead Angular's
{@link ng.$parse $parse} service processes these expressions.
Angular expressions do not have access to global variables like `window`, `document` or `location`.
This restriction is intentional. It prevents accidental access to the global state a common source of subtle bugs.
Unlike JavaScript, where names default to global `window` properties, Angular expressions must use
{@link ng.$window `$window`} explicitly to refer to the global `window` object. For example, if you
want to call `alert()` in an expression you must use `$window.alert()`. This restriction is
intentional. It prevents accidental access to the global state a common source of subtle bugs.
Instead use services like `$window` and `$location` in functions called from expressions. Such services
provide mockable access to globals.
<example module="expressionExample">
<example>
<file name="index.html">
<div class="example2" ng-controller="ExampleController">
<div class="example2" ng-controller="Cntl1">
Name: <input ng-model="name" type="text"/>
<button ng-click="greet()">Greet</button>
<button ng-click="window.alert('Should not see me')">Won't greet</button>
</div>
</file>
<file name="script.js">
angular.module('expressionExample', [])
.controller('ExampleController', ['$window', '$scope', function($window, $scope) {
$scope.name = 'World';
function Cntl1($window, $scope){
$scope.name = 'World';
$scope.greet = function() {
$window.alert('Hello ' + $scope.name);
};
}]);
$scope.greet = function() {
$window.alert('Hello ' + $scope.name);
};
}
</file>
<file name="protractor.js" type="protractor">
@@ -159,10 +152,9 @@ Similarly, invoking a function `a.b.c()` on `undefined` or `null` simply returns
## No Control Flow Statements
Apart from the ternary operator (`a ? b : c`), 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 the views. If you need a real conditional, loop, or to throw from a view
expression, delegate to a JavaScript method instead.
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 the views. If you need a
conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.
## `$event`
+1 -2
View File
@@ -1,12 +1,11 @@
@ngdoc overview
@name Filters
@sortOrder 280
@description
A filter formats the value of an expression for display to the user. They can be used in view templates,
controllers or services and it is easy to define your own filter.
The underlying API is the {@link ng.$filterProvider `filterProvider`}.
The underlying API is the {@link ng.$filterProvider filterProvider}.
## Using filters in view templates
+115 -43
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Forms
@sortOrder 290
@description
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
@@ -17,9 +16,9 @@ The key directive in understanding two-way data-binding is {@link ng.directive:n
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
In addition it provides an {@link ngModel.NgModelController API} for other directives to augment its behavior.
<example module="formExample">
<example>
<file name="index.html">
<div ng-controller="ExampleController">
<div ng-controller="Controller">
<form novalidate class="simple-form">
Name: <input type="text" ng-model="user.name" /><br />
E-mail: <input type="email" ng-model="user.email" /><br />
@@ -33,20 +32,19 @@ In addition it provides an {@link ngModel.NgModelController API} for other direc
</div>
<script>
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
function Controller($scope) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
}]);
$scope.reset();
}
</script>
</file>
</example>
@@ -69,9 +67,9 @@ 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.
<example module="formExample">
<example>
<file name="index.html">
<div ng-controller="ExampleController">
<div ng-controller="Controller">
<form novalidate class="css-form">
Name:
<input type="text" ng-model="user.name" required /><br />
@@ -94,20 +92,19 @@ This ensures that the user is not distracted with an error until after interacti
</style>
<script>
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
function Controller($scope) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
}]);
$scope.reset();
}
</script>
</file>
</example>
@@ -133,9 +130,9 @@ This allows us to extend the above example with these features:
- SAVE button is enabled only if form has some changes and is valid
- custom error messages for `user.email` and `user.agree`
<example module="formExample">
<example>
<file name="index.html">
<div ng-controller="ExampleController">
<div ng-controller="Controller">
<form name="form" class="css-form" novalidate>
Name:
<input type="text" ng-model="user.name" name="uName" required /><br />
@@ -162,24 +159,99 @@ This allows us to extend the above example with these features:
</file>
<file name="script.js">
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.master = {};
function Controller($scope) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.update = function(user) {
$scope.master = angular.copy(user);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.isUnchanged = function(user) {
return angular.equals(user, $scope.master);
};
$scope.isUnchanged = function(user) {
return angular.equals(user, $scope.master);
};
$scope.reset();
}]);
$scope.reset();
}
</file>
</example>
# Custom triggers
By default, any change to the content will trigger a model update and form validation. You can
override this behavior using the {@link ng.directive:ngModelOptions ngModelOptions} directive to
bind only to specified list of events. I.e. `ng-model-options="{ updateOn: 'blur' }"` will update
and validate only after the control loses focus. You can set several events using a space delimited
list. I.e. `ng-model-options="{ updateOn: 'mousedown blur' }"`
If you want to keep the default behavior and just add new events that may trigger the model update
and validation, add "default" as one of the specified events.
I.e. `ng-model-options="{ updateOn: 'default blur' }"`
The following example shows how to override immediate updates. Changes on the inputs within the form will update the model
only when the control loses focus (blur event).
<example>
<file name="index.html">
<div ng-controller="ControllerUpdateOn">
<form>
Name:
<input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" /><br />
Other data:
<input type="text" ng-model="user.data" /><br />
</form>
<pre>username = "{{user.name}}"</pre>
</div>
</file>
<file name="script.js">
function ControllerUpdateOn($scope) {
$scope.user = {};
}
</file>
</example>
# Non-immediate (debounced) model updates
You can delay the model update/validation by using the `debounce` key with the
{@link ng.directive:ngModelOptions ngModelOptions} directive. This delay will also apply to
parsers, validators and model flags like `$dirty` or `$pristine`.
I.e. `ng-model-options="{ debounce: 500 }"` will wait for half a second since
the last content change before triggering the model update and form validation.
If custom triggers are used, custom debouncing timeouts can be set for each event using an object
in `debounce`. This can be useful to force immediate updates on some specific circumstances
(like blur events).
I.e. `ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"`
If those attributes are added to an element, they will be applied to all the child elements and controls that inherit from it unless they are
overridden.
This example shows how to debounce model changes. Model will be updated only 250 milliseconds after last change.
<example>
<file name="index.html">
<div ng-controller="ControllerUpdateOn">
<form>
Name:
<input type="text" ng-model="user.name" ng-model-options="{ debounce: 250 }" /><br />
</form>
<pre>username = "{{user.name}}"</pre>
</div>
</file>
<file name="script.js">
function ControllerUpdateOn($scope) {
$scope.user = {};
}
</file>
</example>
+1 -2
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name i18n and l10n
@sortOrder 520
@description
# i18n and l10n
@@ -115,7 +114,7 @@ You write the following binding using the currency filter:
If your app is currently in the `en-US` locale, the browser will show `$1000.00`. If someone in the
Japanese locale (`ja`) views your app, their browser will show a balance of `¥1000.00` instead.
This is problematic because $1000 is not the same as ¥1000.
This is problematinc because $1000 is not the same as ¥1000.
In this case, you need to override the default currency symbol by providing the
{@link ng.filter:currency} currency filter with a currency symbol as a parameter.
-1
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Internet Explorer Compatibility
@sortOrder 530
@description
# Internet Explorer Compatibility
+3 -5
View File
@@ -47,7 +47,7 @@ In Angular applications, you move the job of filling page templates with data fr
### Testing
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/unit-testing Unit testing}, {@link guide/services#unit-testing Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/dev_guide.unit-testing Unit testing}, {@link guide/dev_guide.services.testing_services Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
* **Scenario testing:** [Protractor](https://github.com/angular/protractor)
## Specific Topics
@@ -73,16 +73,15 @@ This is a short list of libraries with specific support and documentation for wo
* **Internationalization:** [angular-translate](http://angular-translate.github.io), [angular-gettext](http://angular-gettext.rocketeer.be/)
* **RESTful services:** [Restangular](https://github.com/mgonto/restangular)
* **SQL and NoSQL backends:** [BreezeJS](http://www.breezejs.com/), [AngularFire](http://angularfire.com/)
* **UI Widgets: **[KendoUI](http://kendo-labs.github.io/angular-kendo/#/), [UI Bootstrap](http://angular-ui.github.io/bootstrap/), [Wijmo](http://wijmo.com/tag/angularjs-2/), [ngTagsInput](https://github.com/mbenford/ngTagsInput)
* **UI Widgets: **[KendoUI](http://kendo-labs.github.io/angular-kendo/#/), [UI Bootstrap](http://angular-ui.github.io/bootstrap/), [Wijmo](http://wijmo.com/tag/angularjs-2/)
* **Advanced Routing:** [UI-Router](https://github.com/angular-ui/ui-router)
* **Maps:** [UI-Map (Google Maps)](https://github.com/angular-ui/ui-map)
## Deployment
### General
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ngmin automation tool](http://www.thinkster.io/pick/XlWneEZCqY/angularjs-ngmin)
* **Analytics and Logging:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Angulartics (Analytics)](https://github.com/luisfarzati/angulartics), [Logging Client-Side Errors](http://www.bennadel.com/blog/2542-Logging-Client-Side-Errors-With-AngularJS-And-Stacktrace-js.htm)
* **Tracking:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Logging Client-Side Errors](http://www.bennadel.com/blog/2542-Logging-Client-Side-Errors-With-AngularJS-And-Stacktrace-js.htm)
* **SEO:** [By hand](http://www.yearofmoo.com/2012/11/angularjs-and-seo.html), [prerender.io](http://prerender.io/), [Brombone](http://www.brombone.com/), [SEO.js](http://getseojs.com/), [SEO4Ajax](http://www.seo4ajax.com/)
### Server-Specific
@@ -113,7 +112,6 @@ This is a short list of libraries with specific support and documentation for wo
* **Free online:**
[thinkster.io](http://thinkster.io),
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1)
[CodeSchool](https://www.codeschool.com/courses/shaping-up-with-angular-js)
* **Paid online:**
[Pluralsite (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
+1 -2
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Introduction
@sortOrder 100
@description
@@ -23,7 +22,7 @@ The impedance mismatch between dynamic applications and static documents is ofte
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., `durandal`, `ember`, etc.
app specific. E.g., `knockout`, `ember`, etc.
Angular takes another approach. It attempts to minimize the impedance mismatch between document
+2 -5
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Migrating from 1.0 to 1.2
@sortOrder 550
@description
# Migrating from 1.0 to 1.2
@@ -383,6 +382,8 @@ See [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a
## ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
`ngBindHtml` which has been moved from `ngSanitize` module to the core `ng` module.
`ngBindHtml` provides `ngBindHtmlUnsafe` like
behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result
of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanitized via
@@ -390,10 +391,6 @@ of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanit
module is not loaded) and the bound expression evaluates to a value that is not trusted an
exception is thrown.
When using this directive you can either include `ngSanitize` in your module's dependencis (See the
example at the {@link ngBindHtml} reference) or use the {@link $sce} service to set the value as
trusted.
See [dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55).
+15 -33
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Modules
@sortOrder 320
@description
# What is a Module?
@@ -27,12 +26,10 @@ should be bootstrapped. There are several advantages to this approach:
I'm in a hurry. How do I get a Hello World module working?
<example ng-app-included="true">
<example module='myApp'>
<file name="index.html">
<div ng-app="myApp">
<div>
{{ 'World' | greet }}
</div>
<div>
{{ 'World' | greet }}
</div>
</file>
@@ -48,18 +45,12 @@ I'm in a hurry. How do I get a Hello World module working?
};
});
</file>
<file name="protractor.js" type="protractor">
it('should add Hello to the name', function() {
expect(element(by.binding("{{ 'World' | greet }}")).getText()).toEqual('Hello, World!');
});
</file>
</example>
Important things to notice:
* The {@link angular.Module Module} API
* The reference to `myApp` module in `<div ng-app="myApp">`.
* The reference to `myApp` module in `<html ng-app="myApp">`.
This is what bootstraps the app using your module.
* The empty array in `angular.module('myApp', [])`.
This array is the list of modules `myApp` depends on.
@@ -84,14 +75,13 @@ The above is a suggestion. Tailor it to your needs.
<example module='xmpl'>
<file name="index.html">
<div ng-controller="XmplController">
{{ greeting }}
{{ greeting }}!
</div>
</file>
<file name="script.js">
angular.module('xmpl.service', [])
.value('greeter', {
angular.module('xmpl.service', []).
value('greeter', {
salutation: 'Hello',
localize: function(localization) {
this.salutation = localization.salutation;
@@ -99,9 +89,8 @@ The above is a suggestion. Tailor it to your needs.
greet: function(name) {
return this.salutation + ' ' + name + '!';
}
})
.value('user', {
}).
value('user', {
load: function(name) {
this.name = name;
}
@@ -111,28 +100,21 @@ The above is a suggestion. Tailor it to your needs.
angular.module('xmpl.filter', []);
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter'])
.run(function(greeter, user) {
angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
run(function(greeter, user) {
// This is effectively part of the main method initialization code
greeter.localize({
salutation: 'Bonjour'
});
user.load('World');
})
.controller('XmplController', function($scope, greeter, user){
$scope.greeting = greeter.greet(user.name);
});
</file>
<file name="protractor.js" type="protractor">
it('should add Hello to the name', function() {
expect(element(by.binding("{{ greeting }}")).getText()).toEqual('Bonjour World!');
});
// A Controller for your app
var XmplController = function($scope, greeter, user) {
$scope.greeting = greeter.greet(user.name);
};
</file>
</example>
+26 -27
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Providers
@sortOrder 340
@description
# Providers
@@ -84,7 +83,7 @@ On to more complex examples!
## Factory Recipe
The Value recipe is very simple to write, but lacks some important features we often need when
creating services. Let's now look at the Value recipe's more powerful sibling, the Factory. The
creating services. Let's now look at the Value recipe's more powerful sibling, the Factory.The
Factory recipe adds the following abilities:
* ability to use other services (have dependencies)
@@ -98,8 +97,9 @@ created by this recipe.
Note: All services in Angular are singletons. That means that the injector uses each recipe at most
once to create the object. The injector then caches the reference for all future needs.
Since a Factory is a more powerful version of the Value recipe, the same service can be constructed with it.
Using our previous `clientId` Value recipe example, we can rewrite it as a Factory recipe like this:
Since Factory is more powerful version of Value recipe, you can construct the same service with it.
Using our previous `clientId` Value recipe example, we can rewrite it as a Factory recipe like
this:
```javascript
myApp.factory('clientId', function clientIdFactory() {
@@ -111,8 +111,8 @@ But given that the token is just a string literal, sticking with the Value recip
appropriate as it makes the code easier to follow.
Let's say, however, that we would also like to create a service that computes a token used for
authentication against a remote API. This token will be called `apiToken` and will be computed
based on the `clientId` value and a secret stored in the browser's local storage:
authentication against a remote API. This token will be called 'apiToken' and will be computed
based on the `clientId` value and a secret stored in browser's local storage:
```javascript
myApp.factory('apiToken', ['clientId', function apiTokenFactory(clientId) {
@@ -129,23 +129,21 @@ myApp.factory('apiToken', ['clientId', function apiTokenFactory(clientId) {
```
In the code above, we see how the `apiToken` service is defined via the Factory recipe that depends
on the `clientId` service. The factory service then uses NSA-proof encryption to produce an authentication
on `clientId` service. The factory service then uses NSA-proof encryption to produce an authentication
token.
<div class="alert alert-success">
**Best Practice:** name the factory functions as `<serviceId>Factory`
(e.g., apiTokenFactory). While this naming convention is not required, it helps when navigating the codebase
Note: It is a best practice to name the factory functions as "<serviceId>Factory"
(e.g. apiTokenFactory). While this naming convention is not required, it helps when navigating the code base
or looking at stack traces in the debugger.
</div>
Just like with the Value recipe, the Factory recipe can create a service of any type, whether it be a
Just like with Value recipe, Factory recipe can create a service of any type, whether it be a
primitive, object literal, function, or even an instance of a custom type.
## Service Recipe
JavaScript developers often use custom types to write object-oriented code. Let's explore how we
could launch a unicorn into space via our `unicornLauncher` service which is an instance of a
could launch a unicorn into space via our `unicornLauncher` service that is an instance of
custom type:
```javascript
@@ -153,7 +151,7 @@ function UnicornLauncher(apiToken) {
this.launchedCount = 0;
this.launch = function() {
// Make a request to the remote API and include the apiToken
// make a request to the remote api and include the apiToken
...
this.launchedCount++;
}
@@ -170,7 +168,7 @@ myApp.factory('unicornLauncher', ["apiToken", function(apiToken) {
```
This is, however, exactly the use-case that the Service recipe is the most suitable for.
This is, however, exactly the use-case that Service recipe is the most suitable for.
The Service recipe produces a service just like the Value or Factory recipes, but it does so by
*invoking a constructor with the `new` operator*. The constructor can take zero or more arguments,
@@ -189,18 +187,19 @@ myApp.service('unicornLauncher', ["apiToken", UnicornLauncher]);
Much simpler!
Note: Yes, we have called one of our service recipes 'Service'. We regret this and know that we'll
be somehow punished for our misdeed. It's like we named one of our offspring 'Child'. Boy,
be somehow punished for our mis-deed. It's like we named one of our offspring 'Children'. Boy,
that would mess with the teachers.
## Provider Recipe
As already mentioned in the intro, the Provider recipe is the core recipe type and
There are two more recipe types left to cover. They are both fairly specialized and are used
infrequently. As already mentioned in the intro, the Provider recipe is the core recipe type and
all the other recipe types are just syntactic sugar on top of it. It is the most verbose recipe
with the most abilities, but for most services it's overkill.
The Provider recipe is syntactically defined as a custom type that implements a `$get` method. This
method is a factory function just like the one we use in the Factory recipe. In fact, if you define
Provider recipe is syntactically defined as a custom type that implements a `$get` method. This
method is a factory function just like the one we use in Factory recipe. In fact, if you define
a Factory recipe, an empty Provider type with the `$get` method set to your factory function is
automatically created under the hood.
@@ -248,7 +247,7 @@ and wires (injects) all provider instances only.
During application bootstrap, before Angular goes off creating all services, it configures and
instantiates all providers. We call this the configuration phase of the application life-cycle.
During this phase, services aren't accessible because they haven't been created yet.
During this phase services aren't accessible because they haven't been created yet.
Once the configuration phase is over, interaction with providers is disallowed and the process of
creating services starts. We call this part of the application life-cycle the run phase.
@@ -259,9 +258,9 @@ creating services starts. We call this part of the application life-cycle the ru
We've just learned how Angular splits the life-cycle into configuration phase and run phase and how
you can provide configuration to your application via the config function. Since the config
function runs in the configuration phase when no services are available, it doesn't have access
even to simple value objects created via the Value recipe.
even to simple value objects created via Value recipe.
Since simple values, like URL prefixes, don't have dependencies or configuration, it's often handy
Since simple values, like url prefix, don't have dependencies or configuration, it is often handy
to make them available in both the configuration and run phases. This is what the Constant recipe
is for.
@@ -317,7 +316,7 @@ Let's take a look at how we would create a very simple component via the directi
on the `planetName` constant we've just defined and displays the planet name, in our case:
"Planet Name: Greasy Giant".
Since the directives are registered via the Factory recipe, we can use the same syntax as with factories.
Since the directives are registered via Factory recipe, we can use the same syntax as with factories.
```javascript
myApp.directive('myPlanet', ['planetName', function myPlanetDirectiveFactory(planetName) {
@@ -340,7 +339,7 @@ We can then use the component like this:
</html>
```
Using Factory recipes, you can also define Angular's filters and animations, but the controllers
Using Factory recipes you can also define Angular's filters and animations, but the controllers
are a bit special. You create a controller as a custom type that declares its dependencies as
arguments for its constructor function. This constructor is then registered with a module. Let's
take a look at the `DemoController`, created in one of the early examples:
@@ -351,7 +350,7 @@ myApp.controller('DemoController', ['clientId', function DemoController(clientId
}]);
```
The DemoController is instantiated via its constructor, every time the app needs an instance of
The DemoController is instantiated via its constructor every time the app needs an instance of
DemoController (in our simple app it's just once). So unlike services, controllers are not
singletons. The constructor is called with all the requested services, in our case the `clientId`
service.
@@ -365,12 +364,12 @@ To wrap it up, let's summarize the most important points:
- There are five recipe types that define how to create objects: Value, Factory, Service, Provider
and Constant.
- Factory and Service are the most commonly used recipes. The only difference between them is that
the Service recipe works better for objects of a custom type, while the Factory can produce JavaScript
Service recipe works better for objects of custom type, while Factory can produce JavaScript
primitives and functions.
- The Provider recipe is the core recipe type and all the other ones are just syntactic sugar on it.
- Provider is the most complex recipe type. You don't need it unless you are building a reusable
piece of code that needs global configuration.
- All special purpose objects except for the Controller are defined via Factory recipes.
- All special purpose objects except for Controller are defined via Factory recipes.
<table class="table table-bordered code-table">
<thead>
+26 -29
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Scopes
@sortOrder 240
@description
# What are Scopes?
@@ -43,16 +42,15 @@ arrangement isolates the controller from the directive as well as from DOM. This
point since it makes the controllers view agnostic, which greatly improves the testing story of
the applications.
<example module="scopeExample">
<example>
<file name="script.js">
angular.module('scopeExample', [])
.controller('MyController', ['$scope', function($scope) {
$scope.username = 'World';
function MyController($scope) {
$scope.username = 'World';
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}]);
$scope.sayHello = function() {
$scope.greeting = 'Hello ' + $scope.username + '!';
};
}
</file>
<file name="index.html">
<div ng-controller="MyController">
@@ -114,7 +112,7 @@ 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.
structure which parallels the DOM where they're attached
When Angular evaluates `{{name}}`, it first looks at the scope associated with the given
element for the `name` property. If no such property is found, it searches the parent scope
@@ -124,13 +122,13 @@ inheritance, and child scopes prototypically inherit from their parents.
This example illustrates scopes in application, and prototypical inheritance of properties. The example is followed by
a diagram depicting the scope boundaries.
<example module="scopeExample">
<example>
<file name="index.html">
<div class="show-scope-demo">
<div ng-controller="GreetController">
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListController">
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">{{name}} from {{department}}</li>
</ol>
@@ -138,14 +136,14 @@ a diagram depicting the scope boundaries.
</div>
</file>
<file name="script.js">
angular.module('scopeExample', [])
.controller('GreetController', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}])
.controller('ListController', ['$scope', function($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}]);
function GreetCtrl($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
</file>
<file name="style.css">
.show-scope-demo.ng-scope,
@@ -192,15 +190,14 @@ Scopes can propagate events in similar fashion to DOM events. The event can be {
ng.$rootScope.Scope#$broadcast broadcasted} to the scope children or {@link
ng.$rootScope.Scope#$emit emitted} to scope parents.
<example module="eventExample">
<example>
<file name="script.js">
angular.module('eventExample', [])
.controller('EventController', ['$scope', function($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}]);
function EventController($scope) {
$scope.count = 0;
$scope.$on('MyEvent', function() {
$scope.count++;
});
}
</file>
<file name="index.html">
<div ng-controller="EventController">
+3 -10
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Services
@sortOrder 230
@description
# Services
@@ -131,14 +130,8 @@ injection of `$window`, `$scope`, and our `notify` service:
</example>
<div class="alert alert-danger">
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming&#41;) your
code, your variable names will get renamed unless you use one of the annotation techniques above.
</div>
<div class="alert alert-info">
If you use a tool like [ngmin](https://github.com/btford/ngmin#ngmin) in your workflow you can
use implicit dependency notation within your codebase and let **ngmin** automatically convert such
injectable functions to the array notation prior to minifying.
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming) your code,
your variable names will get renamed unless you use one of the annotation techniques above.
</div>
@@ -300,5 +293,5 @@ it('should clear messages after alert', function() {
## Related API
* {@link ./api/ng/service Angular Service API}
* {@link ./ng Angular Service API}
* {@link angular.injector Injector API}
-1
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Templates
@sortOrder 260
@description
In Angular, templates are written with HTML that contains Angular-specific elements and attributes.
+5 -80
View File
@@ -1,6 +1,5 @@
@ngdoc overview
@name Unit Testing
@sortOrder 410
@description
JavaScript is a dynamically typed language which comes with great power of expression, but it also
@@ -50,7 +49,7 @@ Out of the four options in the list above, only the last one is testable. Let's
### Using the `new` operator
While there is nothing wrong with the `new` operator fundamentally, a problem arises when calling `new`
on a constructor. This permanently binds the call site to the type. For example, let's say that we try to
on a constructor. This permanently binds the call site to the type. For example, lets say that we try to
instantiate an `XHR` that will retrieve data from the server.
```js
@@ -66,7 +65,7 @@ function MyClass() {
A problem surfaces in tests when we would like to instantiate a `MockXHR` that would
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
permanently bound to the actual XHR and there is no way to replace it. Yes, we could monkey
permanently bound to the actual XHR and there is no way to replace it. Yes, we could monkey
patch, but that is a bad idea for many reasons which are outside the scope of this document.
Here's an example of how the class above becomes hard to test when resorting to monkey patching:
@@ -97,7 +96,7 @@ function MyClass() {
```
While no new dependency instance is created, it is fundamentally the same as `new` in
that no way exists to intercept the call to `global.xhr` for testing purposes, other then
that no way exists to intercept the call to `global.xhr` for testing purposes, other than
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 of why this is bad see: [Brittle Global
State & Singletons](http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/)
@@ -134,7 +133,7 @@ function MyClass() {
However, where does the serviceRegistry come from? If it is:
* `new`-ed up, the test has no chance to reset the services for testing.
* a global look-up then the service returned is global as well (but resetting is easier, since
* a global look-up then the service returned is global as well (but resetting is easier, since
only one global variable exists to be reset).
The class above is hard to test since we have to change the global state:
@@ -297,7 +296,7 @@ Now we can add a directive to our app.
app.directive('aGreatEye', function () {
return {
restrict: 'E',
replace: true,
replace: true,
template: '<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>'
};
});
@@ -338,80 +337,6 @@ We inject the $compile service and $rootScope before each jasmine test. The $com
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
replaced the content and "lidless, wreathed in flame, 2 times" is present.
### Testing Transclusion Directives
Directives that use transclusion are treated specially by the compiler. Before their compile
function is called, the contents of the directive's element are removed from the element and
provided via a transclusion function. The directive's template is then appended to the directive's
element, to which it can then insert the transcluded content into its template.
Before compilation:
```html
<div translude-directive>
Some transcluded content
</div>
```
After transclusion extraction:
```html
<div transclude-directive></div>
```
After compilation:
```html
<div transclude-directive>
Some Template
<span ng-transclude>Some transcluded content</span>
</div>
```
If the directive is using 'element' transclusion, the compiler will actually remove the
directive's entire element from the DOM and replace it with a comment node. The compiler then
inserts the directive's template "after" this comment node, as a sibling.
Before compilation
```html
<div element-transclude>
Some Content
</div>
```
After transclusion extraction
```html
<!-- elementTransclude -->
```
After compilation:
```html
<!-- elementTransclude -->
<div element-transclude>
Some Template
<span ng-transclude>Some transcluded content</span>
</div>
```
It is important to be aware of this when writing tests for directives that use 'element'
transclusion. If you place the directive on the root element of the DOM fragment that you
pass to {@link $compile}, then the DOM node returned from the linking function will be the
comment node and you will lose the ability to access the template and transcluded content.
```javascript
var node = $compile('<div element-transclude></div>')($rootScope);
expect(node[0].nodeType).toEqual(node.COMMENT_NODE);
expect(node[1]).toBeUndefined();
```
To cope with this you simply ensure that your 'element' transclude directive is wrapped in an
element, such as a `<div>`.
```javascript
var node = $compile('<div><div element-transclude></div></div>')($rootScope);
var contents = node.contents();
expect(contents[0].nodeType).toEqual(node.COMMENT_NODE);
expect(contents[1].nodeType).toEqual(node.ELEMENT_NODE);
```
### Testing Directives With External Templates
If your directive uses `templateUrl`, consider using

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