Compare commits

..

369 Commits

Author SHA1 Message Date
Igor Minar 4b8629b6b8 chore(release): cut 1.0.6 universal-irreversibility release 2013-04-04 10:48:05 -07:00
Misko Hevery ed81d19ce9 chore(docs): correct few unclosed elements
Conflicts:

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

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

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

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

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

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

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

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

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

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

Use the nextRoute object instead of nextRoute.$route.

Closes #1907
2013-03-08 12:01:05 -08:00
Julie 13968343d4 feat(angular.bootstrap): support deferred bootstrap
This features enables tools like Batarang and test runners to
hook into angular's bootstrap process and sneak in more modules
into the DI registry which can replace or augment DI services for
the purpose of instrumentation or mocking out heavy dependencies.

If window.name contains prefix NG_DEFER_BOOTSTRAP! when
angular.bootstrap is called, the bootstrap process will be paused
until angular.resumeBootstrap is called.

angular.resumeBootstrap takes an optional array of modules that
should be added to the original list of modules that the app was
about to be bootstrapped with.

Conflicts:

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

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

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

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

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

Closes #199

Conflicts:

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

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

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

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

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

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

This commit should get reverted once Firefox 21 gets out.

Closes #1468

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

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

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

I fixed an e2e test too because it was incorrect.

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

see original PR: #1966

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

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

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

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

this fixes it

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

it(...

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

 inject(...
 );

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

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

both should return false because these objects are not equal.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

before:

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

after:

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

before:

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

after:

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

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

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

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

usage:

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

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

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

For example:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- use symlinks when creating final zip file

- switch from btar to zip

- get rid of version numbers from filenames

- rewrite version numbers in all index files

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

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

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

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

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

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

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

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

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

if the default was not prevented, the test will fail and the page will
be reloaded causing the test runner to panic.
2012-08-10 14:20:52 -07:00
Igor Minar 6b75475ce3 refactor(formSpec): group preventDefault specs into a describe 2012-08-10 14:20:28 -07:00
Igor Minar 07c354a8c0 docs(faq): update faq docs 2012-08-10 14:20:13 -07:00
Igor Minar 1391579599 docs(styles): fix the cog icon alignment 2012-08-10 14:19:57 -07:00
Vojta Jina 5d2bd1d84c chore(nodeserver): add font mime type 2012-08-10 14:19:47 -07:00
Vojta Jina bf77e212af docs(guide): hide scenario for directive example
scenario test for this example would be tricky, we need to teach
the runner how to inject mocks first.
2012-08-10 14:19:37 -07:00
Vojta Jina eef2f9c31e docs(design): fix icons
Copy fontawesome during build
2012-08-10 14:18:45 -07:00
brettcannon 438627c2c3 fix(docs): "in depth" -> "in-depth" 2012-08-10 14:18:06 -07:00
689 changed files with 47633 additions and 63460 deletions
-4
View File
@@ -1,4 +0,0 @@
{
"directory": "bower_components",
"json": "bower.json"
}
+4 -10
View File
@@ -1,4 +1,6 @@
/build/
build/
angularjs.netrc
jstd.log
.DS_Store
gen_docs.disable
test.disable
@@ -6,15 +8,7 @@ regression/temp*.html
performance/temp*.html
.idea/workspace.xml
*~
*.swp
angular.js.tmproj
/node_modules/
/components/
/bower_components/
node_modules
angular.xcodeproj
.idea
.agignore
libpeerconnection.log
npm-debug.log
/tmp/
/scripts/bower/bower-*
+6 -21
View File
@@ -1,28 +1,13 @@
language: node_js
node_js:
- 0.10
env:
global:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
- BROWSER_STACK_USERNAME=VojtaJina
- BROWSER_STACK_ACCESS_KEY=HAfHZaypxAc3PEUrUU9a
- LOGS_DIR=/tmp/angular-build/logs
- 0.8
before_script:
- mkdir -p $LOGS_DIR
- ./lib/browser-stack/start-tunnel.sh
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- npm install -g grunt-cli
- grunt bower
- grunt bower
- grunt package-without-bower
- grunt ci-checks
- ./lib/sauce/sauce_connect_block.sh
- grunt package
- grunt webserver > /dev/null &
script:
- ./travis_build.sh
after_script:
- ./travis_print_logs.sh
- grunt test --browsers Firefox --reporters=dots
-1781
View File
File diff suppressed because it is too large Load Diff
+22 -236
View File
@@ -1,246 +1,32 @@
#Contributing to AngularJS
## Submitting issues
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
If you have questions about how to use AngularJS, please direct these to the
[Google Group][groups] discussion list or [StackOverflow][stackoverflow]. We are
also available on [IRC][irc].
## Got a Question or Problem?
### Guidelines
If you have questions about how to use AngularJS, please direct these to the [Google Group][groups]
discussion list or [StackOverflow][stackoverflow]. We are also available on [IRC][irc].
## Found an Issue?
If you find a bug in the source code or a mistake in the documentation, you can help us by
submitting and issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
with a fix.
***Localization Issue:*** *Angular.js uses the [Google Closure I18N library], to generate its own I18N files. This means that
any changes to these files would be lost the next time that we import the library. The recommended
approach is to submit a patch to the I18N project directly, instead of submitting it here.*
**Please see the Submission Guidelines below**.
## Want a Feature?
You can request a new feature by submitting an issue to our [GitHub Repository][github]. If you
would like to implement a new feature then consider what kind of change it is:
* **Major Changes** that you wish to contribute to the project should be discussed first on our
[dev mailing list][angular-dev] or [IRC][irc] so that we can better coordinate our efforts, prevent
duplication of work, and help you to craft the change so that it is successfully accepted into the
project.
* **Small Changes** can be crafted and submitted to [GitHub Repository][github] as a Pull Request.
## Submission Guidelines
### Submitting an Issue
Before you submit your issue search the archive, maybe your question was already answered.
* Search the archive first, it's likely that your question was already answered.
* A live example demonstrating your problem or question, will get an answer faster.
* Create one using this [template][template]
* If you get help, help others. Good karma rulez!
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues. Providing the following information will increase the
chances of your issue being dealt with quickly:
features, by not reporting duplicate issues.
* **Overview of the issue** - if an error is being thrown a non-minified stack trace helps
* **Motivation for or Use Case** - explain why this is a bug for you
* **Angular Version(s)** - is it a regression?
* **Browsers and Operating System** - is this a problem with all browsers or only IE8?
* **Reproduce the error** - provide a live example (using [Plunker][plunker] or
[JSFiddle][jsfiddle]) or a unambiguous set of steps.
* **Related issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
causing the problem (line of code or commit)
Here is a great example of a well defined issue: https://github.com/angular/angular.js/issues/5069
**If you get help, help others. Good karma rulez!**
### Submitting a Pull Request
Before you submit your pull request consider the following guidelines:
* Search [GitHub](https://github.com/angular/angular.js/pulls) for an open or closed Pull Request
that relates to your submission. You don't want to duplicate effort.
* Please sign our [Contributor License Agreement (CLA)](#signing-the-cla) before sending pull
requests. We cannot accept code without this.
* Make your changes in a new git branch
```shell
git checkout -b my-fix-branch master
```
* Create your patch, including appropriate test cases.
* Follow our Coding Rules
* Commit your changes and create a descriptive commit message (the
commit message is used to generate release notes, please check out our
[commit message conventions](#commit-message-format) and our commit message presubmit hook
`validate-commit-msg.js`):
```shell
git commit -a
```
* Build your changes locally to ensure all the tests pass
```shell
grunt test
```
* Push your branch to Github:
```shell
git push origin my-fix-branch
```
* In Github, send a pull request to `angular:master`.
* If we suggest changes then you can modify your branch, rebase and force a new push to your GitHub
repository to update the Pull Request:
```shell
git rebase master -i
git push -f
```
That's it! Thank you for your contribution!
When the patch is reviewed and merged, you can safely delete your branch and pull the changes
from the main (upstream) repository:
* Delete the remote branch on Github:
```shell
git push origin --delete my-fix-branch
```
* Check out the master branch:
```shell
git checkout master -f
```
* Delete the local branch:
```shell
git branch -D my-fix-branch
```
* Update your master with the latest upstream version:
```shell
git pull --ff upstream master
```
### GitHub Pull Request Helper
We track Pull Requests by attaching labels and assigning to milestones. For some reason GitHub
does not provide a good UI for managing labels on Pull Requests (unlike Issues). We have developed
a simple Chrome Extension that enables you to view (and manage if you have permission) the labels
on Pull Requests. You can get the extension from the Chrome WebStore -
[GitHub PR Helper][github-pr-helper]
## Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must be tested** by one or more [specs][unit-testing].
* All public API methods **must be documented** with ngdoc, an extended version of jsdoc (we added
support for markdown and templating via @ngdoc tag). To see how we document our APIs, please check
out the existing ngdocs and see [this wiki page][ngDocs].
* With the exceptions listed below, we follow the rules contained in
[Google's JavaScript Style Guide][js-style-guide]:
* **Do not use namespaces**: Instead, wrap the entire angular code base in an anonymous closure and
export our API explicitly rather than implicitly.
* Wrap all code at **100 characters**.
* Instead of complex inheritance hierarchies, we **prefer simple objects**. We use prototypical
inheritance only when absolutely necessary.
* We **love functions and closures** and, whenever possible, prefer them over objects.
* To write concise code that can be better minified, we **use aliases internally** that map to the
external API. See our existing code to see what we mean.
* We **don't go crazy with type annotations** for private internal APIs unless it's an internal API
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
## Git Commit Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the AngularJS change log**.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on github as well as in various git tools.
### Type
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
### Scope
The scope could be anything specifying place of the commit change. For example `$location`,
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
###Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
The body should include the motivation for the change and contrast this with previous behavior.
###Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
A detailed explanation can be found in this [document][commit-message-format].
## Signing the CLA
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
* For individuals we have a [simple click-through form][individual-cla].
* For corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
## Further Information
You can find out more detailed information about contributing in the
[AngularJS documentation][contributing].
[github]: https://github.com/angular/angular.js
[Google Closure I18N library]: https://code.google.com/p/closure-library/source/browse/closure/goog/i18n/
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[contribute]: http://docs.angularjs.org/misc/contribute
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
[angular-dev]: https://groups.google.com/forum/?fromgroups#!forum/angular-dev
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[plunker]: http://plnkr.co/edit
[jsfiddle]: http://jsfiddle.net/
[ngDocs]: https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation
[unit-testing]: http://docs.angularjs.org/guide/dev_guide.unit-testing
[js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
[contributing]: http://docs.angularjs.org/misc/contribute
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[github-pr-helper]: https://chrome.google.com/webstore/detail/github-pr-helper/mokbklfnaddkkbolfldepnkfmanfhpen
[template]: http://plnkr.co/edit/gist:3510140
## Contributing to Source Code
We'd love for you to contribute to our source code and to make AngularJS even
better than it is today!
Please read the [contribution guidelines][contribute] to learn about how to submit code as well as
other useful info like how to build and test AngularJS code.
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[contribute]: http://docs.angularjs.org/misc/contribute
+33 -161
View File
@@ -1,6 +1,5 @@
var files = require('./angularFiles').files;
var util = require('./lib/grunt/utils.js');
var path = require('path');
module.exports = function(grunt) {
//grunt plugins
@@ -8,12 +7,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-jasmine-node');
grunt.loadNpmTasks('grunt-ddescribe-iit');
grunt.loadNpmTasks('grunt-merge-conflict');
grunt.loadNpmTasks('grunt-parallel');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadTasks('lib/grunt');
var NG_VERSION = util.getVersion();
@@ -28,15 +21,6 @@ module.exports = function(grunt) {
grunt.initConfig({
NG_VERSION: NG_VERSION,
parallel: {
travis: {
tasks: [
util.parallelTask(['test:unit', 'test:docgen', 'test:promises-aplus', 'tests:docs'], {stream: true}),
util.parallelTask(['test:e2e'])
]
}
},
connect: {
devserver: {
options: {
@@ -56,36 +40,13 @@ module.exports = function(grunt) {
}
}
},
testserver: {
options: {
// We use end2end task (which does not start the webserver)
// and start the webserver as a separate process (in travis_build.sh)
// to avoid https://github.com/joyent/libuv/issues/826
port: 8000,
hostname: '0.0.0.0',
middleware: function(connect, options){
return [
function(req, resp, next) {
// cache get requests to speed up tests on travis
if (req.method === 'GET') {
resp.setHeader('Cache-control', 'public, max-age=3600');
}
next();
},
connect.favicon('images/favicon.ico'),
connect.static(options.base)
];
}
}
}
testserver: {}
},
tests: {
test: {
jqlite: 'karma-jqlite.conf.js',
jquery: 'karma-jquery.conf.js',
docs: 'karma-docs.conf.js',
modules: 'karma-modules.conf.js',
//NOTE run grunt test:e2e instead and it will start a webserver for you
end2end: 'karma-e2e.conf.js'
@@ -94,65 +55,18 @@ module.exports = function(grunt) {
autotest: {
jqlite: 'karma-jqlite.conf.js',
jquery: 'karma-jquery.conf.js',
modules: 'karma-modules.conf.js',
docs: 'karma-docs.conf.js'
jquery: 'karma-jquery.conf.js'
},
clean: {
build: ['build'],
tmp: ['tmp']
},
clean: {build: ['build']},
jshint: {
ng: {
files: { src: files['angularSrc'] },
options: { jshintrc: 'src/.jshintrc' }
},
ngAnimate: {
files: { src: 'src/ngAnimate/**/*.js' },
options: { jshintrc: 'src/ngAnimate/.jshintrc' }
},
ngCookies: {
files: { src: 'src/ngCookies/**/*.js' },
options: { jshintrc: 'src/ngCookies/.jshintrc' }
},
ngLocale: {
files: { src: 'src/ngLocale/**/*.js' },
options: { jshintrc: 'src/ngLocale/.jshintrc' }
},
ngMock: {
files: { src: 'src/ngMock/**/*.js' },
options: { jshintrc: 'src/ngMock/.jshintrc' }
},
ngResource: {
files: { src: 'src/ngResource/**/*.js' },
options: { jshintrc: 'src/ngResource/.jshintrc' }
},
ngRoute: {
files: { src: 'src/ngRoute/**/*.js' },
options: { jshintrc: 'src/ngRoute/.jshintrc' }
},
ngSanitize: {
files: { src: 'src/ngSanitize/**/*.js' },
options: { jshintrc: 'src/ngSanitize/.jshintrc' }
},
ngScenario: {
files: { src: 'src/ngScenario/**/*.js' },
options: { jshintrc: 'src/ngScenario/.jshintrc' }
},
ngTouch: {
files: { src: 'src/ngTouch/**/*.js' },
options: { jshintrc: 'src/ngTouch/.jshintrc' }
}
},
build: {
scenario: {
dest: 'build/angular-scenario.js',
src: [
'bower_components/jquery/jquery.js',
'lib/jquery/jquery.js',
util.wrap([files['angularSrc'], files['angularScenario']], 'ngScenario/angular')
],
styles: {
@@ -164,59 +78,57 @@ module.exports = function(grunt) {
src: util.wrap([files['angularSrc']], 'angular'),
styles: {
css: ['css/angular.css'],
generateCspCssFile: true,
minify: true
}
},
loader: {
dest: 'build/angular-loader.js',
src: util.wrap(files['angularLoader'], 'loader')
},
touch: {
dest: 'build/angular-touch.js',
src: util.wrap(files['angularModules']['ngTouch'], 'module')
src: util.wrap(['src/loader.js'], 'loader')
},
mocks: {
dest: 'build/angular-mocks.js',
src: util.wrap(files['angularModules']['ngMock'], 'module'),
src: ['src/ngMock/angular-mocks.js'],
strict: false
},
sanitize: {
dest: 'build/angular-sanitize.js',
src: util.wrap(files['angularModules']['ngSanitize'], 'module')
src: util.wrap([
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
], 'module')
},
resource: {
dest: 'build/angular-resource.js',
src: util.wrap(files['angularModules']['ngResource'], 'module')
},
animate: {
dest: 'build/angular-animate.js',
src: util.wrap(files['angularModules']['ngAnimate'], 'module')
},
route: {
dest: 'build/angular-route.js',
src: util.wrap(files['angularModules']['ngRoute'], 'module')
src: util.wrap(['src/ngResource/resource.js'], 'module')
},
cookies: {
dest: 'build/angular-cookies.js',
src: util.wrap(files['angularModules']['ngCookies'], 'module')
src: util.wrap(['src/ngCookies/cookies.js'], 'module')
},
"promises-aplus-adapter": {
dest:'tmp/promises-aplus-adapter++.js',
src:['src/ng/q.js','lib/promises-aplus/promises-aplus-test-adapter.js']
bootstrap: {
dest: 'build/angular-bootstrap.js',
src: util.wrap(['src/bootstrap/bootstrap.js'], 'module')
},
bootstrapPrettify: {
dest: 'build/angular-bootstrap-prettify.js',
src: util.wrap(['src/bootstrap/bootstrap-prettify.js', 'src/bootstrap/google-prettify/prettify.js'], 'module'),
styles: {
css: ['src/bootstrap/google-prettify/prettify.css'],
minify: true
}
}
},
min: {
angular: 'build/angular.js',
animate: 'build/angular-animate.js',
cookies: 'build/angular-cookies.js',
loader: 'build/angular-loader.js',
touch: 'build/angular-touch.js',
resource: 'build/angular-resource.js',
route: 'build/angular-route.js',
sanitize: 'build/angular-sanitize.js'
sanitize: 'build/angular-sanitize.js',
bootstrap: 'build/angular-bootstrap.js',
bootstrapPrettify: 'build/angular-bootstrap-prettify.js',
},
@@ -224,25 +136,6 @@ module.exports = function(grunt) {
process: ['build/docs/*.html', 'build/docs/.htaccess']
},
"jasmine_node": {
projectRoot: 'docs/spec'
},
"ddescribe-iit": {
files: [
'test/**/*.js',
'!test/ngScenario/DescribeSpec.js'
]
},
"merge-conflict": {
files: [
'src/**/*',
'test/**/*',
'docs/**/*',
'css/**/*'
]
},
copy: {
i18n: {
@@ -255,22 +148,11 @@ module.exports = function(grunt) {
compress: {
build: {
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
options: {archive: 'build/' + dist +'.zip'},
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
}
},
shell:{
"promises-aplus-tests":{
options:{
//stdout:true,
stderr:true,
failOnError:true
},
command:path.normalize('./node_modules/.bin/promises-aplus-tests tmp/promises-aplus-adapter++.js')
}
},
write: {
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
@@ -280,20 +162,10 @@ module.exports = function(grunt) {
//alias tasks
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e']);
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
grunt.registerTask('test:e2e', 'Run the end to end tests with Karma and keep a test server running in the background', ['connect:testserver', 'tests:end2end']);
grunt.registerTask('test:docgen', ['jasmine_node']);
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
grunt.registerTask('minify', ['bower','clean', 'build', 'minall']);
grunt.registerTask('test:unit', ['test:jqlite', 'test:jquery', 'test:modules']);
grunt.registerTask('minify', ['clean', 'build', 'minall']);
grunt.registerTask('test:e2e', ['connect:testserver', 'test:end2end']);
grunt.registerTask('webserver', ['connect:devserver']);
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('package-without-bower', ['clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'test:docgen']);
grunt.registerTask('package', ['clean', 'buildall', 'minall', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('default', ['package']);
};
+1 -2
View File
@@ -1,4 +1,4 @@
AngularJS [![Build Status](https://travis-ci.org/angular/angular.js.png?branch=master)](https://travis-ci.org/angular/angular.js)
AngularJS
=========
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
@@ -16,7 +16,6 @@ it makes development fun!
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
* Dashboard: http://dashboard.angularjs.org
Building AngularJS
---------
Vendored Executable → Regular
+91 -89
View File
@@ -1,6 +1,5 @@
angularFiles = {
'angularSrc': [
'src/minErr.js',
'src/Angular.js',
'src/loader.js',
'src/AngularPublic.js',
@@ -10,29 +9,26 @@ angularFiles = {
'src/auto/injector.js',
'src/ng/anchorScroll.js',
'src/ng/animate.js',
'src/ng/browser.js',
'src/ng/cacheFactory.js',
'src/ng/compile.js',
'src/ng/controller.js',
'src/ng/document.js',
'src/ng/exceptionHandler.js',
'src/ng/http.js',
'src/ng/httpBackend.js',
'src/ng/interpolate.js',
'src/ng/interval.js',
'src/ng/locale.js',
'src/ng/location.js',
'src/ng/log.js',
'src/ng/parse.js',
'src/ng/q.js',
'src/ng/route.js',
'src/ng/routeParams.js',
'src/ng/rootScope.js',
'src/ng/sanitizeUri.js',
'src/ng/sce.js',
'src/ng/sniffer.js',
'src/ng/timeout.js',
'src/ng/urlUtils.js',
'src/ng/window.js',
'src/ng/http.js',
'src/ng/httpBackend.js',
'src/ng/locale.js',
'src/ng/timeout.js',
'src/ng/filter.js',
'src/ng/filter/filter.js',
@@ -51,7 +47,6 @@ angularFiles = {
'src/ng/directive/ngController.js',
'src/ng/directive/ngCsp.js',
'src/ng/directive/ngEventDirs.js',
'src/ng/directive/ngIf.js',
'src/ng/directive/ngInclude.js',
'src/ng/directive/ngInit.js',
'src/ng/directive/ngNonBindable.js',
@@ -61,49 +56,25 @@ angularFiles = {
'src/ng/directive/ngStyle.js',
'src/ng/directive/ngSwitch.js',
'src/ng/directive/ngTransclude.js',
'src/ng/directive/ngView.js',
'src/ng/directive/script.js',
'src/ng/directive/select.js',
'src/ng/directive/style.js'
],
'angularLoader': [
'src/minErr.js',
'src/loader.js'
],
'angularSrcModules': [
'src/ngCookies/cookies.js',
'src/ngResource/resource.js',
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
'src/ngMock/angular-mocks.js',
'angularModules': {
'ngAnimate': [
'src/ngAnimate/animate.js'
],
'ngCookies': [
'src/ngCookies/cookies.js'
],
'ngResource': [
'src/ngResource/resource.js'
],
'ngRoute': [
'src/ngRoute/route.js',
'src/ngRoute/routeParams.js',
'src/ngRoute/directive/ngView.js'
],
'ngSanitize': [
'src/ngSanitize/sanitize.js',
'src/ngSanitize/filter/linky.js'
],
'ngMock': [
'src/ngMock/angular-mocks.js'
],
'ngTouch': [
'src/ngTouch/touch.js',
'src/ngTouch/swipe.js',
'src/ngTouch/directive/ngClick.js',
'src/ngTouch/directive/ngSwipe.js'
],
},
'src/bootstrap/bootstrap.js'
],
'angularScenario': [
'src/ngScenario/Scenario.js',
'src/ngScenario/browserTrigger.js',
'src/ngScenario/Application.js',
'src/ngScenario/Describe.js',
'src/ngScenario/Future.js',
@@ -119,104 +90,135 @@ angularFiles = {
],
'angularTest': [
'test/helpers/*.js',
'test/testabilityPatch.js',
'test/matchers.js',
'test/ngScenario/*.js',
'test/ngScenario/output/*.js',
'test/ngScenario/jstd-scenario-adapter/*.js',
'test/*.js',
'test/auto/*.js',
'test/ng/**/*.js',
'test/ngAnimate/*.js',
'test/bootstrap/*.js',
'test/ng/*.js',
'test/ng/directive/*.js',
'test/ng/filter/*.js',
'test/ngCookies/*.js',
'test/ngResource/*.js',
'test/ngRoute/**/*.js',
'test/ngSanitize/**/*.js',
'test/ngMock/*.js',
'test/ngTouch/**/*.js'
'test/ngSanitize/*.js',
'test/ngSanitize/directive/*.js',
'test/ngSanitize/filter/*.js',
'test/ngMock/*.js'
],
'karma': [
'bower_components/jquery/jquery.js',
'jstd': [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'lib/jquery/jquery.js',
'test/jquery_remove.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
'@angularTest',
'example/personalLog/*.js',
'example/personalLog/test/*.js'
],
'karmaExclude': [
'jstdExclude': [
'test/jquery_alias.js',
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js'
],
'karmaScenario': [
'jstdScenario': [
'build/angular-scenario.js',
'build/jstd-scenario-adapter-config.js',
'build/jstd-scenario-adapter.js',
'build/docs/docs-scenario.js'
],
"karmaModules": [
"jstdModules": [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'build/angular.js',
'@angularSrcModules',
'src/ngScenario/browserTrigger.js',
'test/helpers/*.js',
'src/ngMock/angular-mocks.js',
'src/ngCookies/cookies.js',
'src/ngResource/resource.js',
'src/ngSanitize/sanitize.js',
'src/ngSanitize/directive/ngBindHtml.js',
'src/ngSanitize/filter/linky.js',
'test/matchers.js',
'test/ngMock/*.js',
'test/ngCookies/*.js',
'test/ngRoute/**/*.js',
'test/ngResource/*.js',
'test/ngSanitize/**/*.js',
'test/ngTouch/**/*.js'
'test/ngSanitize/*.js',
'test/ngSanitize/directive/*.js',
'test/ngSanitize/filter/*.js'
],
'karmaJquery': [
'bower_components/jquery/jquery.js',
'jstdPerf': [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'@angularSrc',
'@angularSrcModules',
'src/ngMock/angular-mocks.js',
'perf/data/*.js',
'perf/testUtils.js',
'perf/*.js'
],
'jstdPerfExclude': [
'src/ng/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js'
],
'jstdJquery': [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'lib/jquery/jquery.js',
'test/jquery_alias.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
'@angularTest',
'example/personalLog/*.js',
'example/personalLog/test/*.js'
],
'karmaJqueryExclude': [
'jstdJqueryExclude': [
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js',
'test/jquery_remove.js'
]
};
angularFiles['angularSrcModules'] = [].concat(
angularFiles['angularModules']['ngAnimate'],
angularFiles['angularModules']['ngCookies'],
angularFiles['angularModules']['ngResource'],
angularFiles['angularModules']['ngRoute'],
angularFiles['angularModules']['ngSanitize'],
angularFiles['angularModules']['ngMock'],
angularFiles['angularModules']['ngTouch']
);
if (exports) {
exports.files = angularFiles;
exports.mergeFilesFor = function() {
exports.files = angularFiles
exports.mergeFiles = function mergeFiles() {
var files = [];
Array.prototype.slice.call(arguments, 0).forEach(function(filegroup) {
angularFiles[filegroup].forEach(function(file) {
// replace @ref
var match = file.match(/^\@(.*)/);
if (match) {
files = files.concat(angularFiles[match[1]]);
} else {
files.push(file);
}
});
[].splice.call(arguments, 0).forEach(function(file) {
if (file.match(/karma/)) {
files.push(file);
} else {
angularFiles[file].forEach(function(f) {
// replace @ref
var match = f.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
files = files.concat(deps);
} else {
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
files.push(f);
}
}
});
}
});
return files;
};
}
}
-12
View File
@@ -1,12 +0,0 @@
{
"name": "AngularJS",
"devDependencies": {
"jquery": "1.10.2",
"lunr.js": "0.4.0",
"google-code-prettify": "1.0.0",
"components-font-awesome": "3.1.0",
"bootstrap": "https://raw.github.com/twbs/bootstrap/v2.0.2/docs/assets/bootstrap.zip",
"closure-compiler": "https://closure-compiler.googlecode.com/files/compiler-20130603.zip",
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.2/assets/ng-closure-runner.zip"
}
}
+7 -1
View File
@@ -16,6 +16,7 @@ var LINK_ISSUE = '[#%s](https://github.com/angular/angular.js/issues/%s)';
var LINK_COMMIT = '[%s](https://github.com/angular/angular.js/commit/%s)';
var EMPTY_COMPONENT = '$$';
var MAX_SUBJECT_LENGTH = 80;
var warn = function() {
@@ -53,6 +54,11 @@ var parseRawCommit = function(raw) {
return null;
}
if (match[3].length > MAX_SUBJECT_LENGTH) {
warn('Too long subject: %s %s', msg.hash, msg.subject);
match[3] = match[3].substr(0, MAX_SUBJECT_LENGTH);
}
msg.type = match[1];
msg.component = match[2];
msg.subject = match[3];
@@ -186,7 +192,7 @@ var getPreviousTag = function() {
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|BREAKING', tag).then(function(commits) {
readGitLog('^fix|^feat|Breaks', tag).then(function(commits) {
console.log('Parsed', commits.length, 'commits');
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
+80
View File
@@ -0,0 +1,80 @@
<a name="v1.0.0rc3"></a>
# v1.0.0rc3 (2012-03-27)
## Bug Fixes
- **$compile:**
- create new (isolate) scopes for directives on root elements ([5390fb37](https://github.com/angular/angular.js/commit/5390fb37d2c01937922613fc57df4986af521787), closes [#817](https://github.com/angular/angular.js/issues/817))
- don't touch static element attributes ([9cb2195e](https://github.com/angular/angular.js/commit/9cb2195e61a78e99020ec19d687a221ca88b5900))
- Merge interpolated css class when replacing an element ([f49eaf8b](https://github.com/angular/angular.js/commit/f49eaf8bf2df5f4e0e82d6c89e849a4f82c8d414))
- **$http:**
- don't send Content-Type header when no data ([1a5bebd9](https://github.com/angular/angular.js/commit/1a5bebd927ecd22f9c34617642fdf58fe3f62efb), closes [#749](https://github.com/angular/angular.js/issues/749))
- **$log:**
- avoid console.log.apply calls in IE ([15213ec2](https://github.com/angular/angular.js/commit/15213ec212769837cb2b7e781ffc5bfd598d27ca), closes [#805](https://github.com/angular/angular.js/issues/805))
- **$resource:**
- support escaping of ':' in resource url ([6d6f8753](https://github.com/angular/angular.js/commit/6d6f875345e01f2c6c63ef95164f6f39e923da15))
- **compiler:**
- allow transclusion of root elements ([9918b748](https://github.com/angular/angular.js/commit/9918b748be01266eb10db39d51b4d3098d54ab66))
- **e2e runner:**
- fix typo that caused errors on IE8 ([ee5a5352](https://github.com/angular/angular.js/commit/ee5a5352fd4b94cedee6ef20d4bf2d43ce77e00b), closes [#806](https://github.com/angular/angular.js/issues/806))
- **forEach:**
- should ignore prototypically inherited properties ([8d7e6948](https://github.com/angular/angular.js/commit/8d7e6948496ff26ef1da8854ba02fcb8eebfed61), closes [#813](https://github.com/angular/angular.js/issues/813))
- **forms:**
- Remove double registering of form ([1faafa31](https://github.com/angular/angular.js/commit/1faafa31582c4e9413f48dc7d12f5b681f9fe9fd))
- Set ng-valid/ng-invalid correctly ([08bfea18](https://github.com/angular/angular.js/commit/08bfea183a850b29da270eac47f80b598cbe600f))
- **init:**
- use jQuery#ready for init if available ([cb2ad9ab](https://github.com/angular/angular.js/commit/cb2ad9abf24e6f855cc749efe3155bd7987ece9d), closes [#818](https://github.com/angular/angular.js/issues/818))
- **json:**
- added support for iso8061 timezone ([5ac14f63](https://github.com/angular/angular.js/commit/5ac14f633a69f49973b5512780c6ec7752405967))
- **matchers.toHaveClass:**
- Correct reference to angular.mock.dump ([f701ce08](https://github.com/angular/angular.js/commit/f701ce08f9d63be05fc3b92f57ad473e1e749b2d))
- **ng-switch:**
- properly destroy child scopes ([2315d9b3](https://github.com/angular/angular.js/commit/2315d9b3610994b36c44e4a97fb1427d59471ce8))
- **ngDocSpec:**
- fix broken tests ([53b6f522](https://github.com/angular/angular.js/commit/53b6f522a56eea314cbd084816e08f24b2c7879f))
- **ngForm:**
- alias name||ngForm ([823adb23](https://github.com/angular/angular.js/commit/823adb231995e917bc060bfa49453e2a96bac2b6))
- **ngRepeat:**
- correct variable reference in error message ([935c1018](https://github.com/angular/angular.js/commit/935c1018da05dbf3124b2dd33619c4a3c82d7a2a))
- **ngView:**
- controller not published ([21e74c2d](https://github.com/angular/angular.js/commit/21e74c2d2e8e985b23711785287feb59965cbd90))
- **q:**
- resolve all of nothing to nothing ([ac75079e](https://github.com/angular/angular.js/commit/ac75079e2113949d5d64adbcf23d56f3cf295d41))
- **select:**
- multiselect failes to update view on selection insert ([6ecac8e7](https://github.com/angular/angular.js/commit/6ecac8e71a84792a434d21db2c245b3648c55f18))
## Features
- **$compile:**
- do not interpolate boolean attributes, rather evaluate them ([a08cbc02](https://github.com/angular/angular.js/commit/a08cbc02e78e789a66e9af771c410e8ad1646e25))
- **$controller:**
- support controller registration via $controllerProvider ([d54dfecb](https://github.com/angular/angular.js/commit/d54dfecb00fba41455536c5ddd55310592fdaf84))
- **$route:**
- when matching consider trailing slash as optional ([a4fe51da](https://github.com/angular/angular.js/commit/a4fe51da3ba0dc297ecd389e230d6664f250c9a6), closes [#784](https://github.com/angular/angular.js/issues/784))
- **assertArgFn:**
- should support array annotated fns ([4b8d9260](https://github.com/angular/angular.js/commit/4b8d926062eb4d4483555bdbdec4656f585ab40b))
- **http:**
- added params parameter ([73c85930](https://github.com/angular/angular.js/commit/73c8593077155a9f2e8ef42efd4c497eba0bef4f))
- **injector:**
- infer _foo_ as foo ([f13dd339](https://github.com/angular/angular.js/commit/f13dd3393dfb7a33565c9360342c193bc0bddcb6))
- **input.radio:**
- Allow value attribute to be interpolated ([ade6c452](https://github.com/angular/angular.js/commit/ade6c452753145c84884d17027a7865bf4b34b0c))
- **jqLite:**
- make injector() and scope() work with the document object ([5fdab52d](https://github.com/angular/angular.js/commit/5fdab52dd7c269f99839f4fa6b5854d9548269fa))
- add .controller() method ([6c5a05ad](https://github.com/angular/angular.js/commit/6c5a05ad49a1e083570c3dfe331403398f899dbe))
- **ngValue:**
- allow radio inputs to have non string values ([09e175f0](https://github.com/angular/angular.js/commit/09e175f02cca0f4a295fd0c9b980cd8f432e722b), closes [#816](https://github.com/angular/angular.js/issues/816))
- **scope:**
- broadcast $destroy event on scope destruction ([9b1aff90](https://github.com/angular/angular.js/commit/9b1aff905b638aa274a5fc8f88662df446d374bd))
- **scope.$eval:**
- Allow passing locals to the expression ([192ff61f](https://github.com/angular/angular.js/commit/192ff61f5d61899e667c6dbce4d3e6e399429d8b))
## Breaking Changes
- boolean attrs are evaluated rather than interpolated ([a08cbc02](https://github.com/angular/angular.js/commit/a08cbc02e78e789a66e9af771c410e8ad1646e25))
- ng-bind-attr directive removed ([55027132](https://github.com/angular/angular.js/commit/55027132f3d57e5dcf94683e6e6bd7b0aae0087d))
- any app that depends on this service and its fallback to Modernizr, please ([aaedefb9](https://github.com/angular/angular.js/commit/aaedefb92e6bec6626e173e5155072c91471596a))
-17
View File
@@ -1,17 +0,0 @@
This file contains externs for use with the Closure compiler (aka JSCompiler).
Passing these files to the --externs parameter of a compiler pass allows using
type annotations for AngularJS objects. For example, Angular's $scope objects
can be annotated as:
```js
/** @type {angular.Scope} */
var scope = $scope;
```
This allows JSCompiler to type check accesses to scope, give warnings about
missing methods or incorrect arguments, and also prevents renaming of property
accesses with advanced compilation.
The externs are incomplete and maintained on an as-needed basis, but strive to
be correct. Externs for individual modules should be added in separate files.
See https://developers.google.com/closure/compiler/
-1921
View File
File diff suppressed because it is too large Load Diff
-163
View File
@@ -1,163 +0,0 @@
#!/usr/local/bin/node
var util = require('util');
var cp = require('child_process');
var Q = require('q');
var _ = require('lodash');
var semver = require('semver');
var exec = function (cmd) {
return function () {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift(cmd);
var fullCmd = util.format.apply(util, args);
return Q.nfcall(cp.exec, fullCmd).then(function (out) {
return out[0].split('\n');
});
};
};
var andThen = function (fn, after) {
return function () {
return fn.apply(this, arguments).then(after);
};
};
var oneArg = function (fn) {
return function (arg) {
return fn(arg);
};
};
var oneLine = function (lines) {
return lines[0].trim();
};
var noArgs = function (fn) {
return function () {
return fn();
};
};
var identity = function (i) { return i; };
// like Q.all, but runs the comands in series
// useful for ensuring env state (like which branch is checked out)
var allInSeries = function (fn) {
return function (args) {
var results = [];
var def;
while (args.length > 0) {
(function (arg) {
if (def) {
def = def.then(function () {
return fn(arg);
});
} else {
def = fn(arg);
}
def = def.then(function (res) {
results.push(res);
});
}(args.pop()));
}
return def.then(function () {
return results;
});
};
};
var compareBranches = function (left, right) {
console.log('# These commits are in ' + left.name + ' but not in ' + right.name + '\n');
console.log(_(left.log).
difference(right.log).
map(function (line) {
return left.full[left.log.indexOf(line)]; // lol O(n^2)
}).
value().
join('\n'));
};
var checkout = oneArg(exec('git checkout %s'));
var getCurrentBranch = andThen(noArgs(exec('git rev-parse --abbrev-ref HEAD')), oneLine);
var getTags = noArgs(exec('git tag'));
var getShaOfTag = oneArg(exec('git rev-list %s | head -n 1'));
var getTheLog = oneArg(exec('git log --pretty=oneline %s..HEAD | cat'));
// remember this so we can restore state
var currentBranch;
getCurrentBranch().
then(function (branch) {
currentBranch = branch;
}).
then(getTags).
then(function (tags) {
return tags.
filter(semver.valid).
map(semver.clean).
sort(semver.rcompare);
}).
then(function (tags) {
var major = tags[0].split('.')[0] + '.x';
return tags.
filter(function (ver) {
return semver.satisfies(ver, major);
});
}).
then(function (tags) {
return _(tags).
groupBy(function (tag) {
return tag.split('.')[1];
}).
map(function (group) {
return _.first(group);
}).
map(function (tag) {
return 'v' + tag;
}).
value();
}).
then(function (tags) {
return [
{ name: 'v1.0.x', tag: tags[0] },
{ name: 'master', tag: tags[1] }
];
}).
then(allInSeries(function (branch) {
return checkout(branch.name).
then(function () {
return getTheLog(branch.tag);
}).
then(function (log) {
return log.
filter(identity);
}).
then(function (log) {
branch.full = log.map(function (line) {
line = line.split(' ');
var sha = line.shift();
var msg = line.join(' ');
return sha + (msg.toLowerCase().indexOf('fix') === -1 ? ' ' : ' * ') + msg;
});
branch.log = log.map(function (line) {
return line.substr(41)
});
return branch;
});
})).
then(function (pairs) {
compareBranches(pairs[0], pairs[1]);
console.log('\n');
compareBranches(pairs[1], pairs[0]);
return pairs;
}).
then(function () {
return checkout(currentBranch);
}).
catch(function (e) {
console.log(e.stack);
});
+2 -14
View File
@@ -1,22 +1,10 @@
@charset "UTF-8";
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
display: none !important;
.ng-cloak, .x-ng-cloak {
display: none;
}
ng\:form {
display: block;
}
/* The styles below ensure that the CSS transition will ALWAYS
* animate and close. A nasty bug occurs with CSS transitions where
* when the active class isn't set, or if the active class doesn't
* contain any styles to transition to, then, if ngAnimate is used,
* it will appear as if the webpage is broken due to the forever hanging
* animations. The border-spacing (!ie) and zoom (ie) CSS properties are
* used below since they trigger a transition without making the browser
* animate anything and they're both highly underused CSS properties */
.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }
.ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; }
-72
View File
@@ -1,72 +0,0 @@
describe("DocsNavigationCtrl", function() {
beforeEach(module('docsApp'));
var ctrl, $scope;
beforeEach(function() {
module(function($provide) {
$provide.value('docsPages', []);
$provide.factory('docsSearch', function() {
return function(q) {
return ['one','two','three'];
};
});
});
inject(function($controller, $rootScope, $location, docsSearch) {
$scope = $rootScope.$new();
ctrl = $controller('DocsNavigationCtrl', {
$scope : $scope,
$location : $location,
docsSearch : docsSearch
});
});
});
it("should search and return data from docsSearch", function() {
$scope.search('1234')
expect($scope.results.join(',')).toBe('one,two,three');
expect($scope.hasResults).toBe(true);
});
it("should avoid searching if the search term is too short", function() {
$scope.search('1')
expect($scope.results.length).toBe(0);
expect($scope.hasResults).toBe(false);
});
it("should set the columns classname based on the total grouped results", function() {
$scope.search('1234');
expect($scope.colClassName).toBe('cols-3');
$scope.search('1');
expect($scope.colClassName).toBe(null);
});
it("should hide and clear the results when called", function() {
$scope.hasResults = true;
$scope.results = ['one'];
$scope.colClassName = '...';
$scope.hideResults();
expect($scope.hasResults).toBe(false);
expect($scope.results.length).toBe(0);
expect($scope.colClassName).toBe(null);
});
it("should hide, clear and change the path of the page when submitted", inject(function($location) {
$scope.hasResults = true;
$scope.results = {
api : [
{url : '/home'}
],
tutorial : [
{url : '/tutorial'}
]
};
$scope.submit();
expect($location.path()).toBe('/home');
expect($scope.results.length).toBe(0);
expect($scope.hasResults).toBe(false);
}));
});
-195
View File
@@ -1,195 +0,0 @@
describe('Docs Annotations', function() {
beforeEach(module('docsApp'));
var body;
beforeEach(function() {
body = angular.element(document.body);
body.html('');
});
var normalizeHtml = function(html) {
return html.toLowerCase().replace(/\s*$/, '');
};
describe('popover directive', function() {
var $scope, element;
beforeEach(inject(function($rootScope, $compile) {
$scope = $rootScope.$new();
element = angular.element(
'<div style="margin:200px;" data-title="title_text" data-content="content_text" popover></div>'
);
element.attr('id','idx');
body.append(element);
$compile(element)($scope);
$scope.$apply();
}));
it('should be hidden by default', inject(function(popoverElement) {
expect(popoverElement.visible()).toBe(false);
}));
it('should capture the click event and set the title and content and position the tip', inject(function(popoverElement) {
element.triggerHandler('click');
expect(popoverElement.isSituatedAt(element)).toBe(true);
expect(popoverElement.visible()).toBe(true);
expect(popoverElement.title()).toBe('title_text');
expect(popoverElement.content()).toContain('content_text');
expect(popoverElement.besideElement.attr('id')).toBe('idx');
}));
it('should hide and clear the title and content if the same element is clicked again', inject(function(popoverElement) {
//show the element
element.triggerHandler('click');
expect(popoverElement.isSituatedAt(element)).toBe(true);
//hide the element
element.triggerHandler('click');
expect(popoverElement.isSituatedAt(element)).toBe(false);
expect(popoverElement.visible()).toBe(false);
expect(popoverElement.title()).toBe('');
expect(popoverElement.content()).toBe('');
}));
it('should parse markdown content', inject(function(popoverElement, $compile) {
element = angular.element(
'<div style="margin:200px;" data-title="#title_text" data-content="#heading" popover></div>'
);
body.append(element);
$compile(element)($scope);
$scope.$apply();
element.triggerHandler('click');
expect(popoverElement.title()).toBe('#title_text');
expect(normalizeHtml(popoverElement.content())).toMatch('<h1>heading</h1>');
}));
});
describe('foldout directive', function() {
// Do not run this suite on Internet Explorer.
if (msie < 10) return;
var $scope, parent, element, url;
beforeEach(function() {
module(function($provide, $animateProvider) {
$animateProvider.register('.foldout', function($timeout) {
return {
enter : function(element, done) {
$timeout(done, 1000);
},
removeClass : function(element, className, done) {
$timeout(done, 500);
},
addClass : function(element, className, done) {
$timeout(done, 200);
}
}
});
});
inject(function($rootScope, $compile, $templateCache, $rootElement, $animate) {
$animate.enabled(true);
url = '/page.html';
$scope = $rootScope.$new();
parent = angular.element('<div class="parent"></div>');
//we're injecting the element to the $rootElement since the changes in
//$animate only detect and perform animations if the root element has
//animations enabled. If the element is not apart of the DOM
//then animations are skipped.
element = angular.element('<div data-url="' + url + '" class="foldout" foldout></div>');
parent.append(element);
$rootElement.append(parent);
body.append($rootElement);
$compile(parent)($scope);
$scope.$apply();
});
});
it('should inform that it is loading', inject(function($httpBackend) {
$httpBackend.expect('GET', url).respond('hello');
element.triggerHandler('click');
var kids = body.children();
var foldout = angular.element(kids[kids.length-1]);
expect(foldout.html()).toContain('loading');
}));
//TODO(matias): this test is bad. it's not clear what is being tested and what the assertions are.
// Additionally, now that promises get auto-flushed there are extra tasks in the deferred queue which screws up
// these brittle tests.
xit('should download a foldout HTML page and animate the contents', inject(function($httpBackend, $timeout, $sniffer) {
$httpBackend.expect('GET', url).respond('hello');
element.triggerHandler('click');
$httpBackend.flush();
$timeout.flushNext(0);
$timeout.flushNext(1000);
var kids = body.children();
var foldout = angular.element(kids[kids.length-1]);
expect(foldout.text()).toContain('hello');
}));
//TODO(matias): this test is bad. it's not clear what is being tested and what the assertions are.
// Additionally, now that promises get auto-flushed there are extra tasks in the deferred queue which screws up
// these brittle tests.
xit('should hide then show when clicked again', inject(function($httpBackend, $timeout, $sniffer) {
$httpBackend.expect('GET', url).respond('hello');
//enter
element.triggerHandler('click');
$httpBackend.flush();
$timeout.flushNext(0);
$timeout.flushNext(1000);
//hide
element.triggerHandler('click');
$timeout.flushNext(0);
$timeout.flushNext(200);
//show
element.triggerHandler('click');
$timeout.flushNext(0);
$timeout.flushNext(500);
$timeout.flushNext(0);
}));
});
describe('DocsController fold', function() {
var $scope, ctrl;
beforeEach(function() {
inject(function($rootScope, $controller, $location, $cookies, sections) {
$scope = $rootScope.$new();
ctrl = $controller('DocsController',{
$scope : $scope,
$location : $location,
$cookies : $cookies,
sections : sections
});
});
});
it('should download and reveal the foldover container', inject(function($compile, $httpBackend) {
var url = '/page.html';
var fullUrl = '/notes/' + url;
$httpBackend.expect('GET', fullUrl).respond('hello');
var element = angular.element('<div ng-include="docs_fold"></div>');
$compile(element)($scope);
$scope.$apply();
$scope.fold(url);
$httpBackend.flush();
}));
});
});
-59
View File
@@ -1,59 +0,0 @@
describe("docsSearch", function() {
beforeEach(module('docsApp'));
var interceptedLunrResults;
beforeEach(function() {
interceptedLunrResults = [];
});
beforeEach(function() {
module(function($provide) {
var results = [];
results[0] = { section: 'tutorial', shortName: 'item one', keywords: 'item, one, 1' };
results[1] = { section: 'tutorial', shortName: 'item man', keywords: 'item, man' };
results[2] = { section: 'api', shortName: 'item other', keywords: 'item, other' };
results[3] = { section: 'cookbook', shortName: 'item cookbook', keywords: 'item, other' };
results[4] = { section: 'api', shortName: 'ngRepeat', keywords: 'item, other' };
$provide.value('NG_PAGES', results);
$provide.factory('lunrSearch', function() {
return function() {
return {
store : function(value) {
interceptedLunrResults.push(value);
},
search : function(q) {
var data = [];
angular.forEach(results, function(res, i) {
data.push({ ref : i });
});
return data;
}
}
};
});
});
});
it("should lookup and organize values properly", inject(function(docsSearch) {
var items = docsSearch('item');
expect(items['api'].length).toBe(2);
}));
it("should place cookbook items in the tutorial", inject(function(docsSearch) {
var items = docsSearch('item');
expect(items['tutorial'].length).toBe(3);
}));
it("should return all results without a search", inject(function(docsSearch) {
var items = docsSearch();
expect(items['tutorial'].length).toBe(3);
expect(items['api'].length).toBe(2);
}));
it("should store values with and without a ng prefix", inject(function(docsSearch) {
expect(interceptedLunrResults[4].title).toBe('ngRepeat repeat');
}));
});
-76
View File
@@ -1,76 +0,0 @@
describe("errorDisplay", function () {
var $location, compileHTML;
beforeEach(module('docsApp'));
beforeEach(inject(function ($injector) {
var $rootScope = $injector.get('$rootScope'),
$compile = $injector.get('$compile');
$location = $injector.get('$location');
compileHTML = function (code) {
var elm = angular.element(code);
$compile(elm)($rootScope);
$rootScope.$digest();
return elm;
};
this.addMatchers({
toInterpolateTo: function (expected) {
// Given a compiled DOM node with a minerr-display attribute,
// assert that its interpolated string matches the expected text.
return this.actual.text() === expected;
}
});
}));
it('should interpolate a template with no parameters', function () {
var elm;
spyOn($location, 'search').andReturn({});
elm = compileHTML('<div error-display="This is a test"></div>');
expect(elm).toInterpolateTo('This is a test');
});
it('should interpolate a template with no parameters when search parameters are present', function () {
var elm;
spyOn($location, 'search').andReturn({ p0: 'foobaz' });
elm = compileHTML('<div error-display="This is a test"></div>');
expect(elm).toInterpolateTo('This is a test');
});
it('should correctly interpolate search parameters', function () {
var elm;
spyOn($location, 'search').andReturn({ p0: '42' });
elm = compileHTML('<div error-display="The answer is {0}"></div>');
expect(elm).toInterpolateTo('The answer is 42');
});
it('should interpolate parameters in the specified order', function () {
var elm;
spyOn($location, 'search').andReturn({ p0: 'second', p1: 'first' });
elm = compileHTML('<div error-display="{1} {0}"></div>');
expect(elm).toInterpolateTo('first second');
});
it('should preserve interpolation markers when fewer arguments than needed are provided', function () {
var elm;
spyOn($location, 'search').andReturn({ p0: 'Fooooo' });
elm = compileHTML('<div error-display="This {0} is {1} on {2}"></div>');
expect(elm).toInterpolateTo('This Fooooo is {1} on {2}');
});
it('should correctly handle the empty string as an interpolation parameter', function () {
var elm;
spyOn($location, 'search').andReturn({ p0: 'test', p1: '' });
elm = compileHTML('<div error-display="This {0} is a {1}"></div>');
expect(elm).toInterpolateTo('This test is a ');
});
});
@@ -1,52 +0,0 @@
describe("errorLinkFilter", function () {
var errorLinkFilter;
beforeEach(module('docsApp'));
beforeEach(inject(function ($filter) {
errorLinkFilter = $filter('errorLink');
}));
it('should not change text that does not contain links', function () {
expect(errorLinkFilter('This is a test')).toBe('This is a test');
});
it('should find links in text and linkify them', function () {
var output = errorLinkFilter("http://ab/ (http://a/) http://1.2/v:~-123. c");
//temporary fix for IE8 sanitization whitespace bug
output = output.replace('</a>(','</a> (');
expect(output).
toBe('<a href="http://ab/">http://ab/</a> ' +
'(<a href="http://a/">http://a/</a>) ' +
'<a href="http://1.2/v:~-123">http://1.2/v:~-123</a>. c');
expect(errorLinkFilter(undefined)).not.toBeDefined();
});
it('should handle mailto', function () {
expect(errorLinkFilter("mailto:me@example.com")).
toBe('<a href="mailto:me@example.com">me@example.com</a>');
expect(errorLinkFilter("me@example.com")).
toBe('<a href="mailto:me@example.com">me@example.com</a>');
expect(errorLinkFilter("send email to me@example.com, but")).
toBe('send email to <a href="mailto:me@example.com">me@example.com</a>, but');
});
it('should handle target', function () {
expect(errorLinkFilter("http://example.com", "_blank")).
toBe('<a target="_blank" href="http://example.com">http://example.com</a>')
expect(errorLinkFilter("http://example.com", "someNamedIFrame")).
toBe('<a target="someNamedIFrame" href="http://example.com">http://example.com</a>')
});
it('should not linkify stack trace URLs', function () {
expect(errorLinkFilter("http://example.com/angular.min.js:42:1337")).
toBe("http://example.com/angular.min.js:42:1337");
});
it('should truncate linked URLs at 60 characters', function () {
expect(errorLinkFilter("http://errors.angularjs.org/very-long-version-string/$injector/nomod?p0=myApp")).
toBe('<a href="http://errors.angularjs.org/very-long-version-string/$injector/nomod?p0=myApp">' +
'http://errors.angularjs.org/very-long-version-string/$inj...</a>');
});
});
-32
View File
@@ -1,32 +0,0 @@
// Copy/pasted from src/Angular.js, so that we can disable specific tests on IE.
var msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1], 10);
var createMockWindow = function() {
var mockWindow = {};
var setTimeoutQueue = [];
mockWindow.location = window.location;
mockWindow.document = window.document;
mockWindow.getComputedStyle = angular.bind(window, window.getComputedStyle);
mockWindow.scrollTo = angular.bind(window, window.scrollTo);
mockWindow.navigator = window.navigator;
mockWindow.setTimeout = function(fn, delay) {
setTimeoutQueue.push({fn: fn, delay: delay});
};
mockWindow.setTimeout.queue = setTimeoutQueue;
mockWindow.setTimeout.expect = function(delay) {
if (setTimeoutQueue.length > 0) {
return {
process: function() {
var tick = setTimeoutQueue.shift();
expect(tick.delay).toEqual(delay);
tick.fn();
}
};
} else {
expect('SetTimoutQueue empty. Expecting delay of ').toEqual(delay);
}
};
return mockWindow;
};
-50
View File
@@ -1,50 +0,0 @@
describe('Docs Syntax', function() {
beforeEach(module('bootstrap'));
describe('syntax', function() {
var id, element, document;
beforeEach(inject(function($compile, $rootScope, $document) {
document = $document[0];
//create the HTML elements missing in IE8 for this directive
document.createElement('nav');
element = angular.element(
'<div>' +
'<pre syntax ' +
'syntax-github="gh-url" ' +
'syntax-plunkr="pl-url" ' +
'syntax-fiddle="jf-url">' +
'</pre>' +
'</div>'
);
$compile(element)($rootScope);
$rootScope.$digest();
element = element[0];
document.body.appendChild(element);
}));
it("should properly prepare a github link in the page", function() {
var github = element.querySelector('.syntax-github');
expect(github.innerHTML).toMatch(/View on Github/i);
expect(github.getAttribute('href')).toBe('gh-url');
});
it("should properly prepare a plunkr link in the page", function() {
var plunkr = element.querySelector('.syntax-plunkr');
expect(plunkr.innerHTML).toMatch(/View on Plunkr/i);
expect(plunkr.getAttribute('href')).toBe('pl-url');
});
it("should properly prepare a jsfiddle link in the page", function() {
var jsfiddle = element.querySelector('.syntax-jsfiddle');
expect(jsfiddle.innerHTML).toMatch(/View on JSFiddle/i);
expect(jsfiddle.getAttribute('href')).toBe('jf-url');
});
});
});
-33
View File
@@ -1,33 +0,0 @@
describe('DocsApp', function() {
// Do not run this suite on Internet Explorer.
if (msie < 10) return;
beforeEach(module('docsApp'));
describe('DocsVersionsCtrl', function() {
var $scope, ctrl, window, version = '9.8.7';
beforeEach(function() {
module(function($provide) {
$provide.value('$window', window = createMockWindow());
});
inject(function($controller, $rootScope) {
$scope = $rootScope.$new();
$scope.version = version;
ctrl = $controller('DocsVersionsCtrl',{
$scope : $scope,
$window : window
});
});
});
describe('changing the URL', function() {
it('should jump to the url provided', function() {
$scope.jumpToDocsVersion({ version: '1.0.1', url : 'page123'});
expect(window.location).toBe('page123');
});
});
});
});
-392
View File
@@ -1,392 +0,0 @@
'use strict';
var directive = {};
directive.dropdownToggle =
['$document', '$location', '$window',
function ($document, $location, $window) {
var openElement = null, close;
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
close && close();
});
element.parent().on('click', function(event) {
close && close();
});
element.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
var iWasOpen = false;
if (openElement) {
iWasOpen = openElement === element;
close();
}
if (!iWasOpen){
element.parent().addClass('open');
openElement = element;
close = function (event) {
event && event.preventDefault();
event && event.stopPropagation();
$document.off('click', close);
element.parent().removeClass('open');
close = null;
openElement = null;
}
$document.on('click', close);
}
});
}
};
}];
directive.syntax = function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
function makeLink(type, text, link, icon) {
return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' +
'<span class="' + icon + '"></span> ' + text +
'</a>';
};
var html = '';
var types = {
'github' : {
text : 'View on Github',
key : 'syntaxGithub',
icon : 'icon-github'
},
'plunkr' : {
text : 'View on Plunkr',
key : 'syntaxPlunkr',
icon : 'icon-arrow-down'
},
'jsfiddle' : {
text : 'View on JSFiddle',
key : 'syntaxFiddle',
icon : 'icon-cloud'
}
};
for(var type in types) {
var data = types[type];
var link = attrs[data.key];
if(link) {
html += makeLink(type, data.text, link, data.icon);
}
};
var nav = document.createElement('nav');
nav.className = 'syntax-links';
nav.innerHTML = html;
var node = element[0];
var par = node.parentNode;
par.insertBefore(nav, node);
}
}
}
directive.tabbable = function() {
return {
restrict: 'C',
compile: function(element) {
var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
tabContent = angular.element('<div class="tab-content"></div>');
tabContent.append(element.contents());
element.append(navTabs).append(tabContent);
},
controller: ['$scope', '$element', function($scope, $element) {
var navTabs = $element.contents().eq(0),
ngModel = $element.controller('ngModel') || {},
tabs = [],
selectedTab;
ngModel.$render = function() {
var $viewValue = this.$viewValue;
if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
if(selectedTab) {
selectedTab.paneElement.removeClass('active');
selectedTab.tabElement.removeClass('active');
selectedTab = null;
}
if($viewValue) {
for(var i = 0, ii = tabs.length; i < ii; i++) {
if ($viewValue == tabs[i].value) {
selectedTab = tabs[i];
break;
}
}
if (selectedTab) {
selectedTab.paneElement.addClass('active');
selectedTab.tabElement.addClass('active');
}
}
}
};
this.addPane = function(element, attr) {
var li = angular.element('<li><a href></a></li>'),
a = li.find('a'),
tab = {
paneElement: element,
paneAttrs: attr,
tabElement: li
};
tabs.push(tab);
attr.$observe('value', update)();
attr.$observe('title', function(){ update(); a.text(tab.title); })();
function update() {
tab.title = attr.title;
tab.value = attr.value || attr.title;
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
// we are not part of angular
ngModel.$viewValue = tab.value;
}
ngModel.$render();
}
navTabs.append(li);
li.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
if (ngModel.$setViewValue) {
$scope.$apply(function() {
ngModel.$setViewValue(tab.value);
ngModel.$render();
});
} else {
// we are not part of angular
ngModel.$viewValue = tab.value;
ngModel.$render();
}
});
return function() {
tab.tabElement.remove();
for(var i = 0, ii = tabs.length; i < ii; i++ ) {
if (tab == tabs[i]) {
tabs.splice(i, 1);
}
}
};
}
}]
};
};
directive.table = function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if (!attrs['class']) {
element.addClass('table table-bordered table-striped code-table');
}
}
};
};
var popoverElement = function() {
var object = {
init : function() {
this.element = angular.element(
'<div class="popover popover-incode top">' +
'<div class="arrow"></div>' +
'<div class="popover-inner">' +
'<div class="popover-title"><code></code></div>' +
'<div class="popover-content"></div>' +
'</div>' +
'</div>'
);
this.node = this.element[0];
this.element.css({
'display':'block',
'position':'absolute'
});
angular.element(document.body).append(this.element);
var inner = this.element.children()[1];
this.titleElement = angular.element(inner.childNodes[0].firstChild);
this.contentElement = angular.element(inner.childNodes[1]);
//stop the click on the tooltip
this.element.bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
var self = this;
angular.element(document.body).bind('click',function(event) {
if(self.visible()) self.hide();
});
},
show : function(x,y) {
this.element.addClass('visible');
this.position(x || 0, y || 0);
},
hide : function() {
this.element.removeClass('visible');
this.position(-9999,-9999);
},
visible : function() {
return this.position().y >= 0;
},
isSituatedAt : function(element) {
return this.besideElement ? element[0] == this.besideElement[0] : false;
},
title : function(value) {
return this.titleElement.html(value);
},
content : function(value) {
if(value && value.length > 0) {
value = marked(value);
}
return this.contentElement.html(value);
},
positionArrow : function(position) {
this.node.className = 'popover ' + position;
},
positionAway : function() {
this.besideElement = null;
this.hide();
},
positionBeside : function(element) {
this.besideElement = element;
var elm = element[0];
var x = elm.offsetLeft;
var y = elm.offsetTop;
x -= 30;
y -= this.node.offsetHeight + 10;
this.show(x,y);
},
position : function(x,y) {
if(x != null && y != null) {
this.element.css('left',x + 'px');
this.element.css('top', y + 'px');
}
else {
return {
x : this.node.offsetLeft,
y : this.node.offsetTop
};
}
}
};
object.init();
object.hide();
return object;
};
directive.popover = ['popoverElement', function(popover) {
return {
restrict: 'A',
priority : 500,
link: function(scope, element, attrs) {
element.bind('click',function(event) {
event.preventDefault();
event.stopPropagation();
if(popover.isSituatedAt(element) && popover.visible()) {
popover.title('');
popover.content('');
popover.positionAway();
}
else {
popover.title(attrs.title);
popover.content(attrs.content);
popover.positionBeside(element);
}
});
}
}
}];
directive.tabPane = function() {
return {
require: '^tabbable',
restrict: 'C',
link: function(scope, element, attrs, tabsCtrl) {
element.on('$remove', tabsCtrl.addPane(element, attrs));
}
};
};
directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
return {
restrict: 'A',
priority : 500,
link: function(scope, element, attrs) {
var container, loading, url = attrs.url;
if(/\/build\//.test($window.location.href)) {
url = '/build/docs' + url;
}
element.bind('click',function() {
scope.$apply(function() {
if(!container) {
if(loading) return;
loading = true;
var par = element.parent();
container = angular.element('<div class="foldout">loading...</div>');
$animate.enter(container, null, par);
$http.get(url, { cache : true }).success(function(html) {
loading = false;
html = '<div class="foldout-inner">' +
'<div calss="foldout-arrow"></div>' +
html +
'</div>';
container.html(html);
//avoid showing the element if the user has already closed it
if(container.css('display') == 'block') {
container.css('display','none');
$animate.addClass(container, 'ng-hide');
}
});
}
else {
container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
}
});
});
}
}
}];
angular.module('bootstrap', [])
.directive(directive)
.factory('popoverElement', popoverElement)
.run(function() {
marked.setOptions({
gfm: true,
tables: true
});
});
+3 -294
View File
@@ -2,297 +2,6 @@
@name API Reference
@description
# AngularJS API Docs
Welcome to the AngularJS API docs page. These pages contain the AngularJS reference materials for version <strong ng-bind="version"></strong>.
The documentation is organized into **modules** which contain various components of an AngularJS application.
These components are directives, services, filters, providers, types, global APIs and testing mocks.
<div class="alert alert-info">
**Angular Namespaces `$` and `$$`**
To prevent accidental name collisions with your code,
Angular prefixes names of public objects with `$` and names of private objects with `$$`.
Please do not use the `$` or `$$` prefix in your code.
</div>
## Angular Namespace
## {@link ng ng (core module)}
This module is provided by default and contains the core components of AngularJS.
<table class="definition-table spaced">
<tr>
<td>{@link ng#directive Directives}</td>
<td>
<p>
This is the core collection of directives you would use in your template code to build an AngularJS application.
</p>
<p>
Some examples include:
{@link ng.directive:ngClick ngClick},
{@link ng.directive:ngInclude ngInclude},
{@link ng.directive:ngRepeat ngRepeat},
etc… <br />
</p>
</td>
</tr>
<tr>
<td>
{@link ng#service Services / Factories}
</td>
<td>
<p>
This is the core collection of services which are used within the DI of your application.
</p>
<p>
Some examples include:
{@link ng.$compile $compile},
{@link ng.$http $http},
{@link ngRoute.$routeParams $routeParams},
{@link ng.$location $location},
etc…
<p>
</td>
</tr>
<tr>
<td>
{@link ng#filter Filters}
</td>
<td>
<p>
The core filters available in the ng module are used to transform template data before it is renders within directives and expressions.
</p>
<p>
Some examples include:
{@link ng.filter:filter filter},
{@link ng.filter:date date},
{@link ng.filter:currency currency},
{@link ng.filter:lowercase lowercase},
{@link ng.filter:uppercase uppercase},
etc...
</p>
</td>
</tr>
<tr>
<td>
{@link ng#function Global APIs}
</td>
<td>
<p>
The core global API functions are attached to the angular object. These core functions are useful for low level JavaScript operations within your application.
</p>
<p>
Some examples include:
{@link angular.copy angular.copy()},
{@link angular.equals angular.equals()},
{@link angular.element angular.element()},
etc...
</p>
</td>
</tr>
</table>
## {@link ngRoute ngRoute}
Use ngRoute to enable URL routing to your application. The ngRoute module supports URL management via both hashbang and HTML5 pushState.
<div class="alert alert-info">Include the **angular-route.js** file and set **ngRoute** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngRoute#service Services / Factories}
</td>
<td>
The following services are used for route management:
<ul>
<li>{@link ngRoute.$routeParams $routeParams} is used to access the querystring values present in the URL.</li>
<li>{@link ngRoute.$route $route} is used to access the details of the route that is currently being accessed.</li>
<li>{@link ngRoute.$routeProvider $routeProvider} is used to register routes for the application.</li>
</ul>
</td>
</tr>
<tr>
<td>
{@link ngRoute#directive Directives}
</td>
<td>
The {@link ngRoute.directive:ngView ngView} directive will display the template of the current route within the page.
</td>
</tr>
</table>
## {@link ngAnimate ngAnimate}
Use ngAnimate to enable animation features into your application. Various core ng directives will provide
animation hooks into your application when ngAnimate is included. Animations are defined by using CSS transitions/animations
or JavaScript callbacks.
<div class="alert alert-info">Include the **angular-animate.js** file and set **ngAnimate** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngAnimate#service Services / Factories}
</td>
<td>
Use {@link ngAnimate.$animate $animate} to trigger animation operations within your directive code.
</td>
</tr>
<tr>
<td>
{@link ngAnimate CSS-based animations}
</td>
<td>
Follow ngAnimates CSS naming structure to reference CSS transitions / keyframe animations in AngularJS. Once defined the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
<tr>
<td>
{@link ngAnimate JS-based animations}
</td>
<td>
Use {@link angular.Module#methods_animation module.animation()} to register a JavaScript animation. Once registered the animation can be triggered by referencing the CSS class within the HTML template code.
</td>
</tr>
</table>
## {@link ngResource ngResource}
Use the ngResource module when querying and posting data to a REST API.
<div class="alert alert-info">Include the **angular-resource.js** file and set **ngResource** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngResource#service Services / Factories}
</td>
<td>
The {@link ngResource.$resource $resource} service is used to define RESTful objects which communicate with a REST API.
</td>
</tr>
</table>
## {@link ngCookies ngCookies}
Use the ngCookies module to handle cookie management within your application.
<div class="alert alert-info">Include the **angular-cookies.js** file and set **ngCookies** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngCookies#service Services / Factories}
</td>
<td>
The following services are used for cookie management:
<ul>
<li>The {@link ngCookies.$cookies $cookie} service is a convenient wrapper to store simple data within browser cookies.</li>
<li>{@link ngCookies.$cookieStore $cookieStore} is used to store more complex data using serialization.</li>
</ul>
</td>
</tr>
</table>
## {@link ngTouch ngTouch}
Use ngTouch when developing for mobile browsers/devices.
<div class="alert alert-info">Include the **angular-touch.js** file and set **ngTouch** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngTouch#service Services / Factories}
</td>
<td>
The {@link ngTouch.$swipe $swipe} service is used to register and manage mobile DOM events.
</td>
</tr>
<tr>
<td>
{@link ngTouch#directive Directives}
</td>
<td>
Various directives are available in ngTouch to emulate mobile DOM events.
</td>
</tr>
</table>
## {@link ngSanitize ngSanitize}
Use ngSanitize to securely parse and manipulate HTML data in your application.
<div class="alert alert-info">Include the **angular-sanitize.js** file and set **ngSanitize** as a dependency for this to work in your application.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngSanitize#service Services / Factories}
</td>
<td>
The {@link ngSanitize.$sanitize $sanitize} service is used to clean up dangerous HTML code in a quick and convenient way.
</td>
</tr>
<tr>
<td>
{@link ngTouch#filter Filters}
</td>
<td>
The {@link ngSanitize.filter:linky linky filter} is used to turn URLs into HTML links within the provided string.
</td>
</tr>
</table>
## {@link ngMock ngMock}
Use ngMock to inject and mock modules, factories, services and providers within your unit tests
<div class="alert alert-info">Include the **angular-mocks.js** file into your test runner for this to work.</div>
<table class="definition-table spaced">
<tr>
<td>
{@link ngMock#service Services / Factories}
</td>
<td>
<p>
ngMock will extend the behavior of various core services to become testing aware and manageable in a synchronous manner.
<p>
<p>
Some examples include:
{@link ngMock.$timeout $timeout},
{@link ngMock.$interval $interval},
{@link ngMock.$log $log},
{@link ngMock.$httpBackend $httpBackend},
etc...
<p>
</td>
</tr>
<tr>
<td>
{@link ngMock#function Global APIs}
</td>
<td>
<p>
Various helper functions are available to inject and mock modules within unit test code.
</p>
<p>
Some examples
{@link angular.mock.inject inject()},
{@link angular.mock.module module()},
{@link angular.mock.dump dump()},
etc...
<p>
</td>
</tr>
</table>
Use the API Reference documentation when you need more information about a specific feature. Check out
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recommend the
{@link tutorial/ Tutorial}.
+1 -4
View File
@@ -2,7 +2,4 @@
@name ng
@description
# ng (core module)
The ng module is loaded by default when an AngularJS application is started. The module itself contains the essential components to for an AngularJS application to function. The table below lists a high level breakdown of each of the services/factories, filters, directives and testing components available within this core module.
<div doc-module-components="ng"></div>
The `ng` is an angular module which contains all of the core angular services.
+8 -3
View File
@@ -38,8 +38,13 @@ detection, and preventing invalid form submission.
$scope.form.contacts.push({type:'', value:''});
};
$scope.removeContact = function(index) {
$scope.form.contacts.splice(index, 1);
$scope.removeContact = function(contact) {
var contacts = $scope.form.contacts;
for (var i = 0, ii = contacts.length; i < ii; i++) {
if (contact === contacts[i]) {
contacts.splice(i, 1);
}
}
};
$scope.isCancelDisabled = function() {
@@ -78,7 +83,7 @@ detection, and preventing invalid form submission.
<option>IM</option>
</select>
<input type="text" ng-model="contact.value" required/>
[ <a href="" ng-click="removeContact($index)">X</a> ]
[ <a href="" ng-click="removeContact(contact)">X</a> ]
</div>
<button ng-click="cancel()" ng-disabled="isCancelDisabled()">Cancel</button>
<button ng-click="save()" ng-disabled="isSaveDisabled()">Save</button>
+6 -6
View File
@@ -30,9 +30,9 @@ In this example we have a simple app which consist of two screens:
* Welcome: url `welcome` Show the user contact information.
* Settings: url `settings` Show an edit screen for user contact information.
<example module="deepLinking" deps="angular-route.js, angular-sanitize.js">
<example module="deepLinking" deps="angular-sanitize.js">
<file name="script.js">
angular.module('deepLinking', ['ngRoute', 'ngSanitize'])
angular.module('deepLinking', ['ngSanitize'])
.config(function($routeProvider) {
$routeProvider.
when("/welcome", {templateUrl:'welcome.html', controller:WelcomeCntl}).
@@ -141,11 +141,11 @@ In this example we have a simple app which consist of two screens:
# Things to notice
* Routes are defined in the `AppCntl` class. The initialization of the controller causes the
initialization of the {@link api/ngRoute.$route $route} service with the proper URL
initialization of the {@link api/ng.$route $route} service with the proper URL
routes.
* The {@link api/ngRoute.$route $route} service then watches the URL and instantiates the
* The {@link api/ng.$route $route} service then watches the URL and instantiates the
appropriate controller when the URL changes.
* The {@link api/ngRoute.directive:ngView ngView} widget loads the
* The {@link api/ng.directive:ngView ngView} widget loads the
view when the URL changes. It also sets the view scope to the newly instantiated controller.
* Changing the URL is sufficient to change the controller and view. It makes no difference whether
the URL is changed programmatically or by the user.
the URL is changed programatically or by the user.
+3 -3
View File
@@ -10,9 +10,9 @@
}
</script>
<div ng-controller="HelloCntl">
Your name: <input type="text" ng-model="name"/>
Your name: <input type="text" ng-model="name" value="World"/>
<hr/>
Hello {{name || "World"}}!
Hello {{name}}!
</div>
</doc:source>
<doc:scenario>
@@ -34,6 +34,6 @@ Take a look through the source and note:
* There is no need for listener registration and event firing on change events.
* The implicit presence of the `name` variable which is in the root {@link api/ng.$rootScope.Scope scope}.
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
* The concept of {@link guide/databinding data binding}, which reflects any
* The concept of {@link guide/dev_guide.templates.databinding data binding}, which reflects any
changes to the
input field in the greeting text.
+3 -3
View File
@@ -85,8 +85,8 @@ view.
Next Player: {{nextMove}}
<div class="winner" ng-show="winner">Player {{winner}} has won!</div>
<table class="board">
<tr ng-repeat="row in board track by $index" style="height:15px;">
<td ng-repeat="cell in row track by $index" ng-style="cellStyle"
<tr ng-repeat="row in board" style="height:15px;">
<td ng-repeat="cell in row" ng-style="cellStyle"
ng-click="dropPiece($parent.$index, $index)">{{cell}}</td>
</tr>
</table>
@@ -125,4 +125,4 @@ board variable.
* The view can call any controller function.
* In this example, the `setUrl()` and `readUrl()` functions copy the game state to/from the URL's
hash so the browser's back button will undo game steps. See deep-linking. This example calls {@link
api/ng.$rootScope.Scope#methods_$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
api/ng.$rootScope.Scope#$watch $watch()} to set up a listener that invokes `readUrl()` when needed.
-6
View File
@@ -1,6 +0,0 @@
@ngdoc error
@name $animate:notcsel
@fullName Not class CSS selector
@description
Expecting a CSS selector for class. Class selectors must start with `.`, for example: `.my-class-name`.
@@ -1,8 +0,0 @@
@ngdoc error
@name $cacheFactory:iid
@fullName Invalid ID
@description
This error occurs when trying to create a new `cache` object via {@link api/ng.$cacheFactory} with an ID that was already used to create another cache object.
To resolve the error please use a different cache ID when calling `$cacheFactory`.
-49
View File
@@ -1,49 +0,0 @@
@ngdoc error
@name $compile:ctreq
@fullName Missing Required Controller
@description
This error occurs when {@link api/ng.$compile HTML compiler} tries to process a directive that specifies the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object `require` option} in a {@link api/ng.$compile#description_comprehensive-directive-api directive definition},
but the required directive controller is not present on the current DOM element (or its ancestor element, if `^` was specified).
To resolve this error ensure that there is no typo in the required controller name and that the required directive controller is present on the current element.
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.
Example of a directive that requires {@link api/ng.directive:ngModel ngModel} controller:
```
myApp.directive('myDirective', function() {
return {
require: 'ngModel',
...
}
}
```
This directive can then be used as:
```
<input ng-model="some.path" my-directive>
```
Example of a directive that optionally requires a {@link api/ng.directive:form form} controller from an ancestor:
```
myApp.directive('myDirective', function() {
return {
require: '^?form',
...
}
}
```
This directive can then be used as:
```
<form name="myForm">
<div>
<span my-directive></span>
</div>
</form>
```
-25
View File
@@ -1,25 +0,0 @@
@ngdoc error
@name $compile:iscp
@fullName Invalid Isolate Scope Definition
@description
When declaring isolate scope the scope definition object must be in specific format which starts with mode character (`@&=`) with an optional local name.
```
myModule.directive('directiveName', function factory() {
return {
...
scope: {
'attrName': '@', // OK
'attrName2': '=localName', // OK
'attrName3': 'name', // ERROR: missing mode @&=
'attrName4': ' = name', // ERROR: extra spaces
'attrName5': 'name=', // ERROR: must be prefixed with @&=
}
...
}
});
```
Please refer to the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object
`scope` option} of the directive definition documentation to learn more about the API.
-17
View File
@@ -1,17 +0,0 @@
@ngdoc error
@name $compile:multidir
@fullName Multiple Directive Resource Contention
@description
This error occurs when multiple directives are applied to the same DOM element, and
processing them would result in a collision or an unsupported configuration.
To resolve this issue remove one of the directives which is causing the collision.
Example scenarios of multiple incompatible directives applied to the same element include:
* Multiple directives requesting `isolated scope`.
* Multiple directives publishing a controller under the same name.
* Multiple directives declared with the `transclusion` option.
* Multiple directives attempting to define a `template` or `templateURL`.
@@ -1,20 +0,0 @@
@ngdoc error
@name $compile:nodomevents
@fullName Interpolated Event Attributes
@description
This error occurs when one tries to create a binding for event handler attributes like `onclick`, `onload`, `onsubmit`, etc.
There is no practical value in binding to these attributes and doing so only exposes your application to security vulnerabilities like XSS.
For these reasons binding to event handler attributes (all attributes that start with `on` and `formaction` attribute) is not supported.
An example code that would allow XSS vulnerability by evaluating user input in the window context could look like this:
```
<input ng-mode="username">
<div onclick="{{username}}">click me</div>
```
Since the `onclick` evaluates the value as JavaScript code in the window context, setting the `username` model to a value like `javascript:alert('PWND')` would result in script injection when the `div` is clicked.
@@ -1,41 +0,0 @@
@ngdoc error
@name $compile:nonassign
@fullName Non-Assignable Expression
@description
This error occurs when a directive defines an isolate scope property
(using the `=` mode in the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object
`scope` option} of a directive definition) but the directive is used with an expression that is not-assignable.
In order for the two-way data-binding to work, it must be possible to write new values back into the path defined with the expression.
For example, given a directive:
```
myModule.directive('myDirective', function factory() {
return {
...
scope: {
'bind': '=localValue'
}
...
}
});
```
Following are invalid uses of this directive:
```
<!-- ERROR because `1+2=localValue` is an invalid statement -->
<my-directive bind="1+2">
<!-- ERROR because `myFn()=localValue` is an invalid statement -->
<my-directive bind="myFn()">
```
To resolve this error, always use path expressions with scope properties that are two-way data-bound:
```
<my-directive bind="some.property">
<my-directive bind="some[3]['property']">
```
-20
View File
@@ -1,20 +0,0 @@
@ngdoc error
@name $compile:selmulti
@fullName Binding to Multiple Attribute
@description
Binding to the `multiple` attribute of `select` element is not supported since switching between multiple and single mode changes the {@link api/ng.directive:ngModel `ngModel`} object type from instance to array of instances which breaks the model semantics.
If you need to use different types of `select` elements in your template based on some variable, please use {@link api/ng.directive:ngIf ngIf} or {@link api/ng.directive:ngSwitch ngSwitch} directives to select one of them to be used at runtime.
Example with invalid usage:
```
<select ng-model="some.model" multiple="{{mode}}"></select>
```
Example that uses ngIf to pick one of the `select` elements based on a variable:
```
<select ng-if="mode == 'multiple'" ng-model="some.model" multiple></select>
<select ng-if="mode != 'multiple'" ng-model="some.model"></select>
```
-11
View File
@@ -1,11 +0,0 @@
@ngdoc error
@name $compile:tpload
@fullName Error Loading Template
@description
This error occurs when {@link api/ng.$compile `$compile`} attempts to fetch a template from some URL, and the request fails.
To resolve this error, ensure that the URL of the template is spelled correctly and resolves to correct absolute URL.
The [Chrome Developer Tools](https://developers.google.com/chrome-developer-tools/docs/network#network_panel_overview) might also be helpful in determining why the request failed.
If you are using {@link api/ng.$templateCache} to pre-load templates, ensure that the cache was populated with the template.
-39
View File
@@ -1,39 +0,0 @@
@ngdoc error
@name $compile:tplrt
@fullName Invalid Template Root
@description
When a directive is declared with `template` (or `templateUrl`) and `replace` mode on, the template
must have exactly one root element. That is, the text of the template property or the content
referenced by the templateUrl must be contained within a single html element.
For example, `<p>blah <em>blah</em> blah</p>` instead of simply `blah <em>blah</em> blah`.
Otherwise, the replacement operation would result in a single element (the directive) being replaced
with multiple elements or nodes, which is unsupported and not commonly needed in practice.
For example a directive with definition:
```
myModule.directive('myDirective', function factory() {
return {
...
replace: true,
templateUrl: 'someUrl'
...
}
});
```
And a template provided at URL `someUrl`. The template must be an html fragment that has only a
single root element, like the `div` element in this template:
```
<div><b>Hello</b> World!</div>
```
An an invalid template to be used with this directive is one that defines multiple root nodes or
elements. For example:
```
<b>Hello</b> World!
```
-34
View File
@@ -1,34 +0,0 @@
@ngdoc error
@name $compile:uterdir
@fullName Unterminated Directive
@description
This error occurs when using multi-element directives and a `directive-start` attribute fails to form a matching pair with a corresponding `directive-end` attribute.
A `directive-start` should have a matching `directive-end` on a sibling node in the DOM. For instance,
```
<table>
<tr ng-repeat-start="item in list">I get repeated</tr>
<tr ng-repeat-end>I also get repeated</tr>
</table>
```
is a valid example.
This error can occur in several different ways. One is by leaving out the `directive-end` attribute, like so:
```
<div>
<span foo-start></span>
</div>
```
Another is by nesting a `directive-end` inside of `directive-start`, or vice versa:
```
<div>
<span foo-start><span foo-end></span></span>
</div>
```
To avoid this error, make sure each `directive-start` you use has a matching `directive-end` on a sibling node in the DOM.
-21
View File
@@ -1,21 +0,0 @@
@ngdoc error
@name $controller:noscp
@fullName Missing $scope object
@description
This error occurs when {@link api/ng.$controller $controller} service is called in order to instantiate a new controller but no scope is provided via `$scope` property of the locals map.
Example of incorrect usage that leads to this error:
```
$controller(MyController);
//or
$controller(MyController, {scope: newScope});
```
To fix the example above please provide a scope to the $controller call:
```
$controller(MyController, {$scope, newScope});
```
Please consult the {@link api/ng.$controller $controller} service api docs to learn more.
@@ -1,9 +0,0 @@
@ngdoc error
@name $httpBackend:noxhr
@fullName Unsupported XHR
@description
This error occurs in browsers that do not support XmlHttpRequest. AngularJS
supports Safari, Chrome, Firefox, Opera, IE8 and higher, and mobile browsers
(Android, Chrome Mobile, iOS Safari). To avoid this error, use an officially
supported browser.
-13
View File
@@ -1,13 +0,0 @@
@ngdoc overview
@name Error Reference
@description
Use the Error Reference manual to find information about error conditions in
your AngularJS app. Errors thrown in production builds of AngularJS will log
links to this site on the console.
Other useful references for debugging your app include:
- {@link api/ API Reference} for detailed information about specific features
- {@link guide/ Developer Guide} for AngularJS concepts
- {@link tutorial/ Tutorial} for getting started
-26
View File
@@ -1,26 +0,0 @@
@ngdoc error
@name $injector:cdep
@fullName Circular Dependency
@description
This error occurs when the {@link api/angular.injector $injector} tries to get
a service that depends on itself, either directly or indirectly. To fix this,
construct your dependency chain such that there are no circular dependencies.
For example:
```
angular.module('myApp', [])
.factory('myService', function (myService) {
// ...
})
.controller('MyCtrl', function ($scope, myService) {
// ...
});
```
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}.
-26
View File
@@ -1,26 +0,0 @@
@ngdoc error
@name $injector:itkn
@fullName Bad Injection Token
@description
This error occurs when using a bad token as a dependency injection annotation.
Dependency injection annotation tokens should always be strings. Using any other
type will cause this error to be thrown.
Examples of code with bad injection tokens include:
```
var myCtrl = function ($scope, $http) { /* ... */ };
myCtrl.$inject = ['$scope', 42];
myAppModule.controller('MyCtrl', ['$scope', {}, function ($scope, $timeout) {
// ...
}]);
```
The bad injection tokens are `42` in the first example and `{}` in the second.
To avoid the error, always use string literals for dependency injection annotation
tokens.
For an explanation of what injection annotations are and how to use them, refer
to the {@link guide/di Dependency Injection Guide}.
@@ -1,11 +0,0 @@
@ngdoc error
@name $injector:modulerr
@fullName Module Error
@description
This error occurs when a module fails to load due to some exception. The error
message above should provide additional context.
In AngularJS `1.2.0` and later, `ngRoute` has been moved to its own module.
If you are getting this error after upgrading to `1.2.x`, be sure that you've
installed {@link api/ngRoute `ngRoute`}.
-26
View File
@@ -1,26 +0,0 @@
@ngdoc error
@name $injector:nomod
@fullName Module Unavailable
@description
This error occurs when trying to "re-open" a module that has not yet been defined.
To define a new module, call {@link api/angular.module angular.module} with a name
and an array of dependent modules, like so:
```
// When defining a module with no module dependencies,
// the requires array should be defined and empty.
var myApp = angular.module('myApp', []);
```
To retrieve a reference to the same module for further configuration, call
`angular.module` without the `requires` array.
```
var myApp = angular.module('myApp');
```
Calling `angular.module` without the `requires` array when the module has not yet
been defined causes this error to be thrown. To fix it, define your module with
a name and an empty array, as in the first example above.
-26
View File
@@ -1,26 +0,0 @@
@ngdoc error
@name $injector:pget
@fullName Provider Missing $get
@description
This error occurs when attempting to register a provider that does not have a
`$get` method. For example:
```
function BadProvider() {} // No $get method!
angular.module("myApp", [])
.provider('bad', BadProvider); // this throws the error
```
To fix the error, fill in the `$get` method on the provider like so:
```
function GoodProvider() {
this.$get = angular.noop;
}
angular.module("myApp", [])
.provider('good', GoodProvider);
```
For more information, refer to the {@link api/AUTO.$provide#methods_provider
$provide.provider} api doc.
-26
View File
@@ -1,26 +0,0 @@
@ngdoc error
@name $injector:unpr
@fullName Unknown Provider
@description
This error results from the `$injector` being unable to resolve a required
dependency. To fix this, make sure the dependency is defined and spelled
correctly. For example:
```
angular.module('myApp', [])
.controller('myCtrl', ['myService', function (myService) {
// Do something with myService
}]);
```
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', [])
.service('myService', function () { /* ... */ })
.controller('myCtrl', ['myService', function (myService) {
// Do something with myService
}]);
```
@@ -1,7 +0,0 @@
@ngdoc error
@name $interpolate:interr
@fullName Interpolation Error
@description
This error occurs when interpolation fails due to some exception. The error
message above should provide additional context.
@@ -1,12 +0,0 @@
@ngdoc error
@name $interpolate:noconcat
@fullName Multiple Expressions
@description
This error occurs when performing an interpolation that concatenates multiple
expressions when a trusted value is required. Concatenating expressions makes
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 api/ng.$sce $sce} API doc.
-11
View File
@@ -1,11 +0,0 @@
@ngdoc error
@name jqLite:nosel
@fullName Unsupported Selector Lookup
@description
In order to keep Angular small, Angular implements only a subset of the selectors in {@link api/angular.element#description_angulars-jqlite jqLite}.
This error occurs when a jqLite instance is invoked with a selector other than this subset.
In order to resolve this error, rewrite your code to only use tag name selectors and manually traverse the DOM using the APIs provided by jqLite.
Alternatively, you can include a full version of jQuery, which Angular will automatically use and that will make all selectors available.
-7
View File
@@ -1,7 +0,0 @@
@ngdoc error
@name jqLite:offargs
@fullName Invalid jqLite#off() parameter
@description
This error occurs when trying to pass too many arguments to `jqLite#off`. Note
that `jqLite#off` does not support namespaces or selectors like jQuery.
-8
View File
@@ -1,8 +0,0 @@
@ngdoc error
@name jqLite:onargs
@fullName Invalid jqLite#on() Parameters
@description
This error occurs when trying to pass too many arguments to `jqLite#on`. Note
that `jqLite#on` does not support the `selector` or `eventData` parameters as
jQuery does.
@@ -1,17 +0,0 @@
@ngdoc error
@name $location:ihshprfx
@fullName Missing Hash Prefix
@description
This error occurs when {@link api/ng.$location $location} service is configured to use a hash prefix but this prefix was not present in a url that the `$location` service was asked to parse.
For example if you configure `$location` service with prefix `'!'`:
```
myApp.config(function($locationProvider) {
$locationProvider.prefix('!');
});
```
If you enter the app at url `http:/myapp.com/#/myView` this error will be throw.
The correct url for this configuration is `http:/myapp.com/#!/myView` (note the `'!'` after `'#'` symbol).
@@ -1,8 +0,0 @@
@ngdoc error
@name $location:ipthprfx
@fullName Invalid or Missing Path Prefix
@description
This error occurs when you configure the {@link api/ng.$location `$location`} service in the html5 mode, specify a base url for your application via `<base>` element and try to update the location with a path that doesn't match the base prefix.
To resolve this issue, please check the base url specified via the `<base>` tag in the head of your main html document, as well as the url that you tried to set the location to.
@@ -1,9 +0,0 @@
@ngdoc error
@name $location:isrcharg
@fullName Wrong $location.search() argument type
@description
To resolve this error, ensure that the first argument for the `$location.search` call is a `string` or an object.
You can use the stack trace associated with this error to identify the call site that caused this issue.
To learn more, please consult the {@link api/ng.$location `$location`} api docs.
-8
View File
@@ -1,8 +0,0 @@
@ngdoc error
@name ng:areq
@fullName Bad Argument
@description
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.
-8
View File
@@ -1,8 +0,0 @@
@ngdoc error
@name ng:badname
@fullName Bad `hasOwnProperty` Name
@description
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.
-29
View File
@@ -1,29 +0,0 @@
@ngdoc error
@name ng:btstrpd
@fullName App Already Bootstrapped with this Element
@description
Occurs when calling angular.bootstrap on an element that has already been bootstrapped.
This usually happens when you accidentally use both `ng-app` and `angular.bootstrap` to bootstrap an application.
```
<html>
...
<body ng-app="myApp">
<script>
angular.bootstrap(document.body, ['myApp']);
</script>
</body>
</html>
```
Note that for bootrapping purposes, the `<html>` element is the same as `document`, so the following will also throw an error.
```
<html>
...
<script>
angular.bootstrap(document, ['myApp']);
</script>
</html>
```
-10
View File
@@ -1,10 +0,0 @@
@ngdoc error
@name ng:cpi
@fullName Bad Copy
@description
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.
-10
View File
@@ -1,10 +0,0 @@
@ngdoc error
@name ng:cpws
@fullName Copying Window or Scope
@description
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.
@@ -1,27 +0,0 @@
@ngdoc error
@name ngModel:nonassign
@fullName Non-Assignable Expression
@description
This error occurs when expression the {@link api/ng.directive:ngModel ngModel} directive is bound to is a non-assignable expression.
Examples using assignable expressions include:
```
<input ng-model="namedVariable">
<input ng-model="myObj.someProperty">
<input ng-model="indexedArray[0]">
```
Examples of non-assignable expressions include:
```
<input ng-model="foo + bar">
<input ng-model="42">
<input ng-model="'oops'">
<input ng-model="myFunc()">
```
Always make sure that the expression bound via `ngModel` directive can be assigned to.
For more information, see the {@link api/ng.directive:ngModel ngModel API doc}.
-13
View File
@@ -1,13 +0,0 @@
@ngdoc error
@name ngOptions:iexp
@fullName Invalid Expression
@description
This error occurs when 'ngOptions' is passed an expression that isn't in an expected form.
Here's an example of correct syntax:
```
<select ng-model="color" ng-options="c.name for c in colors">
```
For more information on valid expression syntax, see 'ngOptions' in {@link api/ng.directive:select select} directive docs.
@@ -1,7 +0,0 @@
@ngdoc error
@name ngPattern:noregexp
@fullName Expected Regular Expression
@description
This error occurs when 'ngPattern' is passed an expression that isn't a regular expression or doesn't have the expected format.
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:select input} directive docs.
-22
View File
@@ -1,22 +0,0 @@
@ngdoc error
@name ngRepeat:dupes
@fullName Duplicate Key in Repeater
@description
Occurs if there are duplicate keys in an {@link api/ng.directive:ngRepeat ngRepeat} expression. Duplicate keys are banned because AngularJS uses keys to associate DOM nodes with items.
By default, collections are keyed by reference which is desirable for most common models but can be problematic for primitive types that are interned (share references).
For example the issue can be triggered by this *invalid* code:
```
<div ng-repeat="value in [4, 4]"></div>
```
To resolve this error either ensure that the items in the collection have unique identity of use the `track by` syntax to specify how to track the association between models and DOM.
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
```
<div ng-repeat="value in [4, 4] track by $index"></div>
```
-12
View File
@@ -1,12 +0,0 @@
@ngdoc error
@name ngRepeat:iexp
@fullName Invalid Expression
@description
Occurs when there is a syntax error in an {@link api/ng.directive:ngRepeat ngRepeat}'s expression. The expression should be in the form '_item_ in _collection_[ track by _id_]'.
Be aware, the ngRepeat directive parses the expression using a regex before sending _collection_ and optionally _id_ to the AngularJS parser. This error comes from the regex parsing.
To resolve, identify and fix errors in the expression, paying special attention to the 'in' and 'track by' keywords in the expression.
Please consult the api documentation of {@link api/ng.directive:ngRepeat ngRepeat} to learn more about valid syntax.
-25
View File
@@ -1,25 +0,0 @@
@ngdoc error
@name ngRepeat:iidexp
@fullName Invalid Identifier
@description
Occurs when there is an error in the identifier part of {@link api/ng.directive:ngRepeat ngRepeat}'s expression.
To resolve, use either a valid identifier or a tuple (_key_, _value_) where both _key_ and _value_ are valid identifiers.
Examples of *invalid* syntax:
```
<div ng-repeat="33 in users"></div>
<div ng-repeat="someFn() in users"></div>
<div ng-repeat="some user in users"></div>
```
Examples of *valid* syntax:
```
<div ng-repeat="user in users"></div>
<div ng-repeat="(id, user) in userMap"></div>
```
Please consult the api documentation of {@link api/ng.directive:ngRepeat ngRepeat} to learn more about valid syntax.
@@ -1,12 +0,0 @@
@ngdoc error
@name ngTransclude:orphan
@fullName Orphan ngTransclude Directive
@description
Occurs when an `ngTransclude` occurs without a transcluded ancesstor element.
This error often occurs when you have forgotten to set `transclude: true` in some directive definition, and then used `ngTranslude` in the driective's template.
To resolve, either remove the offending `ngTransclude` or check that `transclude: true` is included in the intended directive definition.
Consult the API documentation for {@link guide/directive writing directives} to learn more.
-16
View File
@@ -1,16 +0,0 @@
@ngdoc error
@name $parse:isecdom
@fullName Referencing a DOM node in Expression
@description
Occurs when an expression attempts to access a DOM node.
AngularJS restricts access to DOM nodes from within expressions since it's a known way to
execute arbitrary Javascript code.
This check is only performed on object index and function calls in Angular expressions. These are
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
perform this check - it's up to the developer to not expose such sensitive and powerful objects
directly on the scope chain.
To resolve this error, avoid access to DOM nodes.
-18
View File
@@ -1,18 +0,0 @@
@ngdoc error
@name $parse:isecfld
@fullName Referencing 'constructor' Field in Expression
@description
Occurs when an expression attempts to access an objects constructor field.
AngularJS bans constructor access from within expressions since constructor
access is a known way 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.
Example expression that would result in this error:
```
<div>{{user.constructor.name}}</div>
```
-10
View File
@@ -1,10 +0,0 @@
@ngdoc error
@name $parse:isecfn
@fullName Referencing Function Disallowed
@description
Occurs when an expression attempts to access the 'Function' object (constructor for all functions in JavaScript).
Angular bans access to Function from within expressions since constructor access is a known way to execute arbitrary Javascript code.
To resolve this error, avoid Function access.
-16
View File
@@ -1,16 +0,0 @@
@ngdoc error
@name $parse:isecwindow
@fullName Referencing Window object in Expression
@description
Occurs when an expression attempts to access a Window object.
AngularJS restricts access to the Window object from within expressions since it's a known way to
execute arbitrary Javascript code.
This check is only performed on object index and function calls in Angular expressions. These are
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
perform this check - it's up to the developer to not expose such sensitive and powerful objects
directly on the scope chain.
To resolve this error, avoid Window access.
-10
View File
@@ -1,10 +0,0 @@
@ngdoc error
@name $parse:lexerr
@fullName Lexer Error
@description
Occurs when an expression has a lexical error, for example a malformed number (0.5e-) or an invalid unicode escape.
The error message contains a more precise error.
To resolve, learn more about {@link guide/expression Angular expressions}, identify the error and fix the expression's syntax.
-9
View File
@@ -1,9 +0,0 @@
@ngdoc error
@name $parse:syntax
@fullName Syntax Error
@description
Occurs when there is a syntax error in an expression. These errors are thrown while compiling the expression.
The error message contains a more precise description of the error, including the location (column) in the expression where the error occurred.
To resolve, learn more about {@link guide/expression Angular expressions}, identify the error and fix the expression's syntax.
-9
View File
@@ -1,9 +0,0 @@
@ngdoc error
@name $parse:ueoe
@fullName Unexpected End of Expression
@description
Occurs when an expression is missing tokens at the end of the expression.
For example, forgetting a closing bracket in an expression will trigger this error.
To resolve, learn more about {@link guide/expression Angular expressions}, identify the error and fix the expression's syntax.
@@ -1,9 +0,0 @@
@ngdoc error
@name $resource:badargs
@fullName Too Many Arguments
@description
This error occurs when specifying too many arguments to a {@link api/ngResource.$resource `$resource`} action, such as `get`, `query` or any user-defined custom action.
These actions may take up to 4 arguments.
For more information, refer to the {@link api/ngResource.$resource `$resource`} API reference documentation.
-11
View File
@@ -1,11 +0,0 @@
@ngdoc error
@name $resource:badcfg
@fullName Response does not match configured parameter
@description
This error occurs when the {@link api/ngResource.$resource `$resource`} service expects a response that can be deserialized as an array, receives an object, or vice versa.
By default, all resource actions expect objects, except `query` which expects arrays.
To resolve this error, make sure your `$resource` configuration matches the actual format of the data returned from the server.
For more information, see the {@link api/ngResource.$resource `$resource`} API reference documentation.
@@ -1,27 +0,0 @@
@ngdoc error
@name $resource:badmember
@fullName Syntax error in param value using @member lookup
@description
Occurs when there is a syntax error when attempting to extract a param
value from the data object.
Here's an example of valid syntax for `params` or `paramsDefault`:
````javascript
{
bar: '@foo.bar'
}
````
The part following the `@`, `foo.bar` in this case, should be a simple
dotted member lookup using only ASCII identifiers. This error occurs
when there is an error in that expression. The following are all syntax
errors
| Value | Error |
|---------|----------------|
| `@` | Empty expression following `@`. |
| `@1.a` | `1` is an invalid javascript identifier. |
| `@.a` | Leading `.` is invalid. |
| `@a[1]` | Only dotted lookups are supported (no index operator) |
@@ -1,8 +0,0 @@
@ngdoc error
@name $resource:badname
@fullName Cannot use hasOwnProperty as a parameter name
@description
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.
-17
View File
@@ -1,17 +0,0 @@
@ngdoc error
@name $rootScope:infdig
@fullName Infinite $digest Loop
@description
This error occurs when the application's model becomes unstable and each `$digest` cycle triggers a state change and subsequent `$digest` cycle.
Angular detects this situation and prevents an infinite loop from causing the browser to become unresponsive.
For example, the situation can occur by setting up a watch on a path and subsequently updating the same path when the value changes.
```
$scope.$watch('foo', function() {
$scope.foo = $scope.foo + 1;
});
```
The maximum number of allowed iterations of the `$digest` cycle is controlled via TTL setting which can be configured via {@link api/ng.$rootScopeProvider $rootScopeProvider}.
-74
View File
@@ -1,74 +0,0 @@
@ngdoc error
@name $rootScope:inprog
@fullName Action Already In Progress
@description
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.
`$digest` or `$apply` are processing operational states of the Scope - data-structure in Angular that provides context for models and enables model mutation observation.
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:
```
function MyController() {
thirdPartyComponent.getData(function(someData) {
scope.$apply(function() {
scope.someData = someData;
});
});
}
```
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.
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.
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.
For example:
```
myApp.directive('myDirective', function() {
return {
link: function($scope, $element) {
function doSomeWork() {
$scope.$apply(function() {
// do work here, and update the model
};
}
$element.on('click', doSomeWork);
doSomeWork(); // << this will throw an exception because templates are compiled within $apply
}
}
});
```
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
}
$element.on('click', function() {
$scope.$apply(doSomeWork); // <<< the $apply call was moved to the callsite that doesn't execute in $apply call already
});
doSomeWork();
}
}
});
```
To learn more about Angular processing model please check out the {@link guide/concepts concepts doc} as well as the {@link api/ng.$rootScope.Scope api} doc.
@@ -1,11 +0,0 @@
@ngdoc error
@name $sanitize:badparse
@fullName Parsing Error while Sanitizing
@description
This error occurs when the HTML string passed to '$sanitize' can't be parsed by the sanitizer.
The error contains part of the html string that can't be parsed.
The parser is more strict than a typical browser parser, so it's possible that some obscure input would produce this error despite the string being recognized as valid HTML by a browser.
If a valid html code results in this error, please file a bug.
-8
View File
@@ -1,8 +0,0 @@
@ngdoc error
@name $sce:icontext
@fullName Invalid / Unknown SCE context
@description
The context enum passed to {@link api/ng.$sce#methods_trustAs $sce.trustAs} was not recognized.
Please consult the list of {@link api/ng.$sce#contexts supported Strict Contextual Escaping (SCE) contexts}.
-15
View File
@@ -1,15 +0,0 @@
@ngdoc error
@name $sce:iequirks
@fullName IE8 in quirks mode is unsupported
@description
This error occurs when you are using AngularJS with {@link api/ng.$sce Strict Contextual Escaping (SCE)} mode enabled (the default) on IE8 or lower in quirks mode.
In this mode, IE8 allows one to execute arbitrary javascript by the use of the `expression()` syntax and is not supported.
Refer {@link http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx MSDN Blogs > IEBlog > Ending Expressions} to learn more about them.
To resolve this error please specify the proper doctype at the top of your main html document:
```
<!doctype html>
```
-9
View File
@@ -1,9 +0,0 @@
@ngdoc error
@name $sce:imatcher
@fullName Invalid matcher (only string patterns and RegExp instances are supported)
@description
Please see {@link api/ng.$sceDelegateProvider#methods_resourceUrlWhitelist
$sceDelegateProvider.resourceUrlWhitelist} and {@link
api/ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
list of acceptable items.
-26
View File
@@ -1,26 +0,0 @@
@ngdoc error
@name $sce:insecurl
@fullName Processing of a Resource from Untrusted Source Blocked
@description
AngularJS' {@link api/ng.$sce Strict Contextual Escaping (SCE)} mode (enabled by default) has blocked loading a resource from an insecure URL.
Typically, this would occur if you're attempting to load an Angular template from an untrusted source.
It's also possible that a custom directive threw this error for a similar reason.
Angular only loads templates from trusted URLs (by calling {@link api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl} on the template URL).
By default, only URLs that belong to the same origin are trusted. These are urls with the same domain and protocol as the application document.
The {@link api/ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
To load templates from other domains and/or protocols, either adjust the {@link
api/ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist}/ {@link
api/ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
api/ng.$sce#methods_trustAsResourceUrl $sce.trustAsResourceUrl}.
**Note**: The browser's {@link
https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest Same Origin
Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)} policy apply
that may further restrict whether the template is successfully loaded. (e.g. neither cross-domain
requests won't work on all browsers nor `file://` requests on some browsers)
-8
View File
@@ -1,8 +0,0 @@
@ngdoc error
@name $sce:itype
@fullName String Value is Required for SCE Trust Call
@description
{@link api/ng.$sce#methods_trustAs $sce.trustAs} requires a string value.
Read more about {@link api/ng.$sce Strict Contextual Escaping (SCE)} in AngularJS.
-9
View File
@@ -1,9 +0,0 @@
@ngdoc error
@name $sce:iwcard
@fullName The sequence *** is not a valid pattern wildcard
@description
The strings in {@link api/ng.$sceDelegateProvider#methods_resourceUrlWhitelist
$sceDelegateProvider.resourceUrlWhitelist} and {@link
api/ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
contain the undefined sequence `***`. Only `*` and `**` wildcard patterns are defined.
-15
View File
@@ -1,15 +0,0 @@
@ngdoc error
@name $sce:unsafe
@fullName Require a safe/trusted value
@description
The value provided for use in a specific context was not found to be safe/trusted for use.
Angular's {@link api/ng.$sce Strict Contextual Escaping (SCE)} mode
(enabled by default), requires bindings in certain
contexts to result in a value that is trusted as safe for use in such a context. (e.g. loading an
Angular template from a URL requires that the URL is one considered safe for loading resources.)
This helps prevent XSS and other security issues. Read more at {@link
api/ng.$sce Strict Contextual Escaping (SCE)}
-289
View File
@@ -1,289 +0,0 @@
@ngdoc overview
@name Developer Guide: Animations
@description
# Animations
AngularJS 1.2 provides animation hooks for common directives such as `ngRepeat`, `ngSwitch`, and `ngView`, as well as custom directives
via the `$animate` service. These animation hooks are set in place to trigger animations during the life cycle of various directives and when
triggered, will attempt to perform a CSS Transition, CSS Keyframe Animation or a JavaScript callback Animation (depending on if an animation is
placed on the given directive). Animations can be placed using vanilla CSS by following the naming conventions set in place by AngularJS
or with JavaScript code when it's defined as a factory.
Animations are not available unless you include the {@link api/ngAnimate `ngAnimate` module} as a dependency within your application.
Below is a quick example of animations being enabled for `ngShow` and `ngHide`:
<example animations="true">
<file name="index.html">
<div ng-init="checked=true">
<label>
<input type="checkbox" ng-model="checked" style="float:left; margin-right:10px;"> Is Visible...
</label>
<div class="check-element animate-show-hide" ng-show="checked" style="clear:both;">
Visible...
</div>
</div>
</file>
<file name="animations.css">
.animate-show-hide {
padding:10px;
border:1px solid black;
background:white;
}
.animate-show-hide.ng-hide-add, .animate-show-hide.ng-hide-remove {
-webkit-transition:all linear 0.5s;
-moz-transition:all linear 0.5s;
-o-transition:all linear 0.5s;
transition:all linear 0.5s;
display:block!important;
}
.animate-show-hide.ng-hide-add.ng-hide-add-active,
.animate-show-hide.ng-hide-remove {
opacity:0;
}
.animate-show-hide.ng-hide-add,
.animate-show-hide.ng-hide-remove.ng-hide-remove-active {
opacity:1;
}
</file>
</example>
## Installation
See the {@link api/ngAnimate API docs for `ngAnimate`} for instructions on installing the module.
You may also want to setup a separate CSS file for defining CSS-based animations.
## How they work
Animations in AngularJS are completely based on CSS classes. As long as you have a CSS class attached to a HTML element within
your website, you can apply animations to it. Lets say for example that we have an HTML template with a repeater in it like so:
<pre>
<div ng-repeat="item in items" class="repeated-item">
{{ item.id }}
</div>
</pre>
As you can see, the `.repeated-item` class is present on the element that will be repeated and this class will be
used as a reference within our application's CSS and/or JavaScript animation code to tell AngularJS to perform an animation.
As ngRepeat does its thing, each time a new item is added into the list, ngRepeat will add
a `ng-enter` class name to the element that is being added. When removed it will apply a `ng-leave` class name and when moved around
it will apply a `ng-move` class name.
Taking a look at the following CSS code, we can see some transition and keyframe animation code set for each of those events that
occur when ngRepeat triggers them:
<pre>
&#47;&#42;
We're using CSS transitions for when
the enter and move events are triggered
for the element that has the .repeated-item
class
&#42;&#47;
.repeated-item.ng-enter, .repeated-item.ng-move {
-webkit-transition:0.5s linear all;
-moz-transition:0.5s linear all;
-o-transition:0.5s linear all;
transition:0.5s linear all;
opacity:0;
}
&#47;&#42;
The ng-enter-active and ng-move-active
are where the transition destination properties
are set so that the animation knows what to
animate.
&#42;&#47;
.repeated-item.ng-enter.ng-enter-active,
.repeated-item.ng-move.ng-move-active {
opacity:1;
}
&#47;&#42;
We're using CSS keyframe animations for when
the leave event is triggered for the element
that has the .repeated-item class
&#42;&#47;
.repeated-item.ng-leave {
-webkit-animation:0.5s my_animation;
-moz-animation:0.5s my_animation;
-o-animation:0.5s my_animation;
animation:0.5s my_animation;
}
&#64;keyframes my_animation {
from { opacity:1; }
to { opacity:0; }
}
&#47;&#42;
Unfortunately each browser vendor requires
its own definition of keyframe animation code...
&#42;&#47;
&#64;-webkit-keyframes my_animation {
from { opacity:1; }
to { opacity:0; }
}
&#64;-moz-keyframes my_animation {
from { opacity:1; }
to { opacity:0; }
}
&#64;-o-keyframes my_animation {
from { opacity:1; }
to { opacity:0; }
}
</pre>
The same approach to animation can be used using JavaScript code (**jQuery is used within to perform animations**):
<pre>
myModule.animation('.repeated-item', function() {
return {
enter : function(element, done) {
element.css('opacity',0);
jQuery(element).animate({
opacity: 1
}, done);
// optional onDone or onCancel callback
// function to handle any post-animation
// cleanup operations
return function(isCancelled) {
if(isCancelled) {
jQuery(element).stop();
}
}
},
leave : function(element, done) {
element.css('opacity', 1);
jQuery(element).animate({
opacity: 0
}, done);
// optional onDone or onCancel callback
// function to handle any post-animation
// cleanup operations
return function(isCancelled) {
if(isCancelled) {
jQuery(element).stop();
}
}
},
move : function(element, done) {
element.css('opacity', 0);
jQuery(element).animate({
opacity: 1
}, done);
// optional onDone or onCancel callback
// function to handle any post-animation
// cleanup operations
return function(isCancelled) {
if(isCancelled) {
jQuery(element).stop();
}
}
},
// you can also capture these animation events
addClass : function(element, className, done) {},
removeClass : function(element, className, done) {}
}
});
</pre>
With these generated CSS class names present on the element at the time, AngularJS automatically
figures out whether to perform a CSS and/or JavaScript animation. If both CSS and JavaScript animation
code is present, and match the CSS class name on the element, then AngularJS will run both animations at the same time.
## Class and ngClass animation hooks
AngularJS also pays attention to CSS class changes on elements by triggering the **add** and **remove** hooks.
This means that if a CSS class is added to or removed from an element then an animation can be executed in between
before the CSS class addition or removal is finalized. (Keep in mind that AngularJS will only be
able to capture class changes if an **expression** or the **ng-class** directive is used on the element.)
The example below shows how to perform animations during class changes:
<example animations="true">
<file name="index.html">
<p>
<input type="button" value="set" ng-click="myCssVar='css-class'">
<input type="button" value="clear" ng-click="myCssVar=''">
<br>
<span ng-class="myCssVar">CSS-Animated Text</span>
</p>
</file>
<file name="style.css">
.css-class-add, .css-class-remove {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
.css-class,
.css-class-add.css-class-add-active {
color: red;
font-size:3em;
}
.css-class-remove.css-class-remove-active {
font-size:1.0em;
color:black;
}
</file>
</example>
Although the CSS is a little different then what we saw before, the idea is the same.
## Which directives support animations?
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 api/ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave, and move |
| {@link api/ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
| {@link api/ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
| {@link api/ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
| {@link api/ng.directive:ngIf#usage_animations ngIf} | enter and leave |
| {@link api/ng.directive:ngShow#usage_animations ngClass or &#123;&#123;class&#125;&#125;} | add and remove |
| {@link api/ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
For a full breakdown of the steps involved during each animation event, refer to the {@link api/ngAnimate.$animate API docs}.
## How do I use animations in my own directives?
Animations within custom directives can also be established by injecting `$animate` directly into your directive and
making calls to it when needed.
<pre>
myModule.directive('my-directive', ['$animate', function($animate) {
return function(element, scope, attrs) {
element.bind('click', function() {
if(element.hasClass('clicked')) {
$animate.removeClass(element, 'clicked');
} else {
$animate.addClass(element, 'clicked');
}
});
};
}]);
</pre>
## More about animations
For a full breakdown of each method available on `$animate`, see the {@link api/ngAnimate.$animate API documentation}.
To see a complete demo, see the {@link tutorial/step_12 animation step within the AngularJS phonecat tutorial}.
+16 -38
View File
@@ -7,7 +7,8 @@
This page explains the Angular initialization process and how you can manually initialize Angular
if necessary.
## Angular `<script>` Tag
# Angular `<script>` Tag
This example shows the recommended path for integrating Angular with what we call automatic
initialization.
@@ -37,10 +38,6 @@ initialization.
<html ng-app>
* If IE7 support is required add `id="ng-app"`
<html ng-app id="ng-app">
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
`ng:`.)
@@ -49,14 +46,13 @@ initialization.
## Automatic Initialization
# Automatic Initialization
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
Angular initializes automatically upon `DOMContentLoaded` event or when the `angular.js` script is
evaluated if at that time `document.readyState` is set to `'complete'`. At this point Angular looks
for the {@link api/ng.directive:ngApp `ng-app`} directive which designates your application root.
If the {@link api/ng.directive:ngApp `ng-app`} directive is found then Angular will:
Angular initializes automatically upon `DOMContentLoaded` event, at which point Angular looks for
the {@link api/ng.directive:ngApp `ng-app`} directive which
designates your application root. If the {@link
api/ng.directive:ngApp `ng-app`} directive is found then Angular
will:
* load the {@link guide/module module} associated with the directive.
* create the application {@link api/AUTO.$injector injector}
@@ -77,14 +73,16 @@ If the {@link api/ng.directive:ngApp `ng-app`} directive is found then Angular w
## Manual Initialization
# Manual Initialization
If you need to have more control over the initialization process, you can use a manual
bootstrapping method instead. Examples of when you'd need to do this include using script loaders
or the need to perform an operation before Angular compiles a page.
Here is an example of manually initializing Angular:
Here is an example of manually initializing Angular. The example is equivalent to using the {@link
api/ng.directive:ngApp ng-app} directive.
<pre>
<!doctype html>
@@ -94,37 +92,17 @@ Here is an example of manually initializing Angular:
<script src="http://code.angularjs.org/angular.js"></script>
<script>
angular.element(document).ready(function() {
angular.module('myApp', []);
angular.bootstrap(document, ['myApp']);
angular.bootstrap(document);
});
</script>
</body>
</html>
</pre>
Note that we have provided the name of our application module to be loaded into the injector as the second
parameter of the {@link api/angular.bootstrap} function. Notice that `angular.bootstrap` will not create modules
on the fly. You must create any custom {@link guide/module modules} before you pass them as a parameter.
This is the sequence that your code should follow:
1. After the page and all of the code is loaded, find the root element of your AngularJS
application, which is typically the root of the document.
1. After the page and all of the code is loaded, find the root of the HTML template, which is
typically the root of the document.
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the element into an
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the template into an
executable, bi-directionally bound application.
## Deferred Bootstrap
This feature enables tools like Batarang and test runners to
hook into angular's bootstrap process and sneak in more modules
into the DI registry which can replace or augment DI services for
the purpose of instrumentation or mocking out heavy dependencies.
If `window.name` contains prefix `NG_DEFER_BOOTSTRAP!` when
{@link api/angular.bootstrap} is called, the bootstrap process will be paused
until `angular.resumeBootstrap()` is called.
`angular.resumeBootstrap()` takes an optional array of modules that
should be added to the original list of modules that the app was
about to be bootstrapped with.
+35 -271
View File
@@ -2,44 +2,35 @@
@name Developer Guide: HTML Compiler
@description
<div class="alert alert-warning">
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
If you're just getting started, we recommend the {@link tutorial/ tutorial} first.
If you just want to create custom directives, we recommend the {@link guide/directive directives guide}.
If you want a deeper look into Angular's compilation process, you're in the right place.
</div>
# Overview
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
and even create new HTML elements or attributes with custom behavior. Angular calls these behavior
extensions {@link api/ng.$compileProvider#methods_directive directives}.
and even create new HTML element or attributes with custom behavior. Angular calls these behavior
extensions {@link api/ng.$compileProvider#directive directives}.
HTML has a lot of constructs for formatting the HTML for static documents in a declarative fashion.
For example if something needs to be centered, there is no need to provide instructions to the
browser how the window size needs to be divided in half so that the center is found, and that this
center needs to be aligned with the text's center. Simply add an `align="center"` attribute to any
browser how the window size needs to be divided in half so that center is found, and that this
center needs to be aligned with the text's center. Simply add `align="center"` attribute to any
element to achieve the desired behavior. Such is the power of declarative language.
But the declarative language is also limited, since it does not allow you to teach the browser new
syntax. For example there is no easy way to get the browser to align the text at 1/3 the position
instead of 1/2. What is needed is a way to teach the browser new HTML syntax.
instead of 1/2. What is needed is a way to teach browser new HTML syntax.
Angular comes pre-bundled with common directives which are useful for building any app. We also
expect that you will create directives that are specific to your app. These extensions become a
expect that you will create directives that are specific to your app. These extension become a
Domain Specific Language for building your application.
All of this compilation takes place in the web browser; no server side or pre-compilation step is
involved.
## Compiler
# Compiler
Compiler is an Angular service which traverses the DOM looking for attributes. The compilation
process happens in two phases.
Compiler is an angular service which traverses the DOM looking for attributes. The compilation
process happens into two phases.
1. **Compile:** traverse the DOM and collect all of the directives. The result is a linking
function.
@@ -48,16 +39,17 @@ process happens in two phases.
scope model are reflected in the view, and any user interactions with the view are reflected
in the scope model. This makes the scope model the single source of truth.
Some directives such as {@link api/ng.directive:ngRepeat `ng-repeat`} clone DOM elements once
for each item in a collection. Having a compile and link phase improves performance since the
cloned template only needs to be compiled once, and then linked once for each clone instance.
Some directives such {@link api/ng.directive:ngRepeat
`ng-repeat`} clone DOM elements once for each item in collection. Having a compile and link phase
improves performance since the cloned template only needs to be compiled once, and then linked
once for each clone instance.
## Directive
# Directive
A directive is a behavior which should be triggered when specific HTML constructs are encountered
during the compilation process. The directives can be placed in element names, attributes, class
names, as well as comments. Here are some equivalent examples of invoking the {@link
A directive is a behavior which should be triggered when specific HTML constructs are encountered in
the compilation process. The directives can be placed in element names, attributes, class names, as
well as comments. Here are some equivalent examples of invoking the {@link
api/ng.directive:ngBind `ng-bind`} directive.
<pre>
@@ -68,7 +60,7 @@ api/ng.directive:ngBind `ng-bind`} directive.
</pre>
A directive is just a function which executes when the compiler encounters it in the DOM. See {@link
api/ng.$compileProvider#methods_directive directive API} for in-depth documentation on how
api/ng.$compileProvider#directive directive API} for in-depth documentation on how
to write directives.
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
@@ -78,21 +70,19 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
<file name="script.js">
angular.module('drag', []).
directive('draggable', function($document) {
var startX=0, startY=0, x = 0, y = 0;
return function(scope, element, attr) {
var startX = 0, startY = 0, x = 0, y = 0;
element.css({
position: 'relative',
border: '1px solid red',
backgroundColor: 'lightgrey',
cursor: 'pointer'
});
element.on('mousedown', function(event) {
// Prevent default dragging of selected content
event.preventDefault();
element.bind('mousedown', function(event) {
startX = event.screenX - x;
startY = event.screenY - y;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
$document.bind('mousemove', mousemove);
$document.bind('mouseup', mouseup);
});
function mousemove(event) {
@@ -117,261 +107,35 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
</example>
The presence of the `draggable` attribute on any element gives the element new behavior.
We extended the vocabulary of the browser in a way which is natural to anyone who is familiar with the principles of HTML.
The presence of the `draggable` attribute on any element gives the element new behavior. The beauty of
this approach is that we have taught the browser a new trick. We have extended the vocabulary of
what the browser understands in a way which is natural to anyone who is familiar with HTML
principles.
## Understanding View
# Understanding View
Most other templating systems consume a static string template and
There are many templating systems out there. Most of them consume a static string template and
combine it with data, resulting in a new string. The resulting text is then `innerHTML`ed into
an element.
<img src="img/One_Way_Data_Binding.png">
This means that any changes to the data need to be re-merged with the template and then
`innerHTML`ed into the DOM. Some of the issues with this approach are:
`innerHTML`ed into the DOM. Some of the issues with this approach are: reading user input and merging it with data,
clobbering user input by overwriting it, managing the whole update process, and lack of behavior
expressiveness.
1. reading user input and merging it with data
2. clobbering user input by overwriting it
3. managing the whole update process
4. lack of behavior expressiveness
Angular is different. The Angular compiler consumes the DOM, not string templates.
Angular is different. The Angular compiler consumes the DOM with directives, not string templates.
The result is a linking function, which when combined with a scope model results in a live view. The
view and scope model bindings are transparent. The developer does not need to make any special calls to update
the view. And because `innerHTML` is not used, you won't accidentally clobber user input.
view and scope model bindings are transparent. No action from the developer is needed to update
the view. And because no `innerHTML` is used there are no issues of clobbering user input.
Furthermore, Angular directives can contain not just text bindings, but behavioral constructs as
well.
<img src="img/Two_Way_Data_Binding.png">
The Angular approach produces a stable DOM. The DOM element instance bound to a model
The Angular approach produces a stable DOM. This means that the DOM element instance bound to a model
item instance does not change for the lifetime of the binding. This means that the code can get
hold of the elements and register event handlers and know that the reference will not be destroyed
by template data merge.
## How directives are compiled
It's important to note that Angular operates on DOM nodes rather than strings. Usually, you don't
notice this restriction because when a page loads, the web browser parses HTML into the DOM automatically.
However it's important to keep this in mind when calling `$compile` yourself, because passing it a string
will fail. Instead, use `angular.element` to convert a string to DOM before passing elements into
Angular's `$compile` service.
HTML compilation happens in three phases:
1. {@link api/ng.$compile `$compile`} traverses the DOM and matches directives.
If the compiler finds that an element matches a directive, then the directive is added to the list of
directives that match the DOM element. A single element may match multiple directives.
2. Once all directives matching a DOM element have been identified, the compiler sorts the directives
by their `priority`.
Each directive's `compile` functions are executed. Each `compile` function has a chance to
modify the DOM. Each `compile` function returns a `link` function. These functions are composed into
a "combined" link function, which invokes each directive's returned `link` function.
3. `$compile` links the template with the scope by calling the combined linking function from the previous step.
This in turn will call the linking function of the individual directives, registering listeners on the elements
and setting up {@link api/ng.$rootScope.Scope#methods_$watch `$watch`s} with the {@link api/ng.$rootScope.Scope `scope`}
as each directive is configured to do.
The result of this is a live binding between the scope and the DOM. So at this point, a change in
a model on the compiled scope will be reflected in the DOM.
Below is the corresponding code using the `$compile` service.
This should help give you an idea of what Angular does internally.
<pre>
var $compile = ...; // injected into your code
var scope = ...;
var html = '<div ng-bind="exp"></div>';
// Step 1: parse HTML into DOM element
var template = angular.element(html);
// Step 2: compile the template
var linkFn = $compile(template);
// Step 3: link the compiled template with the scope.
linkFn(scope);
</pre>
### The difference between Compile and Link
At this point you may wonder why the compile process has separate compile and link phases. The
short answer is that compile and link separation is needed any time a change in a model causes
a change in the **structure** of the DOM.
It's rare for directives to have a **compile function**, since most directives are concerned with
working with a specific DOM element instance rather than changing its overall structure.
Directives often have a **link function**. A link function allows the directive to register
listeners to the specific cloned DOM element instance as well as to copy content into the DOM
from the scope.
<div class="alert alert-success">
**Best Practice:** Any operation which can be shared among the instance of directives should be
moved to the compile function for performance reasons.
</div>
#### An Example of "Compile" Versus "Link"
To understand, let's look at a real-world example with `ngRepeat`:
<pre>
Hello {{user}}, you have these actions:
<ul>
<li ng-repeat="action in user.actions">
{{action.description}}
</li>
</ul>
</pre>
When the above example is compiled, the compiler visits every node and looks for directives.
`{{user}}` matches the {@link api/ng.$interpolate interpolation directive}
and `ng-repeat` matches the {@link api/ng.directive:ngRepeat `ngRepeat` directive}.
But {@link api/ng.directive:ngRepeat ngRepeat} has a dilemma.
It needs to be able to clone new `<li>` elements for every `action` in `user.actions`.
This initially seems trivial, but it becomes more complicated when you consider that `user.actions`
might have items added to it later. This means that it needs to save a clean copy of the `<li>`
element for cloning purposes.
As new `action`s are inserted, the template `<li>` element needs to be cloned and inserted into `ul`.
But cloning the `<li>` element is not enough. It also needs to compile the `<li>` so that its
directives, like `{{action.description}}`, evaluate against the right {@link api/ng.$rootScope.Scope scope}.
A naive approach to solving this problem would be to simply insert a copy of the `<li>` element and
then compile it.
The problem with this approach is that compiling on every `<li>` element that we clone would duplicate
a lot of the work. Specifically, we'd be traversing `<li>` each time before cloning it to find the
directives. This would cause the compilation process to be slower, in turn making applications
less responsive when inserting new nodes.
The solution is to break the compilation process into two phases:
the **compile phase** where all of the directives are identified and sorted by priority,
and a **linking phase** where any work which "links" a specific instance of the
{@link api/ng.$rootScope.Scope scope} and the specific instance of an `<li>` is performed.
<div class="alert alert-warning">
**Note:** *Link* means setting up listeners on the DOM and setting up `$watch` on the Scope to
keep the two in sync.
</div>
{@link api/ng.directive:ngRepeat `ngRepeat`} works by preventing the compilation process from
descending into the `<li>` element so it can make a clone of the original and handle inserting
and removing DOM nodes itself.
Instead the {@link api/ng.directive:ngRepeat `ngRepeat`} directive compiles `<li>` separately.
The result of the `<li>` element compilation is a linking function which contains all of the
directives contained in the `<li>` element, ready to be attached to a specific clone of the `<li>`
element.
At runtime the {@link api/ng.directive:ngRepeat `ngRepeat`} watches the expression and as items
are added to the array it clones the `<li>` element, creates a new
{@link api/ng.$rootScope.Scope scope} for the cloned `<li>` element and calls the link function
on the cloned `<li>`.
### Understanding How Scopes Work with Transcluded Directives
One of the most common use cases for directives is to create reusable components.
Below is a pseudo code showing how a simplified dialog component may work.
<pre>
<div>
<button ng-click="show=true">show</button>
<dialog title="Hello {{username}}."
visible="show"
on-cancel="show = false"
on-ok="show = false; doSomething()">
Body goes here: {{username}} is {{title}}.
</dialog>
</div>
</pre>
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
data bound to `username`, and it will also have a body which we would like to transclude
into the dialog.
Here is an example of what the template definition for the `dialog` widget may look like.
<pre>
<div ng-show="visible">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
<button ng-click="onOk()">Save changes</button>
<button ng-click="onCancel()">Close</button>
</div>
</div>
</pre>
This will not render properly, unless we do some scope magic.
The first issue we have to solve is that the dialog box template expects `title` to be defined.
But we would like the template's scope property `title` to be the result of interpolating the
`<dialog>` element's `title` attribute (i.e. `"Hello {{username}}"`. Furthermore, the buttons expect
the `onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
widget. To solve the mapping issue we use the `locals` to create local variables which the template
expects as follows:
<pre>
scope: {
title: '@', // the title uses the data-binding from the parent scope
onOk: '&', // create a delegate onOk function
onCancel: '&', // create a delegate onCancel function
visible: '=' // set up visible to accept data-binding
}
</pre>
Creating local properties on widget scope creates two problems:
1. isolation - if the user forgets to set `title` attribute of the dialog widget the dialog
template will bind to parent scope property. This is unpredictable and undesirable.
2. transclusion - the transcluded DOM can see the widget locals, which may overwrite the
properties which the transclusion needs for data-binding. In our example the `title`
property of the widget clobbers the `title` property of the transclusion.
To solve the issue of lack of isolation, the directive declares a new `isolated` scope. An
isolated scope does not prototypically inherit from the parent scope, and therefore we don't have
to worry about accidentally clobbering any properties.
However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
is a child of the original scope, before the widget created an isolated scope for its local
variables. This makes the transcluded and widget isolated scope siblings.
This may seem to be unexpected complexity, but it gives the widget user and developer the least
surprise.
Therefore the final directive definition looks something like this:
<pre>
transclude: true,
scope: {
title: '@', // the title uses the data-binding from the parent scope
onOk: '&', // create a delegate onOk function
onCancel: '&', // create a delegate onCancel function
visible: '=' // set up visible to accept data-binding
},
restrict: 'E',
replace: true
</pre>
+439 -356
View File
@@ -2,383 +2,466 @@
@name Conceptual Overview
@description
There are some concepts within Angular that you should understand before creating your first application.
This section touches all important parts of Angular really quickly using a simple example.
However, it won't explain all details.
For a more in-depth explanation, have a look at the {@link tutorial/ tutorial}.
# Overview
| Concept | Description |
|------------------|------------------------------------------|
|{@link concepts#template Template} | HTML with additional markup |
|{@link concepts#directive Directives} | extend HTML with custom attributes and elements |
|{@link concepts#model Model} | the data that is shown to the user and with which the user interacts |
|{@link concepts#scope Scope} | context where the model is stored so that controllers, directives and expressions can access it |
|{@link concepts#expression Expressions} | access variables and functions from the scope |
|{@link concepts#compiler Compiler} | parses the template and instantiates directives and expressions |
|{@link concepts#filter Filter} | formats the value of an expression for display to the user |
|{@link concepts#view View} | what the user sees (the DOM) |
|{@link concepts#databinding Data Binding} | sync data between the model and the view |
|{@link concepts#controller Controller} | the business logic behind views |
|{@link concepts#di Dependency Injection} | Creates and wires objects / functions |
|{@link concepts#injector Injector} | dependency injection container |
|{@link concepts#module Module} | configures the Injector |
|{@link concepts#service Service} | reusable business logic independent of views |
This document gives a quick overview of the main angular components and how they work together.
These are:
* {@link concepts#startup startup} - bring up hello world
* {@link concepts#runtime runtime} - overview of angular runtime
* {@link concepts#scope scope} - the glue between the view and the controller
* {@link concepts#controller controller} - application behavior
* {@link concepts#model model} - your application data
* {@link concepts#view view} - what the user sees
* {@link concepts#directives directives} - extend HTML vocabulary
* {@link concepts#filters filters} - format the data in user locale
* {@link concepts#injector injector} - assembles your application
* {@link concepts#module module} - configures the injector
* {@link concepts#angular_namespace `$`} - angular namespace
<a name="startup"></a>
# Startup
This is how we get the ball rolling (refer to the diagram and example below):
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
1. The browser loads the HTML and parses it into a DOM
2. The browser loads `angular.js` script
3. Angular waits for `DOMContentLoaded` event
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
{@link guide/directive directive}, which designates the application boundary
5. The {@link guide/module Module} specified in {@link
api/ng.directive:ngApp ng-app} (if any) is used to configure
the {@link api/AUTO.$injector $injector}
6. The {@link api/AUTO.$injector $injector} is used to create the {@link
api/ng.$compile $compile} service as well as {@link
api/ng.$rootScope $rootScope}
7. The {@link api/ng.$compile $compile} service is used to compile the DOM and link
it with {@link api/ng.$rootScope $rootScope}
8. The {@link api/ng.directive:ngInit ng-init} {@link
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
scope}
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
`Hello World!`
<div class="clear">
</div>
<example>
<file name="index.html">
<p ng-init=" name='World' ">Hello {{name}}!</p>
</file>
</example>
# A first example: Data binding
<a name="runtime"></a>
# Runtime
In the following we will build a form to calculate the costs of an invoice in different currencies.
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
Let's start with input fields for quantity and cost whose values are multiplied to produce the total of the invoice:
The diagram and the example below describe how Angular interacts with the browser's event loop.
1. The browser's event-loop waits for an event to arrive. An event is a user interactions, timer event,
or network event (response from a server).
2. The event's callback gets executed. This enters the JavaScript context. The callback can
modify the DOM structure.
3. Once the callback executes, the browser leaves the JavaScript context and
re-renders the view based on DOM changes.
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
splits the JavaScript into classical and Angular execution context. Only operations which are
applied in Angular execution context will benefit from Angular data-binding, exception handling,
property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in
mind that in most places (controllers, services) $apply has already been called for you by the
directive which is handling the event. An explicit call to $apply is needed only when
implementing custom event callbacks, or when working with a third-party library callbacks.
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
the work you wish to do in Angular execution context.
2. Angular executes the `stimulusFn()`, which typically modifies application state.
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
stabilizes, which means that the {@link api/ng.$rootScope.Scope#$evalAsync
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#$watch
$watch} list does not detect any changes.
4. The {@link api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue is used to
schedule work which needs to occur outside of current stack frame, but before the browser's
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
suffers from slowness and may cause view flickering since the browser renders the view after
each event.
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
which may have changed since last iteration. If a change is detected then the `$watch`
function is called which typically updates the DOM with the new value.
6. Once the Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
the execution leaves the Angular and JavaScript context. This is followed by the browser
re-rendering the DOM to reflect any changes.
Here is the explanation of how the `Hello wold` example achieves the data-binding effect when the
user enters text into the text field.
1. During the compilation phase:
1. the {@link api/ng.directive:ngModel ng-model} and {@link
api/ng.directive:input input} {@link guide/directive
directive} set up a `keydown` listener on the `<input>` control.
2. the {@link api/ng.$interpolate &#123;&#123;name&#125;&#125; } interpolation
sets up a {@link api/ng.$rootScope.Scope#$watch $watch} to be notified of
`name` changes.
2. During the runtime phase:
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
2. The {@link api/ng.directive:input input} directive
captures the change to the input's value and calls {@link
api/ng.$rootScope.Scope#$apply $apply}`("name = 'X';")` to update the
application model inside the Angular execution context.
3. Angular applies the `name = 'X';` to the model.
4. The {@link api/ng.$rootScope.Scope#$digest $digest} loop begins
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
on the `name` property and notifies the {@link api/ng.$interpolate
&#123;&#123;name&#125;&#125; } interpolation, which in turn updates the DOM.
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
the JavaScript execution context.
7. The browser re-renders the view with update text.
<div class="clear">
</div>
<example>
<file name="index.html">
<input ng-model="name">
<p>Hello {{name}}!</p>
</file>
</example>
<a name="scope"></a>
#Scope
The {@link guide/scope scope} is responsible for detecting changes to the model section and
provides the execution context for expressions. The scopes are nested in a hierarchical structure
which closely follow the DOM structure. (See individual directive documentation to see which
directives cause a creation of new scopes.)
The following example demonstrates how `name` {@link guide/expression expression} will evaluate
into different value depending on which scope it is evaluated in. The example is followed by
a diagram depicting the scope boundaries.
<div class="clear">
</div>
<div class="show-scope">
<example>
<file name="index.html">
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">{{name}}</li>
</ol>
</div>
</file>
<file name="script.js">
function GreetCtrl($scope) {
$scope.name = 'World';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
</file>
<file name="style.css">
.show-scope .doc-example-live.ng-scope,
.show-scope .doc-example-live .ng-scope {
border: 1px solid red;
margin: 3px;
}
</file>
</example>
</div>
<img class="center" src="img/guide/concepts-scope.png">
<a name="controller"></a>
# Controller
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
A controller is the code behind the view. Its job is to construct the model and publish it to the
view along with callback methods. The view is a projection of the scope onto the template (the
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
controller.
The separation of the controller and the view is important because:
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
for specifying application behavior. The controller should not contain any rendering
information (DOM references or HTML fragments).
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
specifying UI. The View should not contain any behavior.
* Since the controller is unaware of the view, there could be many views for the same
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
and testability.
<div class="clear">
</div>
<example>
<file name="index.html">
<div ng-controller="MyCtrl">
Hello {{name}}!
<button ng-click="action()">
OK
</button>
</div>
</file>
<file name="script.js">
function MyCtrl($scope) {
$scope.action = function() {
$scope.name = 'OK';
}
$scope.name = 'World';
}
</file>
</example>
<a name="model"></a>
# Model
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
The model is the data which is used merged with the template to produce the view. To be able to
render the model into the view, the model has to be able to be referenced from the scope. Unlike many
other frameworks Angular makes no restrictions or requirements on the model. There are no classes
to inherit from or special accessor methods for accessing or changing the model. The model can be
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
<div class="clear">
</div>
<a name="view"></a>
# View
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
The view is what the user sees. The view begins its life as a template, is merged with the
model and finally rendered into the browser DOM. Angular takes a very different approach to
rendering the view compared to most other templating systems.
* **Others** - Most templating systems begin as an HTML string with special templating markup.
Often the template markup breaks the HTML syntax which means that the template can not be
edited by an HTML editor. The template string is then parsed by the template engine, and
merged with the data. The result of the merge is an HTML string. The HTML string is then
written to the browser using the `.innerHTML`, which causes the browser to render the HTML.
When the model changes the whole process needs to be repeated. The granularity of the template
is the granularity of the DOM updates. The key here is that the templating system manipulates
strings.
* **Angular** - Angular is different, since its templating system works on DOM objects not on
strings. The template is still written in an HTML string, but it is HTML (not HTML with
template sprinkled in.) The browser parses the HTML into the DOM, and the DOM becomes the input to
the template engine known as the {@link api/ng.$compile compiler}. The compiler
looks for {@link guide/directive directives} which in turn set up {@link
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
continuously updating view which does not need template model re-merging. Your model becomes
the single source-of-truth for your view.
<div class="clear">
</div>
<example>
<file name="index.html">
<div ng-init="qty=1;cost=2">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="qty" required >
</div>
<div>
Costs: <input type="number" ng-model="cost" required >
</div>
<div>
<b>Total:</b> {{qty * cost | currency}}
</div>
</div>
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
<input ng-model="list" ng-list> <br>
<input ng-model="list" ng-list> <br>
<pre>list={{list}}</pre> <br>
<ol>
<li ng-repeat="item in list">
{{item}}
</li>
</ol>
</div>
</file>
</example>
Try out the Live Preview above, and then let's walk through the example and describe what's going on.
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding1.png">
<a name="directives"></a>
# Directives
This looks like normal HTML, with some new markup. In Angular, a file like this is called a
<a name="template">"{@link templates template}"</a>. When Angular starts your application, it parses and
processes this new markup from the template using the so called <a name="compiler">"{@link compiler compiler}"</a>.
The loaded, transformed and rendered DOM is then called the <a name="view">"view"</a>.
A directive is a behavior or DOM transformation which is triggered by the presence of a custom attribute,
element name, or a class name. A directive allows you to extend the HTML vocabulary in a
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
in HTML.
The first kind of new markup are the so called <a name="directive">"{@link directive directives}"</a>.
They apply special behavior to attributes or elements in the HTML. In the example above we use the
{@link api/ng.directive:ngApp `ng-app`} attribute, which is linked to a directive that automatically
initializes our application. Angular also defines a directive for the {@link api/ng.directive:input `input`}
element that adds extra behavior to the element. E.g. it is able to automatically validate that the entered
text is non empty by evaluating the `required` attribute.
The {@link api/ng.directive:ngModel `ng-model`} directive stores/updates
the value of the input field into/from a variable and shows the validation state of the input field by
adding css classes. In the example we use these css classes to mark an empty input field with a red border.
<div class="alert alert-info">
**Custom directives to access the DOM**: In Angular, the only place where an application touches the DOM is
within directives. This is good as artifacts that access the DOM are hard to test.
If you need to access the DOM directly you should write a custom directive for this. The
{@link directive directives guide} explains how to do this.
</div>
The second kind of new markup are the double curly braces `{{ expression | filter }}`:
When the compiler encounters this markup, it will replace it with the evaluated value of the markup.
An <a name="expression">"{@link expression expression}"</a> in a template is a JavaScript-like code snippet that allows
to read and write variables. Note that those variables are not global variables.
Just like variables in a JavaScript function live in a scope,
Angular provides a <a name="scope">"{@link scope scope}"</a> for the variables accessible to expressions.
The values that are stored in variables on the scope are referred to as the <a name="model">"model"</a>
in the rest of the documentation.
Applied to the example above, the markup directs Angular to "take the data we got from the input widgets
and multiply them together".
The example above also contains a <a name="filter">"{@link filter filter}"</a>.
A filter formats the value of an expression for display to the user.
In the example above, the filter {@link api/ng.filter:currency `currency`} formats a number
into an output that looks like money.
The important thing in the example is that angular provides _live_ bindings:
Whenever the input values change, the value of the expressions are automatically
recalculated and the DOM is updated with their values.
The concept behind this is <a name="databinding">"{@link databinding two-way data binding}"</a>.
# Adding UI logic: Controllers
Let's add some more logic to the example that allows us to enter and calculate the costs in
different currencies and also pay the invoice.
<example module="invoice1">
<file name="invoice1.js">
angular.module('invoice1', [])
.controller('InvoiceController', function() {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = ['USD', 'EUR', 'CNY'];
this.usdToForeignRates = {
USD: 1,
EUR: 0.74,
CNY: 6.09
};
this.total = function total(outCurr) {
return this.convertCurrency(this.qty * this.cost, this.inCurr, outCurr);
};
this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
return amount * this.usdToForeignRates[outCurr] * 1 / this.usdToForeignRates[inCurr];
};
this.pay = function pay() {
window.alert("Thanks!");
};
});
</file>
<file name="index.html">
<div ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
</file>
</example>
What changed?
First, there is a new JavaScript file that contains a so called <a name="controller">"{@link controller controller}"</a>.
More exactly, the file contains a constructor function that creates the actual controller instance.
The purpose of controllers is to expose variables and functionality to expressions and directives.
Besides the new file that contains the controller code we also added a
{@link api/ng.directive:ngController `ng-controller`} directive to the HTML.
This directive tells angular that the new `InvoiceController` is responsible for the element with the directive
and all of the element's children.
The syntax `InvoiceController as invoice` tells Angular to instantiate the controller
and save it in the variable `invoice` in the current scope.
We also changed all expressions in the page to read and write variables within that
controller instance by prefixing them with `invoice.` . The possible currencies are defined in the controller
and added to the template using {@link api/ng.directive:ngRepeat `ng-repeat`}.
As the controller contains a `total` function
we are also able to bind the result of that function to the DOM using `{{ invoice.total(...) }}`.
Again, this binding is live, i.e. the DOM will be automatically updated
whenever the result of the function changes.
The button to pay the invoice uses the directive {@link api/ng.directive:ngClick `ngClick`}. This will evaluate the
corresponding expression whenever the button is clicked.
In the new JavaScript file we are also creating a {@link concepts#module module}
at which we register the controller. We will talk about modules in the next section.
The following graphic shows how everything works together after we introduced the controller:
<img style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding2.png">
# View independent business logic: Services
Right now, the `InvoiceController` contains all logic of our example. When the application grows it
is a good practise to move view independent logic from the controller into a so called
<a name="service">"{@link dev_guide.services service}"</a>, so it can be reused by other parts
of the application as well. Later on, we could also change that service to load the exchange rates
from the web, e.g. by calling the Yahoo Finance API, without changing the controller.
Let's refactor our example and move the currency conversion into a service in another file:
<example module="invoice2">
<file name="finance2.js">
angular.module('finance2', [])
.factory('currencyConverter', function() {
var currencies = ['USD', 'EUR', 'CNY'],
usdToForeignRates = {
USD: 1,
EUR: 0.74,
CNY: 6.09
};
return {
currencies: currencies,
convert: convert
};
function convert(amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
}
});
</file>
<file name="invoice2.js">
angular.module('invoice2', ['finance2'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
</file>
<file name="index.html">
<div ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
</file>
</example>
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-service.png">
What changed?
We moved the `convertCurrency` function and the definition of the existing currencies
into the new file `finance.js`. But how does the controller
get a hold of the now separated function?
This is where <a name="di">"{@link di Dependency Injection}"</a> comes into play.
Dependency Injection (DI) is a software design pattern that
deals with how objects and functions get created and how they get a hold of their dependencies.
Everything within Angular (directives, filters, controllers,
services, ...) is created and wired using dependency injection. Within Angular,
the DI container is called the <a name="injector">"{@link di injector}"</a>.
To use DI, there needs to be a place where all the things that should work together are registered.
In Angular, this is the purpose of the so called <a name="module">"{@link module modules}"</a>.
When Angular starts, it will use the configuration of the module with the name defined by the `ng-app` directive,
including the configuration of all modules that this module depends on.
In the example above:
The template contains the directive `ng-app="invoice"`. This tells Angular
to use the `invoice` module as the main module for the application.
The code snippet `angular.module('invoice', ['finance'])` specifies that the `invoice` module depends on the
`finance` module. By this, Angular uses the `InvoiceController` as well as the `currencyConverter` service.
Now that Angular knows of all the parts of the application, it needs to create them.
In the previous section we saw that controllers are created using a factory function.
For services there are multiple ways to define their factory
(see the {@link dev_guide.services service guide}).
In the example above, we are using a function that returns the `currencyConverter` function as the factory
for the service.
Back to the initial question: How does the `InvoiceController` get a reference to the `currencyConverter` function?
In Angular, this is done by simply defining arguments on the constructor function. With this, the injector
is able to create the objects in the right order and pass the previously created objects into the
factories of the objects that depend on them.
In our example, the `InvoiceController` has an argument named `currencyConverter`. By this, Angular knows about the
dependency between the controller and the service and calls the controller with the service instance as argument.
The last thing that changed in the example between the previous section and this section is that we
now pass an array to the `module.controller` function, instead of a plain function. The array first
contains the names of the service dependencies that the controller needs. The last entry
in the array is the controller constructor function.
Angular uses this array syntax to define the dependencies so that the DI also works after minifying
the code, which will most probably rename the argument name of the controller constructor function
to something shorter like `a`.
# Accessing the backend
Let's finish our example by fetching the exchange rates from the Yahoo Finance API.
The following example shows how this is done with Angular:
<example module="invoice3">
<file name="invoice3.js">
angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
</file>
<file name="finance3.js">
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'http://query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK',
currencies = ['USD', 'EUR', 'CNY'],
usdToForeignRates = {};
refresh();
return {
currencies: currencies,
convert: convert,
refresh: refresh
};
function convert(amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
}
function refresh() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
<example module="directive">
<file name="script.js">
angular.module('directive', []).directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
// view -> model
elm.bind('blur', function() {
scope.$apply(function() {
ctrl.$setViewValue(elm.html());
});
usdToForeignRates = newUsdToForeignRates;
});
// model -> view
ctrl.$render = function(value) {
elm.html(value);
};
// load init value from DOM
ctrl.$setViewValue(elm.html());
}
}]);
};
});
</file>
<file name="index.html">
<div ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
<div contentEditable="true" ng-model="content">Edit Me</div>
<pre>model = {{content}}</pre>
</file>
<file name="style.css">
div[contentEditable] {
cursor: pointer;
background-color: #D0D0D0;
margin-bottom: 1em;
padding: 1em;
}
</file>
</example>
What changed?
Our `currencyConverter` service of the `finance` module now uses the
{@link api/ng.$http $http} service, a builtin service provided by Angular
for accessing the backend. It is a wrapper around [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
and [JSONP](http://en.wikipedia.org/wiki/JSONP) transports. Details can be found in the api docs of that service.
<a name="filters"></a>
# Filters
{@link api/ng.$filter Filters} perform data transformation. Typically
they are used in conjunction with the locale to format the data in locale specific output.
They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
Number formatting: {{ 1234567890 | number }} <br>
array filtering <input ng-model="predicate">
{{ list | filter:predicate | json }}
</div>
</file>
</example>
<a name="module"></a>
<a name="injector"></a>
# Modules and the Injector
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
The {@link api/AUTO.$injector injector} is a service locator. There is a single
{@link api/AUTO.$injector injector} per Angular {@link
api/ng.directive:ngApp application}. The {@link
api/AUTO.$injector injector} provides a way to look up an object instance by its
name. The injector keeps an internal cache of all objects so that repeated calls to get the same
object name result in the same instance. If the object does not exist, then the {@link
api/AUTO.$injector injector} asks the instance factory to create a new instance.
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
as a {@link api/AUTO.$provide provider}.
<div class='clear'></div>
<pre>
// Create a module
var myModule = angular.module('myModule', [])
// Configure the injector
myModule.factory('serviceA', function() {
return {
// instead of {}, put your object creation here
};
});
// create an injector and configure it from 'myModule'
var $injector = angular.injector(['myModule']);
// retrieve an object from the injector by name
var serviceA = $injector.get('serviceA');
// always true because of instance cache
$injector.get('serviceA') === $injector.get('serviceA');
</pre>
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
used to {@link api/AUTO.$injector#invoke call} methods and {@link
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
allows the methods and types to ask for their dependencies instead of having to look for them.
<pre>
// You write functions such as this one.
function doSomething(serviceA, serviceB) {
// do something here.
}
// Angular provides the injector for your application
var $injector = ...;
///////////////////////////////////////////////
// the old-school way of getting dependencies.
var serviceA = $injector.get('serviceA');
var serviceB = $injector.get('serviceB');
// now call the function
doSomething(serviceA, serviceB);
///////////////////////////////////////////////
// the cool way of getting dependencies.
// the $injector will supply the arguments to the function automatically
$injector.invoke(doSomething); // This is how the framework calls your functions
</pre>
Notice that the only thing you needed to write was the function, and list the dependencies in the
function arguments. When angular calls the function, it will use the {@link
api/AUTO.$injector#invoke call} which will automatically fill the function
arguments.
Examine the `ClockCtrl` bellow, and notice how it lists the dependencies in the constructor. When the
{@link api/ng.directive:ngController ng-controller} instantiates
the controller it automatically provides the dependencies. There is no need to create
dependencies, look for dependencies, or even get a reference to the injector.
<example module="timeExampleModule">
<file name="index.html">
<div ng-controller="ClockCtrl">
Current time is: {{ time.now }}
</div>
</file>
<file name="script.js">
angular.module('timeExampleModule', []).
// Declare new object called time,
// which will be available for injection
factory('time', function($timeout) {
var time = {};
(function tick() {
time.now = new Date().toString();
$timeout(tick, 1000);
})();
return time;
});
// Notice that you can simply ask for time
// and it will be provided. No need to look for it.
function ClockCtrl($scope, time) {
$scope.time = time;
}
</file>
</example>
<a name="angular_namespace"></a>
# Angular Namespace
To prevent accidental name collision, Angular prefixes names of objects which could potentially
collide with `$`. Please do not use the `$` prefix in your code as it may accidentally collide
with Angular code.
-340
View File
@@ -1,340 +0,0 @@
@ngdoc overview
@name Controllers
@description
# Understanding Controllers
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
{@link scope Angular Scope}.
When a Controller is attached to the DOM via the {@link api/ng.directive:ngController ng-controller}
directive, Angular will instantiate a new Controller object, using the specified Controller's
**constructor function**. A new **child scope** will be available as an injectable parameter to the
Controller's constructor function as `$scope`.
Use Controllers to:
- Set up the initial state of the `$scope` object.
- Add behavior to the `$scope` object.
# Setting up the initial state of a `$scope` object
Typically, when you create an application you need to set up the initial state for the Angular
`$scope`. You set up the initial state of a scope by attaching properties to the `$scope` object.
The properties contain the **view model** (the model that will be presented by the view). All the
`$scope` properties will be available to the template at the point in the DOM where the Controller
is registered.
The following example shows a very simple constructor function for a Controller, `GreetingCtrl`,
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
<pre>
function GreetingCtrl($scope) {
$scope.greeting = 'Hola!';
}
</pre>
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
template:
<pre>
<div ng-controller="GreetingCtrl">
{{ greeting }}
</div>
</pre>
**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:
<pre>
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
</pre>
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 http://docs.angularjs.org/guide/di Dependency Injection} for more information.
# Adding Behavior to a Scope Object
In order to react to events or execute computation in the view we must provide behavior to the
scope. We add behavior to the scope by attaching methods to the `$scope` object. These methods are
then available to be called from the template/view.
The following example uses a Controller to add a method to the scope, which doubles a number:
<pre>
var myApp = angular.module('myApp',[]);
myApp.controller('DoubleCtrl', ['$scope', function($scope) {
$scope.double = function(value) { return value * 2; };
}]);
</pre>
Once the Controller has been attached to the DOM, the `double` method can be invoked in an Angular
expression in the template:
<pre>
<div ng-controller="DoubleCtrl">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
</pre>
As discussed in the {@link concepts Concepts} section of this guide, any
objects (or primitives) assigned to the scope become model properties. Any methods assigned to
the scope are available in the template/view, and can be invoked via angular expressions
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
# Using Controllers Correctly
In general, a Controller shouldn't try to do too much. It should contain only the business logic
needed for a single view.
The most common way to keep Controllers slim is by encapsulating work that doesn't belong to
controllers into services and then using these services in Controllers via dependency injection.
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
Services} sections of this guide.
Do not use Controllers for:
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
manipulation (the presentation logic of an application) is well known for being hard to test.
Putting any presentation logic into Controllers significantly affects testability of the business
logic. Angular offers {@link databinding databinding} for automatic DOM manipulation. If
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
{@link guide/directive directives}.
- Input formatting — Use {@link forms angular form controls} instead.
- Output filtering — Use {@link filter angular filters} instead.
- Sharing stateless or stateful code across Controllers — Use {@link dev_guide.services angular
services} instead.
- Managing the life-cycle of other components (for example, to create service instances).
# Associating Controllers with Angular Scope Objects
You can associate Controllers with scope objects implicitly via the {@link api/ng.directive:ngController ngController
directive} or {@link api/ngRoute.$route $route service}.
## Simple Spicy Controller Example
To illustrate further how Controller components work in Angular, let's create a little app with the
following components:
- A {@link templates template} with two buttons and a simple message
- A model consisting of a string named `spice`
- A Controller with two functions that set the value of `spice`
The message in our template contains a binding to the `spice` model, which by default is set to the
string "very". Depending on which button is clicked, the `spice` model is set to `chili` or
`jalapeño`, and the message is automatically updated by data-binding.
<doc:example module="spicyApp1">
<doc:source>
<div ng-app="spicyApp1" ng-controller="SpicyCtrl">
<button ng-click="chiliSpicy()">Chili</button>
<button ng-click="jalapenoSpicy()">Jalapeño</button>
<p>The food is {{spice}} spicy!</p>
</div>
<script>
var myApp = angular.module('spicyApp1', []);
myApp.controller('SpicyCtrl', ['$scope', function($scope){
$scope.spice = 'very';
$scope.chiliSpicy = function() {
$scope.spice = 'chili';
};
$scope.jalapenoSpicy = function() {
$scope.spice = 'jalapeño';
};
}]);
</script>
</doc:source>
</doc:example>
Things to notice in the example above:
- The `ng-controller` directive is used to (implicitly) create a scope for our template, and the
scope is augmented (managed) by the `SpicyCtrl` Controller.
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
starts with capital letter and ends with "Ctrl" or "Controller".
- Assigning a property to `$scope` creates or updates the model.
- Controller methods can be created through direct assignment to scope (see the `chiliSpicy` method)
- The Controller methods and properties are available in the template (for the `<div>` element and
and its children).
## Spicy Arguments Example
Controller methods can also take arguments, as demonstrated in the following variation of the
previous example.
<doc:example module="spicyApp2">
<doc:source>
<div ng-app="spicyApp2" ng-controller="SpicyCtrl">
<input ng-model="customSpice">
<button ng-click="spicy('chili')">Chili</button>
<button ng-click="spicy(customSpice)">Custom spice</button>
<p>The food is {{spice}} spicy!</p>
</div>
<script>
var myApp = angular.module('spicyApp2', []);
myApp.controller('SpicyCtrl', ['$scope', function($scope){
$scope.customSpice = "wasabi";
$scope.spice = 'very';
$scope.spicy = function(spice){
$scope.spice = spice;
};
}]);
</script>
</doc:source>
</doc:example>
Notice that the `SpicyCtrl` Controller now defines just one method called `spicy`, which takes one
argument called `spice`. The template then refers to this Controller method and passes in a string
constant `'chili'` in the binding for the first button and a model property `customSpice` (bound to an
input box) in the second button.
## Scope Inheritance Example
It is common to attach Controllers at different levels of the DOM hierarchy. Since the
{@link api/ng.directive:ngController ng-controller} directive creates a new child scope, we get a
hierarchy of scopes that inherit from each other. The `$scope` that each Controller receives will
have access to properties and methods defined by Controllers higher up the hierarchy.
See {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes Understanding Scopes} for
more information about scope inheritance.
<doc:example module="scopeInheritance">
<doc:source>
<div ng-app="scopeInheritance" class="spicy">
<div ng-controller="MainCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="GrandChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
</div>
</div>
</div>
</div>
<style>
div.spicy div {
padding: 10px;
border: solid 2px blue;
}
</style>
<script>
var myApp = angular.module('scopeInheritance', []);
myApp.controller('MainCtrl', ['$scope', function($scope){
$scope.timeOfDay = 'morning';
$scope.name = 'Nikki';
}]);
myApp.controller('ChildCtrl', ['$scope', function($scope){
$scope.name = 'Mattie';
}]);
myApp.controller('GrandChildCtrl', ['$scope', function($scope){
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbreak Baby';
}]);
</script>
</doc:source>
</doc:example>
Notice how we nested three `ng-controller` directives in our template. This will result in four
scopes being created for our view:
- The root scope
- The `MainCtrl` scope, which contains `timeOfDay` and `name` properties
- The `ChildCtrl` scope, which inherits the `timeOfDay` property but overrides (hides) the `name`
property from the previous
- The `GrandChildCtrl` scope, which overrides (hides) both the `timeOfDay` property defined in `MainCtrl`
and the `name` property defined in `ChildCtrl`
Inheritance works with methods in the same way as it does with properties. So in our previous
examples, all of the properties could be replaced with methods that return string values.
## Testing Controllers
Although there are many ways to test a Controller, one of the best conventions, shown below,
involves injecting the {@link api/ng.$rootScope $rootScope} and {@link api/ng.$controller $controller}:
**Controller Definition:**
<pre>
var myApp = angular.module('myApp',[]);
myApp.controller('MyController', function($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
$scope.spice = "habanero";
});
</pre>
**Controller Test:**
<pre>
describe('myController function', function() {
describe('myController', function() {
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
$controller('MyController', {$scope: $scope});
}));
it('should create "spices" model with 3 spices', function() {
expect($scope.spices.length).toBe(3);
});
it('should set the default value of spice', function() {
expect($scope.spice).toBe('habanero');
});
});
});
</pre>
If you need to test a nested Controller you need to create the same scope hierarchy
in your test that exists in the DOM:
<pre>
describe('state', function() {
var mainScope, childScope, grandChildScope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
$controller('MainCtrl', {$scope: mainScope});
childScope = mainScope.$new();
$controller('ChildCtrl', {$scope: childScope});
grandChildScope = childScope.$new();
$controller('GrandChildCtrl', {$scope: grandChildScope});
}));
it('should have over and selected', function() {
expect(mainScope.timeOfDay).toBe('morning');
expect(mainScope.name).toBe('Nikki');
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(grandChildScope.timeOfDay).toBe('evening');
expect(grandChildScope.name).toBe('Gingerbreak Baby');
});
});
</pre>
+14 -148
View File
@@ -3,10 +3,6 @@
@name Developer Guide: E2E Testing
@description
**If you're starting a new Angular project, you may want to look into
using {@link https://github.com/angular/protractor Protractor}, as it is going to
replace the current method of E2E Testing in the near future.**
As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to
verify the correctness of new features, catch bugs and notice regressions.
@@ -41,15 +37,10 @@ it('should filter results', function() {
});
});
</pre>
Note that
[`input('user')`](https://github.com/angular/angular.js/blob/master/docs/content/guide/dev_guide.e2e-testing.ngdoc#L119)
finds the `<input>` element with `ng-model="user"` not `name="user"`.
This scenario describes the requirements of a Buzz Client, specifically, that it should be able to
filter the stream of the user. It starts by entering a value in the input field with ng-model="user", clicking
filter the stream of the user. It starts by entering a value in the 'user' input field, clicking
the only button on the page, and then it verifies that there are 10 items listed. It then enters
'Bees' in the input field with ng-model='filterText' and verifies that the list is reduced to a single item.
'Bees' in the 'filterText' input field and verifies that the list is reduced to a single item.
The API section below lists the available commands and expectations for the Runner.
@@ -106,8 +97,7 @@ the test frame.
Asserts the value of the given `future` satisfies the `matcher`. All API statements return a
`future` object, which get a `value` assigned after they are executed. Matchers are defined using
`angular.scenario.matcher`, and they use the value of futures to run the expectation. For example:
`expect(browser().location().href()).toEqual('http://www.google.com')`. Available matchers
are presented further down this document.
`expect(browser().location().href()).toEqual('http://www.google.com')`
## expect(future).not().{matcher}
Asserts the value of the given `future` satisfies the negation of the `matcher`.
@@ -119,16 +109,16 @@ Scopes the next DSL element selection.
Returns the value of the first binding matching the given `name`.
## input(name).enter(value)
Enters the given `value` in the text field with the corresponding ng-model `name`.
Enters the given `value` in the text field with the given `name`.
## input(name).check()
Checks/unchecks the checkbox with the corresponding ng-model `name`.
Checks/unchecks the checkbox with the given `name`.
## input(name).select(value)
Selects the given `value` in the radio button with the corresponding ng-model `name`.
Selects the given `value` in the radio button with the given `name`.
## input(name).val()
Returns the current value of an input field with the corresponding ng-model `name`.
Returns the current value of an input field with the given `name`.
## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
@@ -143,10 +133,10 @@ Returns an array with the values in the column with the given `binding` in the r
the given jQuery `selector`. The `label` is used for test output.
## select(name).option(value)
Picks the option with the given `value` on the select with the given ng-model `name`.
Picks the option with the given `value` on the select with the given `name`.
## select(name).options(value1, value2...)
Picks the options with the given `values` on the multi select with the given ng-model `name`.
## select(name).option(value1, value2...)
Picks the options with the given `values` on the multi select with the given `name`.
## element(selector, label).count()
Returns the number of elements that match the given jQuery `selector`. The `label` is used for test
@@ -182,131 +172,7 @@ Executes the `method` passing in `key` and `value` on the element matching the g
`selector`, where `method` can be any of the following jQuery methods: `attr`, `prop`, `css`. The
`label` is used for test output.
# Matchers
Matchers are used in combination with the `expect(...)` function as described above and can
be negated with `not()`. For instance: `expect(element('h1').text()).not().toEqual('Error')`.
Source: {@link https://github.com/angular/angular.js/blob/master/src/ngScenario/matchers.js}
<pre>
// value and Object comparison following the rules of angular.equals().
expect(value).toEqual(value)
// a simpler value comparison using ===
expect(value).toBe(value)
// checks that the value is defined by checking its type.
expect(value).toBeDefined()
// the following two matchers are using JavaScript's standard truthiness rules
expect(value).toBeTruthy()
expect(value).toBeFalsy()
// verify that the value matches the given regular expression. The regular
// expression may be passed in form of a string or a regular expression
// object.
expect(value).toMatch(expectedRegExp)
// a check for null using ===
expect(value).toBeNull()
// Array.indexOf(...) is used internally to check whether the element is
// contained within the array.
expect(value).toContain(expected)
// number comparison using < and >
expect(value).toBeLessThan(expected)
expect(value).toBeGreaterThan(expected)
</pre>
# Example
See the {@link https://github.com/angular/angular-seed angular-seed} project for more examples.
## Conditional actions with element(...).query(fn)
E2E testing with angular scenario is highly asynchronous and hides a lot of complexity by
queueing actions and expectations that can handle futures. From time to time, you might need
conditional assertions or element selection. Even though you should generally try to avoid this
(as it is can be sign for unstable tests), you can add conditional behavior with
`element(...).query(fn)`. The following code listing shows how this function can be used to delete
added entries (where an entry is some domain object) using the application's web interface.
Imagine the application to be structured into two views:
1. *Overview view* which lists all the added entries in a table and
2. a *detail view* which shows the entries' details and contains a delete button. When clicking the
delete button, the user is redirected back to the *overview page*.
<pre>
beforeEach(function () {
var deleteEntry = function () {
browser().navigateTo('/entries');
// we need to select the <tbody> element as it might be the case that there
// are no entries (and therefore no rows). When the selector does not
// result in a match, the test would be marked as a failure.
element('table tbody').query(function (tbody, done) {
// ngScenario gives us a jQuery lite wrapped element. We call the
// `children()` function to retrieve the table body's rows
var children = tbody.children();
if (children.length > 0) {
// if there is at least one entry in the table, click on the link to
// the entry's detail view
element('table tbody a').click();
// and, after a route change, click the delete button
element('.btn-danger').click();
}
// if there is more than one entry shown in the table, queue another
// delete action.
if (children.length > 1) {
deleteEntry();
}
// remember to call `done()` so that ngScenario can continue
// test execution.
done();
});
};
// start deleting entries
deleteEntry();
});
</pre>
In order to understand what is happening, we should emphasize that ngScenario calls are not
immediately executed, but queued (in ngScenario terms, we would be talking about adding
future actions). If we had only one entry in our table, then the following future actions
would be queued:
<pre>
// delete entry 1
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
</pre>
For two entries, ngScenario would have to work on the following queue:
<pre>
// delete entry 1
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
// delete entry 2
// indented to represent "recursion depth"
browser().navigateTo('/entries');
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
</pre>
# Caveats
ngScenario does not work with apps that manually bootstrap using angular.bootstrap. You must use the ng-app directive.
JavaScript is a dynamically typed language which comes with great power of expression, but it also
come with almost no-help from the compiler. For this reason we feel very strongly that any code
written in JavaScript needs to come with a strong set of tests. We have built many features into
angular which makes testing your angular applications easy. So there is no excuse for not testing.
+24
View File
@@ -0,0 +1,24 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular
@description
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
first appeared, Angular incorporates the basic principles behind the original {@link
http://en.wikipedia.org/wiki/Modelviewcontroller MVC} software design pattern into its way of
building client-side web applications.
The MVC pattern summarized:
* Separate applications into distinct presentation, data, and logic components
* Encourage loose coupling between these components
Along with {@link dev_guide.services services} and {@link di dependency injection}, MVC
makes angular applications better structured, easier to maintain and more testable.
The following topics explain how angular incorporates the MVC pattern into the angular way of
developing web applications:
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
@@ -0,0 +1,293 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
@description
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of
angular {@link scope Scope}, excluding the root scope. When you or Angular create a new
child scope object via the {@link api/ng.$rootScope.Scope#$new scope.$new} API , there is an
option to pass in a controller as a method argument. This will tell Angular to associate the
controller with the new scope and to augment its behavior.
Use controllers to:
- Set up the initial state of a scope object.
- Add behavior to the scope object.
# Setting up the initial state of a scope object
Typically, when you create an application you need to set up an initial state for an Angular scope.
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
to a new Angular scope object, which sets up an initial scope state. This means that Angular never
creates instances of the controller type (by invoking the `new` operator on the controller
constructor). Constructors are always applied to an existing scope object.
You set up the initial state of a scope by creating model properties. For example:
function GreetingCtrl($scope) {
$scope.greeting = 'Hola!';
}
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
**NOTE**: Many of the examples in the documentation show the creation of functions
in the global scope. This is only for demonstration purposes - in a real
application you should use the `.controller` method of your Angular module for
your application as follows:
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingCtrl', ['$scope', function(scope) {
scope.greeting = 'Hola!';
}]);
Note also that we use the array notation to explicitly specify the dependency
of the controller on the `$scope` service provided by Angular.
# Adding Behavior to a Scope Object
Behavior on an Angular scope object is in the form of scope method properties available to the
template/view. This behavior interacts with and modifies the application model.
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
the scope are available in the template/view, and can be invoked via angular expressions
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
# Using Controllers Correctly
In general, a controller shouldn't try to do too much. It should contain only the business logic
needed for a single view.
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
controllers into services and then using these services in controllers via dependency injection.
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
Services} sections of this guide.
Do not use controllers for:
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
manipulation—the presentation logic of an application—is well known for being hard to test.
Putting any presentation logic into controllers significantly affects testability of the business
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
{@link guide/directive directives}.
- Input formatting — Use {@link forms angular form controls} instead.
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
- To run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
services} instead.
- To instantiate or manage the life-cycle of other components (for example, to create service
instances).
# Associating Controllers with Angular Scope Objects
You can associate controllers with scope objects explicitly via the {@link api/ng.$rootScope.Scope#$new
scope.$new} api or implicitly via the {@link api/ng.directive:ngController ngController
directive} or {@link api/ng.$route $route service}.
## Controller Constructor and Methods Example
To illustrate how the controller component works in angular, let's create a little app with the
following components:
- A {@link dev_guide.templates template} with two buttons and a simple message
- A model consisting of a string named `spice`
- A controller with two functions that set the value of `spice`
The message in our template contains a binding to the `spice` model, which by default is set to the
string "very". Depending on which button is clicked, the `spice` model is set to `chili` or
`jalapeño`, and the message is automatically updated by data-binding.
## A Spicy Controller Example
<pre>
<body ng-controller="SpicyCtrl">
<button ng-click="chiliSpicy()">Chili</button>
<button ng-click="jalapenoSpicy()">Jalapeño</button>
<p>The food is {{spice}} spicy!</p>
</body>
function SpicyCtrl($scope) {
$scope.spice = 'very';
$scope.chiliSpicy = function() {
$scope.spice = 'chili';
}
$scope.jalapenoSpicy = function() {
$scope.spice = 'jalapeño';
}
}
</pre>
Things to notice in the example above:
- The `ngController` directive is used to (implicitly) create a scope for our template, and the
scope is augmented (managed) by the `SpicyCtrl` controller.
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
starts with capital letter and ends with "Ctrl" or "Controller".
- Assigning a property to `$scope` creates or updates the model.
- Controller methods can be created through direct assignment to scope (the `chiliSpicy` method)
- Both controller methods are available in the template (for the `body` element and and its
children).
- NB: Previous versions of Angular (pre 1.0 RC) allowed you to use `this` interchangeably with
the $scope method, but this is no longer the case. Inside of methods defined on the scope
`this` and $scope are interchangeable (angular sets `this` to $scope), but not otherwise
inside your controller constructor.
- NB: Previous versions of Angular (pre 1.0 RC) added prototype methods into the scope
automatically, but this is no longer the case; all methods need to be added manually to
the scope.
Controller methods can also take arguments, as demonstrated in the following variation of the
previous example.
## Controller Method Arguments Example
<pre>
<body ng-controller="SpicyCtrl">
<input ng-model="customSpice" value="wasabi">
<button ng-click="spicy('chili')">Chili</button>
<button ng-click="spicy(customSpice)">Custom spice</button>
<p>The food is {{spice}} spicy!</p>
</body>
function SpicyCtrl($scope) {
$scope.spice = 'very';
$scope.spicy = function(spice) {
$scope.spice = spice;
}
}
</pre>
Notice that the `SpicyCtrl` controller now defines just one method called `spicy`, which takes one
argument called `spice`. The template then refers to this controller method and passes in a string
constant `'chili'` in the binding for the first button and a model property `spice` (bound to an
input box) in the second button.
## Controller Inheritance Example
Controller inheritance in Angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
have a look at an example:
<pre>
<body ng-controller="MainCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
</div>
</body>
function MainCtrl($scope) {
$scope.timeOfDay = 'morning';
$scope.name = 'Nikki';
}
function ChildCtrl($scope) {
$scope.name = 'Mattie';
}
function BabyCtrl($scope) {
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbreak Baby';
}
</pre>
Notice how we nested three `ngController` directives in our template. This template construct will
result in 4 scopes being created for our view:
- The root scope
- The `MainCtrl` scope, which contains `timeOfDay` and `name` models
- The `ChildCtrl` scope, which shadows the `name` model from the previous scope and inherits the
`timeOfDay` model
- The `BabyCtrl` scope, which shadows both the `timeOfDay` model defined in `MainCtrl` and `name`
model defined in the ChildCtrl
Inheritance works between controllers in the same way as it does with models. So in our previous
examples, all of the models could be replaced with controller methods that return string values.
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
because as we mentioned earlier, controllers are not instantiated directly by Angular, but rather
are applied to the scope object.
## Testing Controllers
Although there are many ways to test a controller, one of the best conventions, shown below,
involves injecting the `$rootScope` and `$controller`
Controller Function:
<pre>
function myController($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
$scope.spice = "habanero";
}
</pre>
Controller Test:
<pre>
describe('myController function', function() {
describe('myController', function() {
var scope;
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
var ctrl = $controller(myController, {$scope: scope});
}));
it('should create "spices" model with 3 spices', function() {
expect(scope.spices.length).toBe(3);
});
it('should set the default value of spice', function() {
expect(scope.spice).toBe('habanero');
});
});
});
</pre>
If you need to test a nested controller you need to create the same scope hierarchy
in your test that exists in the DOM.
<pre>
describe('state', function() {
var mainScope, childScope, babyScope;
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
childScope = mainScope.$new();
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
babyScope = childCtrl.$new();
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
}));
it('should have over and selected', function() {
expect(mainScope.timeOfDay).toBe('morning');
expect(mainScope.name).toBe('Nikki');
expect(childScope.timeOfDay).toBe('morning');
expect(childScope.name).toBe('Mattie');
expect(babyScope.timeOfDay).toBe('evening');
expect(babyScope.name).toBe('Gingerbreak Baby');
});
});
</pre>
## Related Topics
* {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
@@ -0,0 +1,71 @@
@ngdoc overview
@name Developer Guide: About MVC in Angular: Understanding the Model Component
@description
Depending on the context of the discussion in the Angular documentation, the term _model_ can refer to
either a single object representing one entity (for example, a model called "phones" with its value
being an array of phones) or the entire data model for the application (all entities).
In Angular, a model is any data that is reachable as a property of an angular {@link
scope Scope} object. The name of the property is the model identifier and the value is
any JavaScript object (including arrays and primitives).
The only requirement for a JavaScript object to be a model in Angular is that the object must be
referenced by an Angular scope as a property of that scope object. This property reference can be
created explicitly or implicitly.
You can create models by explicitly creating scope properties referencing JavaScript objects in the
following ways:
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
occurs in controllers:
function MyCtrl($scope) {
// create property 'foo' on the MyCtrl's scope
// and assign it an initial value 'bar'
$scope.foo = 'bar';
}
* Use an {@link expression angular expression} with an assignment operator in templates:
<button ng-click="{{foos='ball'}}">Click me</button>
* Use {@link api/ng.directive:ngInit ngInit directive} in templates (for toy/example apps
only, not recommended for real applications):
<body ng-init=" foo = 'bar' ">
Angular creates models implicitly (by creating a scope property and assigning it a suitable value)
when processing the following template constructs:
* Form input, select, textarea and other form elements:
<input ng-model="query" value="fluffy cloud">
The code above creates a model called "query" on the current scope with the value set to "fluffy
cloud".
* An iterator declaration in {@link api/ng.directive:ngRepeat ngRepeater}:
<p ng-repeat="phone in phones"></p>
The code above creates one child scope for each item in the "phones" array and creates a "phone"
object (model) on each of these scopes with its value set to the value of "phone" in the array.
In Angular, a JavaScript object stops being a model when:
* No Angular scope contains a property that references the object.
* All Angular scopes that contain a property referencing the object become stale and eligible for
garbage collection.
The following illustration shows a simple data model created implicitly from a simple template:
<img src="img/guide/about_model_final.png">
## Related Topics
* {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}

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