This feature adds similar functionality to what `$ControllerProvider.register`
and `$CompileProvider.directive` currently provide by allowing a map of filter
name/factories to be passed as the sole argument to `$FilterProvider.register`
to register all of the specified filters.
Closes#4036Closes#4091
How did compiling a templateUrl (async) directive with `replace:true` work before this commit?
1/ apply all directives with higher priority than the templateUrl directive
2/ partially apply the templateUrl directive (create `beforeTemplateNodeLinkFn`)
3/ fetch the template
4/ apply second part of the templateUrl directive on the fetched template
(`afterTemplateNodeLinkFn`)
That is, the templateUrl directive is basically split into two parts (two `nodeLinkFn` functions),
which has to be both applied.
Normally we compose linking functions (`nodeLinkFn`) using continuation - calling the linking
function of a parent element, passing the linking function of the child elements as an argument. The
parent linking function then does:
1/ execute its pre-link functions
2/ call the child elements linking function (traverse)
3/ execute its post-link functions
Now, we have two linking functions for the same DOM element level (because the templateUrl directive
has been split).
There has been multiple issues because of the order of these two linking functions (creating
controller before setting up scope locals, running linking functions before instantiating
controller, etc.). It is easy to fix one use case, but it breaks some other use case. It is hard to
decide what is the "correct" order of these two linking functions as they are essentially on the
same level.
Running them side-by-side screws up pre/post linking functions for the high priority directives
(those executed before the templateUrl directive). It runs post-linking functions before traversing:
```js
beforeTemplateNodeLinkFn(null); // do not travers
afterTemplateNodeLinkFn(afterTemplateChildLinkFn);
```
Composing them (in any order) screws up the order of post-linking functions. We could fix this by
having post-linking functions to execute in reverse order (from the lowest priority to the highest)
which might actually make a sense.
**My solution is to remove this splitting.** This commit removes the `beforeTemplateNodeLinkFn`. The
first run (before we have the template) only schedules fetching the template. The rest (creating
scope locals, instantiating a controller, linking functions, etc) is done when processing the
directive again (in the context of the already fetched template; this is the cloned
`derivedSyncDirective`).
We still need to pass-through the linking functions of the higher priority directives (those
executed before the templateUrl directive), that's why I added `preLinkFns` and `postLinkFns`
arguments to `applyDirectivesToNode`.
This also changes the "$compile transclude should make the result of a transclusion available to the
parent directive in post- linking phase (templateUrl)" unit test. It was testing that a parent
directive can see the content of transclusion in its pre-link function. That is IMHO wrong (as the
`ngTransclude` directive inserts the translusion in its linking function). This test was only passing because of
c173ca4128, which changed the behavior of the compiler to traverse
before executing the parent linking function. That was wrong and also caused the #3792 issue, which
this change fixes.
Closes#3792Closes#3923Closes#3935Closes#3927
jqLite previously used `elt.className` to add and remove classes from a DOM Node, but
because the className property is not writable on SVG elements, it doesn't work with
them. This patch replaces accesses to `className` with `get/setAttribute`.
`classList` was also considered as a solution, but because only IE10+ supports it, we
have to wait. :'(
The JqLiteAddClass/JQLiteRemoveClass methods are now also used directly by $animate
to work around the jQuery not being able to handle class modifications on SVG elements.
Closes#3858
The problem was in keeping the values of `attrNameStart` and `attrNameEnd` between directive loop iterations which lead to the compiler looking for multi-element ranges for any directives that happened to be in the directive list after one that was applied on a range. For instance, having a ng-repeat-start and ng-class on a single element with ng-repeat being resolved first made the compiler look for an ng-repeat-end for both ng-repeat and ng-class because the `attrNameEnd` was not reset to a falsy value before the second iteration. As the result, an exception saying the block end element could not be found and the second directive was not actually applied.
Closes#4002
Previously if the collection model was set to undefined on the first digest,
the repeater would get confused and not use the correct tracking function
for associating model with dom elements in the repeater.
Closes#4145Closes#3964
Ref: https://github.com/angular/angular.js/pull/4045
I have this sinking feeling that support this use case sort of
encourages binding to function that blindly trust some html. For now,
I'm fixing the issue while I think about the use cases some more.
In the case of a function that performs any non-trivial work before
wrapping the value (e.g. the showdown filter in issue #3980, or the
binding to a simply wrapper function in issue #3932 if it did anything
meaty), this fix makes it "work" - but performance is going to suck -
you should bind to some other thing on scope that watches the actual
source and adjusts itself when that changes (e.g. the showdown filter.)
For the case of the wrapper in #3932, if one isn't performing
sanitization or some such thing - then you the developer has insight
into why that value is safe in that particular context - and it should
be available simply by name and not as a result of a function taking any
arbitrary input to make auditing of security a little saner.
Closes#3932, #3980
BREAKING CHANGE: ngInclude's priority is now set to 1000
It's quite rare for anyone to depend on explicity directive priority,
but if a custom directive that needs to run before ngInclude exists,
it should have its priority checked and adjusted if needed.
Closes#3793
Previously, the check that Application should return a new $window and
$document had the arguments reversed in the first call to navigateTo;
thus, the subsequent check of inequality of $window and $document in the
next navigateTo call would always pass.
This corrects the argument order, which makes this test not succeptible
to false positives.
onAnimationProgress now checks the event's elapsedTime property before
checking the originalEvent.elapsedTime property.
Use browserTrigger with elapsedTime parameter to trigger animation events
BREAKING CHANGE: browserTrigger now uses an eventData object instead of direct parameters for mouse events.
To migrate, place the `keys`,`x` and `y` parameters inside of an object and place that as the third parameter
for the browserTrigger function.
It's great that IE11 wants to be compatible enough that it doesn't want
to be special cased and treated differently.
However, as long as one has to have a different code path for IE than
for the other supported browsers, we still need to detect and special
case it. For instance, our URL parsing code still needs the same
workaround the we used for IE10. We still see the same Access denied /
TypeError exceptions when setting certain values. FYI, Angular doesn't
generally blindly test for IE – we also check the version number.
Thanks to modern.ie for the free IE11 test VM.
Closes#3682
This reverts commit 42af8eada2.
This turned out to be a bad idea as it prevents us from moving the
time forward and asserting that the component state didn't change
due to the scheduled task executing too early.
This change causes a new $digest to be scheduled in the next tick if
a task was was sent to the $evalAsync queue from outside of a $digest
or an $apply.
While this mode of operation is not common for most of the user code,
this change means that $q promises that utilze $evalAsync queue to
guarantee asynchronicity of promise apis will now also resolve outside
of a $digest, which turned out to be a big pain point for some developers.
The implementation ensures that we don't do more work than needed and
that we coalese as much work as possible into a single $digest.
The use of $browser instead of setTimeout ensures that we can mock out
and control the scheduling of "auto-flush", which should in theory
allow all of the existing code and tests to work without negative
side-effects.
Closes#3539Closes#2438
When $timeout#flush is called with a delay and no task can be flushed within that
delay, the current time should not be updated as that gets the mock into an inconsistent
state.
BREAKING CHANGE: if a tests was written around the buggy behavior the delays might be off now
This would typically not be a problem, but because of the previous breaking change in
$timeout.flush, the combination of two might be confusing and that's why we are documenting
it.
Old behavior:
```
doSomething(); //schedules task to execute in 500ms from now
doOtherStuff(); //schedules task to execute in 600ms from now
try {
$timeout.flush(300); // throws "no task to be flushed" exception
} catch(e) {};
$time.flush(200); //flushes only doSomething() task
```
New behavior:
```
doSomething(); //schedules task to execute in 500ms from now
doOtherStuff(); //schedules task to execute in 600ms from now
try {
$timeout.flush(300); // throws "no task to be flushed" exception
} catch(e) {};
$time.flush(200); // throws "no task to be flushed" exception again
// because previous exception didn't move the time forward
```
Fixed test:
```
doSomething(); //schedules task to execute in 500ms from now
doOtherStuff(); //schedules task to execute in 600ms from now
try {
$timeout.flush(300); // throws "no task to be flushed" exception
} catch(e) {};
$time.flush(500); // flushes only doSomething() task
```
When calling $timeout.flush with or without a delay an exception should
be thrown if there is nothing to be flushed.
This prevents tests from flushing stuff unnecessarily.
BREAKING CHANGE: calling $timeout.flush(delay) when there is no task to be flushed
within the delay throws an exception now.
Please adjust the delay or remove the flush call from your tests as the exception
is a signed of a programming error.
ngAnimate causes a 1ms flicker on the screen when no CSS animations are present on the element.
The solution is to change $animate to only use $timeouts when a duration is found on the element
before the transition/keyframe animation takes over.
Closes#3613
This reverts commit 637c9b1611.
(ref #3633 and #3646)
The minimum bar for $sce is IE8 in standards mode. IE7 standards mode
is not supported. If you must support IE7, you should disable $sce
completely.
angular.module('ie7support', []).config(function($sceProvider) {
// Completely disable SCE to support IE7.
$sceProvider.enabled(false);
});
Changes documentMode test version to 7 in order to support IE 8 in IE 7 standards
mode while still protecting against quirks mode.
documentMode returns the following values:
5 - quirks mode,
7 - IE 7 standards mode,
8 - IE 8 standards mode.
Closes#3633Closes#3646
when the transluded content is being teleported to the translusion point, we should ensure that
the translusion point is empty before appending otherwise we end up with junk before the transcluded
content
previously the translusion was appended the the ngTranslude element via
$evalAsync which makes the transluded dom unavailable to parent
post-linking functions. By appending translusion in linking phase,
post-linking functions will be able to access it.
Code was evaluating !expression[key] while attempting to
see if the key was present, but this was evaluating to true for
false values as well as missing keys.
Closes#2797.
Make sure $timeout callbacks are forgotten about immediately after
execution or cancellation.
Previously when passing invokeApply=false, the cleanup used $q and so
would be pending until the next $digest was triggered. This does not
make a large functional difference, but can be very visible when
looking at memory consumption of an app or debugging around the
$$asyncQueue - these callbacks can have a big retaining tree.
After a recent refactoring using $location in the default hashbang mode would result
in hash url being initialized unnecessarily in cases when the base url didn't end
with a slash.
for example http://localhost:8000/temp.html would get rewritten as
http://location:8000/temp.html#/temp.html by error.
Added new route matching capabilities:
- optional param
Changed route matching syntax:
- named wildcard
BREAKING CHANGE: the syntax for named wildcard parameters in routes
has changed from *wildcard to :wildcard*
To migrate the code, follow the example below. Here, *highlight becomes
:highlight*:
Before:
$routeProvider.when('/Book1/:book/Chapter/:chapter/*highlight/edit',
{controller: noop, templateUrl: 'Chapter.html'});
After:
$routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit',
{controller: noop, templateUrl: 'Chapter.html'});
This fixes regression introduced by #3514 (5c560117) - this commit is being
reverted here and a better fix is included.
The regression caused the controller to be instantiated before the isolate scope
was initialized.
Closes#3493Closes#3482Closes#3537Closes#3540
BREAKING CHANGE: the `always` method has been renamed to `finally`.
The reason for this change is to align `$q` with the Q promises library,
despite the fact that this makes it a bit more difficult to
use with non-ES5 browsers, like IE8.
`finally` also goes well together with `catch` api that was added to
$q recently and is part of the DOM promises standard.
To migrate the code follow the example below:
Before:
$http.get('/foo').always(doSomething);
After:
$http.get('/foo').finally(doSomething);
or for IE8 compatible code:
$http.get('/foo')['finally'](doSomething);
Nothing would prevent a user from accidentally calling angular.bootstrap on an element that had already been bootstrapped. If this was done, odd behavior could manifest in an application, causing different scopes to update the same DOM, and causing debugger confusion.
This fix adds a check inside of angular.bootstrap to check if the passed-in element already has an injector, and if so, will throw an error.
BREAKING CHANGE: since all the code in the ngMobile module is touch related,
we are renaming the module to ngTouch.
To migrate, please replace all references to "ngMobile" with "ngTouch" and
"angular-mobile.js" to "angular-touch.js".
Closes#3526
This is necessary to make e2e tests pass for implementing #3411. At present, the docs are violating the rule being enforced by double-bootstrap prevention.
angular.copy previously copied RegExp as an empty object. Change detects
RegExp instance and clones into new RegExp. This change is based on a previous
fix to allow Date to be copied.
Closes#3473Closes#3474
Controllers should be always instantiated after compile fn runs, but before
pre-link fn runs. This way, controllers are available to pre-link fns that
request them.
Previously this was broken for async directives (directives with templateUrl).
Closes#3493Closes#3482Closes#3514
<form name="ctrl.form"> form controller will accessible
as $scope.ctrl.form instead of $scope['ctrl.form']
BREAKING CHANGE:
If you have form names that will evaluate as an expression:
<form name="ctrl.form">
And if you are accessing the form from your controller:
Before:
function($scope) {
$scope['ctrl.form'] // form controller instance
}
After:
function($scope) {
$scope.ctrl.form // form controller instance
}
This makes it possible to access a form from a controller
using the new "controller as" syntax. Supporting the previous
behavior offers no benefit.
The input field email regex does't not match long domain extensions. This commit extends the email regexp to take a 6 character TLD.
Example 6-character TLDs include .museum and .travel - (e.g. allabout.travel).
Add support for passing function as validating data:
- To avoid hacking test method of RegExp
- Optionally overwrite `toString` method of fn to show validation tips
- change docs: param description for `when`, `whenPost`, `whenPut`,
`expect`, `expectPost`, `expectPut`, `expectPATCH`
Closes: #2981
This fixes an inconsistency where you can't call the setter function
when the expression resolves to a top level field name on a promise.
Setting a field on an unresolved promise will throw an exception. (This
shouldn't really happen in your template/js code and points to a
programming error.)
Closes#1827
Ghost clicks are busted but the corresponding form elements are still focused. This means that for example on smartphones the soft keyboard will be opened. This pull request prevents the unwanted opening of the soft keyboard.
The global jQuery reference is removed by angular scenario and only a local scoped reference is kept. To make jQuery available for other code, a new reference angular.scenario.jQuery is added.
Normally $exceptionHandler doesn't throw an exception. It is normally
used just for logging and so on. But if an application developer
implemented a version that did throw an exception then $q would never
have called reject() when converting an exception thrown inside a `then`
handler into a rejected promise.
When using $resource you must setup your actions carefully based on what the server returns.
If the server responds to a request with an array then you must configure the action with
`isArray:true` and vice versa. The built-in `get` action defaults to `isArray:false` and the
`query` action defaults to `isArray:true`, which is must be changed if the server does not do this.
Before the error message was an exception inside angular.copy, which didn't explain what the
real problem was. Rather than changing the way that angular.copy works, this change ensures that
a better error message is provided to the programmer if they do not set up their resource actions
correctly.
Closes#2255, #1044
Change the implementation of isArrayLike to use one heavily based on the
implementation in jQuery in order to correctly detect array-like
objects, that way functionality like ngRepeat works as expected.
Support controller: 'MyController as my' syntax for directives which publishes
the controller instance to the directive scope.
Support controllerAs syntax to define an alias to the controller within the
directive scope.
Support controller: 'MyController as my' syntax for directives which publishes
the controller instance to the directive scope.
Support controllerAs syntax to define an alias to the controller within the
directive scope.
If ngClass fires off an add- or removeClass whilst the opposite animation is going on then
the animation will be skipped. The default behavior of ngClass was executing remoteClass
with an empty string while addClass had just fired. This commit fixes that bug.
BREAKING CHANGE: previously ngView only updated its content, after this change
ngView will recreate itself every time a new content is included. This ensures
that a single rootElement for all the included contents always exists, which makes
definition of css styles for animations much easier.
BREAKING CHANGE: previously ngInclude only updated its content, after this change
ngInclude will recreate itself every time a new content is included. This ensures
that a single rootElement for all the included contents always exists, which makes
definition of css styles for animations much easier.
- ngAnimate directive is gone and was replaced with class based animations/transitions
- support for triggering animations on css class additions and removals
- done callback was added to all animation apis
- $animation and $animator where merged into a single $animate service with api:
- $animate.enter(element, parent, after, done);
- $animate.leave(element, done);
- $animate.move(element, parent, after, done);
- $animate.addClass(element, className, done);
- $animate.removeClass(element, className, done);
BREAKING CHANGE: too many things changed, we'll write up a separate doc with migration instructions
the $timeout mock's flush method allows flushing queued up requests
but doesn't allow to for checking with what delay a task was queued
up. flushNext flushes the next queued up task and can asserts the
scheduled delay.
Similar to ngMobile clicks, these events were not capturable by other
directives. Now they emit 'swipeleft' and 'swiperight' events that can
be follow with element.on('swipeleft', ...).
Changes:
- remove ng-bind-html-unsafe
- ng-bind-html is now in core
- ng-bind-html is secure
- supports SCE - so you can bind to an arbitrary trusted string
- automatic sanitization if $sanitize is available
BREAKING CHANGE:
ng-html-bind-unsafe has been removed and replaced by ng-html-bind
(which has been removed from ngSanitize.) ng-bind-html provides
ng-html-bind-unsafe like behavior (innerHTML's the result without
sanitization) when bound to the result of $sce.trustAsHtml(string).
When bound to a plain string, the string is sanitized via $sanitize
before being innerHTML'd. If $sanitize isn't available, it's logs an
exception.
$sce is a service that provides Strict Contextual Escaping services to AngularJS.
Strict Contextual Escaping
--------------------------
Strict Contextual Escaping (SCE) is a mode in which AngularJS requires
bindings in certain contexts to result in a value that is marked as safe
to use for that context One example of such a context is binding
arbitrary html controlled by the user via ng-bind-html-unsafe. We
refer to these contexts as privileged or SCE contexts.
As of version 1.2, Angular ships with SCE enabled by default.
Note: When enabled (the default), IE8 in quirks mode is not supported.
In this mode, IE8 allows one to execute arbitrary javascript by the use
of the expression() syntax. Refer
http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx
to learn more about them. You can ensure your document is in standards
mode and not quirks mode by adding <!doctype html> to the top of your
HTML document.
SCE assists in writing code in way that (a) is secure by default and (b)
makes auditing for security vulnerabilities such as XSS, clickjacking,
etc. a lot easier.
Here's an example of a binding in a privileged context:
<input ng-model="userHtml">
<div ng-bind-html-unsafe="{{userHtml}}">
Notice that ng-bind-html-unsafe is bound to {{userHtml}} controlled by
the user. With SCE disabled, this application allows the user to render
arbitrary HTML into the DIV. In a more realistic example, one may be
rendering user comments, blog articles, etc. via bindings. (HTML is
just one example of a context where rendering user controlled input
creates security vulnerabilities.)
For the case of HTML, you might use a library, either on the client side, or on the server side,
to sanitize unsafe HTML before binding to the value and rendering it in the document.
How would you ensure that every place that used these types of bindings was bound to a value that
was sanitized by your library (or returned as safe for rendering by your server?) How can you
ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
properties/fields and forgot to update the binding to the sanitized value?
To be secure by default, you want to ensure that any such bindings are disallowed unless you can
determine that something explicitly says it's safe to use a value for binding in that
context. You can then audit your code (a simple grep would do) to ensure that this is only done
for those values that you can easily tell are safe - because they were received from your server,
sanitized by your library, etc. You can organize your codebase to help with this - perhaps
allowing only the files in a specific directory to do this. Ensuring that the internal API
exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
In the case of AngularJS' SCE service, one uses $sce.trustAs (and
shorthand methods such as $sce.trustAsHtml, etc.) to obtain values that
will be accepted by SCE / privileged contexts.
In privileged contexts, directives and code will bind to the result of
$sce.getTrusted(context, value) rather than to the value directly.
Directives use $sce.parseAs rather than $parse to watch attribute
bindings, which performs the $sce.getTrusted behind the scenes on
non-constant literals.
As an example, ngBindHtmlUnsafe uses $sce.parseAsHtml(binding
expression). Here's the actual code (slightly simplified):
var ngBindHtmlUnsafeDirective = ['$sce', function($sce) {
return function(scope, element, attr) {
scope.$watch($sce.parseAsHtml(attr.ngBindHtmlUnsafe), function(value) {
element.html(value || '');
});
};
}];
Impact on loading templates
---------------------------
This applies both to the ng-include directive as well as templateUrl's
specified by directives.
By default, Angular only loads templates from the same domain and
protocol as the application document. This is done by calling
$sce.getTrustedResourceUrl on the template URL. To load templates from
other domains and/or protocols, you may either either whitelist them or
wrap it into a trusted value.
*Please note*:
The browser's Same Origin Policy and Cross-Origin Resource Sharing
(CORS) policy apply in addition to this and may further restrict whether
the template is successfully loaded. This means that without the right
CORS policy, loading templates from a different domain won't work on all
browsers. Also, loading templates from file:// URL does not work on
some browsers.
This feels like too much overhead for the developer?
----------------------------------------------------
It's important to remember that SCE only applies to interpolation expressions.
If your expressions are constant literals, they're automatically trusted
and you don't need to call $sce.trustAs on them.
e.g. <div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div> just works.
Additionally, a[href] and img[src] automatically sanitize their URLs and
do not pass them through $sce.getTrusted. SCE doesn't play a role here.
The included $sceDelegate comes with sane defaults to allow you to load
templates in ng-include from your application's domain without having to
even know about SCE. It blocks loading templates from other domains or
loading templates over http from an https served document. You can
change these by setting your own custom whitelists and blacklists for
matching such URLs.
This significantly reduces the overhead. It is far easier to pay the
small overhead and have an application that's secure and can be audited
to verify that with much more ease than bolting security onto an
application later.
Previously, no handlers for the click event would be called for the
fast, touch-based ngMobile clicks, only for desktop browser clicks. Now
the event will fire properly for all clicks.
Closes#3219Closes#3218Closes#3137
changing the type of select box from single to multiple or the other way around
at runtime is currently not supported and the two-way binding does odd stuff
when such situation happens.
we might eventually support this, but for now we are just going to not allow
binding to select[multiple] to prevent people from relying on something that
doesn't work.
BREAKING CHANGE: binding to select[multiple] directly or via ngMultiple (ng-multiple)
directive is not supported. This feature never worked with two-way data-binding,
so it's not expected that anybody actually depends on it.
Closes#3230
- the ngClick attribute was always triggered, regardless the ngDisabled/disabled attributes
- we now check the DOM disabled status before triggering the original click event
Closes#3124Closes#3132
Previously, the number filter would format small and large numbers
as scientific notation. It now uses toFixed() to ensure that all
requested digits are shown.
angular.equals was returning inconsistent values for the comparison between
{} and []:
angular.equals({}, []) // true
angular.equals([], {}]) // false
Since these object are not of the same type, they should not be considered
equivalent.
In commit 6820322db562382fac903be35831275948825317 of Karma-Jasmine, the
dependency on angular.dump was removed. This caused two undesirable side
effects in the angular.js project. 1) Tests for presence of mock dump were failing,
and 2) the default window.dump was not outputting valuable angular-aware info. This
simple fix adds window.dump in testabilityPatch, to preprocess dumped input prior
to passing it to the global dump method.
This code is not being used any more and the test is now failing
due to Karma changes. Karma used to expose window.dump but that
changed recently and that's why our build is now failing.
I'm removing the code and test, but we still need to figure out
how to route window.dump through angular.mock.dump, but that will
have to be a separate commit.
Ref: 1adf29af13
BREAKING CHANGE: img[src] URLs are now sanitized via a separate
whitelist regex instead of sharing the whitelist regex with a[href].
With this change, img[src] URLs may also be data: URI's matching
mime types image/*. mailto: URLs are disallowed (and do not make
sense for img[src] but were allowed under the a[href] whitelist used
before.)
It is now possible to notify a promise through deferred.notify() method.
Notifications are useful to provide a way to send progress information
to promise holders.
Regular expression objects didn't used to be considered to be equal when using
'angular.equals'. Dirty checking therefore failed to recognize a
property modification.
Closes#2685
Return early in `angular.toJson` if the object to be stringified is `undefined`.
IE8 stringifies `undefined` to `'undefined'` whereas other browsers return
`undefined`. This normalizes behavior and passes currently broken unit tests
in IE8.
The colon character is used to identify parameters in $resource.
This meant that we had to escape the colon used in a port.
It turns out that this is not necessary if we assume that parameter
names cannot consist of only digits.
If the parameter consists only of numbers, then it's a port.
Closes#2778
With select(...).option(val) it previously would select the first node
which contains the value, even if an exact match was available.
This fix prefers exact matches if available, otherwise it reverts
to the previous 'contains' behaviour for backwards compatibility.
Closes#2856
Merely testing for object[key] will give incorrect results on keys
defined in Object.prototype.
Note: IE8 is generally broken in this regard since `for...in` never returns
certain property keys even if they are defined directly on the object.
See #2141 - partially merges this PR
The stock Android browser doesn't support the current for-in body/style
detection for animations and transitions but we can manually fix this.
This is useful for PhoneGap web-views or traditional web-apps using the
stock browser.
Previously if a template contained a directive that had a template
(sync or async) and the directive template was to replace the original
element and the directive template contained another directive on the
root element of this template and this new directive was an element
transclude directive then an infinite recursion would follow because
the compiler kept on re-adding and reapplying the original directive
to the replaced node.
This change fixes that.
Closes#2155
This reverts commit 15e1a29cd0.
The original commit was fixing two issues - one of them was
preventing attributes that triggered directives that replaced
the compiled node to be merged into the new node.
This change was a breaking change (as seen in the diff of the
tests in this commit) and that's why it's being removed.
A proper fix will follow.
This reverts commit 0c6fb665a4.
The change invalidated the test because the point of the the test
was to test that an element directive works. Changing it to attribute
directive was wrong.
parseKeyValue and toKeyValue can now handle duplicate values in the query.
```
?x=1&x=2 <-> {x:[1,2]}
```
The algorithm looks like:
1)parseKeyValue looks for presence of obj[key]
2)detects and replaces obj[key] with [obj[key],val]
3)then pushes more duplicates if necessary
4)toKeyValue decodes array correctly
5)(not changed)$location.search({param: 'key'}) still replaces if necessary
6)(not changed)$location.search({param: ['key1', 'key2']}) sets the url with duplicates
BREAKING CHANGE: Before this change:
- `parseKeyValue` only took the last key overwriting all the previous keys;
- `toKeyValue` joined the keys together in a comma delimited string.
This was deemed buggy behavior. If your server relied on this behavior
then either the server should be fixed or a simple serialization of
the array should be done on the client before passing it to $location.
img[src]="https://foo" has the unfortunate problem that the browser will
actually try retrieving the resource the non FQDN foo. The local DNS
might suffix a domain to this, resolve it, and try to present a
certificate for the https request and prompt the user to pick a
certificate. This commit avoids that by making foo a FQDN. Note that it
might be better to replace foo with example.com (ref
http://tools.ietf.org/html/rfc2606#section-3).
With the recent refactoring of $location service we changed this behavior
resulting in a regression.
Previously we thought that html5 mode always required base[href]
to be set in order for urls to resolve properly. It turns out that
base[href] is problematic because it makes anchor urls (#foo) to
always resolve to the base url, which is almost always incorrect
and results in all anchors links and other anchor urls (e.g. svg
references) to be broken.
For this reason, we should now start recommending that people just
deploy to root context (/) and not set the base[href] when using
the html5 mode (push/pop history state).
If it's impossible to deploy to the root context then either all
urls in the app must be absolute or base[href] must be set with the
caveat that anchor urls in such app won't work.
Closes#2762
BREAKING CHANGE: Concatenating expressions makes it hard to reason about
whether some combination of concatenated values are unsafe to use
and could easily lead to XSS. By requiring that a single expression
be used for *[src/ng-src] such as iframe[src], object[src], etc.
(but not img[src/ng-src] since that value is sanitized), we ensure that the value
that's used is assigned or constructed by some JS code somewhere
that is more testable or make it obvious that you bound the value to
some user controlled value. This helps reduce the load when
auditing for XSS issues.
To migrate your code, follow the example below:
Before:
JS:
scope.baseUrl = 'page';
scope.a = 1;
scope.b = 2;
HTML:
<!-- Are a and b properly escaped here? Is baseUrl
controlled by user? -->
<iframe src="{{baseUrl}}?a={{a}&b={{b}}">
After:
JS:
var baseUrl = "page";
scope.getIframeSrc = function() {
// There are obviously better ways to do this. The
// key point is that one will think about this and do
// it the right way.
var qs = ["a", "b"].map(function(value, name) {
return encodeURIComponent(name) + "=" +
encodeURIComponent(value);
}).join("&");
// baseUrl isn't on scope so it isn't bound to a user
// controlled value.
return baseUrl + "?" + qs;
}
HTML: <iframe src="{{getIframeSrc()}}">
BREAKING CHANGE: Interpolations inside DOM event handlers are
disallowed. DOM event handlers execute arbitrary Javascript code.
Using an interpolation for such handlers means that the interpolated
value is a JS string that is evaluated. Storing or generating such
strings is error prone and likely leads to an XSS if you're not
super careful. On the other hand, ng-click and such event handlers
evaluate Angular expressions that are a lot safer (e.g. No direct
access to global objects - only scope), cleaner and harder to
exploit.
To migrate the code follow the example below:
Before:
JS: scope.foo = 'alert(1)';
HTML: <div onclick="{{foo}}">
After:
JS: scope.foo = function() { alert(1); }
HTML: <div ng-click="foo()">
Ref: 9532234bf1
BREAKING CHANGE: img[src] URLs are now sanitized using the same whitelist
as a[href] URLs. The most obvious impact is if you were using data:
URIs. data: URIs will be whitelisted for img[src] in a future
commit.
jQuery switched to a completely new event binding implementation as of
1.7.0, centering around on/off methods instead of previous bind/unbind.
This patch makes jqLite match this implementation while still supporting
previous bind/unbind methods.
$route, $routeParams and ngView have been pulled from core angular.js
to angular-route.js/ngRoute module.
This is was done to in order keep the core focused on most commonly
used functionality and allow community routers to be freely used
instead of $route service.
There is no need to panic, angular-route will keep on being supported
by the angular team.
Note: I'm intentionally not fixing tutorial links. Tutorial will need
bigger changes and those should be done when we update tutorial to
1.2.
BREAKING CHANGE: applications that use $route will now need to load
angular-route.js file and define dependency on ngRoute module.
Before:
```
...
<script src="angular.js"></script>
...
var myApp = angular.module('myApp', ['someOtherModule']);
...
```
After:
```
...
<script src="angular.js"></script>
<script src="angular-route.js"></script>
...
var myApp = angular.module('myApp', ['ngRoute', 'someOtherModule']);
...
```
Closes#2804
jQuery's API for removeData allows a second 'name' argument to just
remove the property by that name from an element's data. The absence
of this argument was causing some features not to work correctly when
combining multiple directives, such as ng-click, ng-show, and ng-animate.
By appending directive-start and directive-end to a
directive it is now possible to have the directive
act on a group of elements.
It is now possible to iterate over multiple elements like so:
<table>
<tr ng-repeat-start="item in list">I get repeated</tr>
<tr ng-repeat-end>I also get repeated</tr>
</table>
This new service is used by the ngSwipeLeft/Right directives, and by the
separate ngCarousel and swipe-to-delete directives which are under
development.
- Instance or collection have `$promise` property which is the initial promise.
- Add per-action `interceptor`, which has access to entire $http response object.
BREAKING CHANGE: resource instance does not have `$then` function anymore.
Before:
Resource.query().$then(callback);
After:
Resource.query().$promise.then(callback);
BREAKING CHANGE: instance methods return the promise rather than the instance itself.
Before:
resource.$save().chaining = true;
After:
resource.$save();
resourve.chaining = true;
BREAKING CHANGE: On success, promise is resolved with the resource instance rather than http
response object.
Use interceptor to access the http response object.
Before:
Resource.query().$then(function(response) {...});
After:
var Resource = $resource('/url', {}, {
get: {
method: 'get',
interceptor: {
response: function(response) {
// expose response
return response;
}
}
}
});
When real jQuery is present, Angular monkey patch it to fire `$destroy` event.
This commit fixes two issues in the jQuery patch:
- passing a selector to the $.fn.remove method (only fire `$destroy` on the matched elements)
- using `$.fn.html` without parameters as a getter (do not fire `$destroy`)
If the timeout argument is a promise, abort the request when it is resolved.
Implemented by adding support to $httpBackend service and $httpBackend mock
service.
This api can also be used to explicitly abort requests while keeping the
communication between the deffered and promise unidirectional.
Closes#1159
Previously, anchor elements could not be used with triggerHandler because
triggerHandler passes null as the event, and any anchor element with an empty
href automatically calls event.preventDefault(). Instead, pass a dummy event
when using triggerHandler, similar to what full jQuery does. Modified from
PR #2379.
Add '?' token to lexer, add ternary rule to parser at
(hopefully) proper precedence and associativity (based
on https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence).
Since (exp1 && exp2 || exp3) is supported by the parser,
and (exp1 ? exp2 : exp3) works the same way, it seems
reasonable to add this minor form of control to templates
(see #719).
The default header is now application/json which while not perfect
in all cases is better than the browser default application/xml.
The new headers also makes for better compatibility with Rails 4
In line with ngSrc and ngHref, this new directive ensures that the
`srcset` HTML5 attribute does not include a pre-interpolated string.
Without it the browser will fetch from the URL with the literal text
`{{hash}}` until AngularJS replaces the expression inside `{{hash}}`.
Closes#2601
Added mousedown and mouseup event triggers to scenadio dsl 'element' expression.
Added mousedown and mouseup to the custom jquery trigger method to generate real events.
Previously only repeated `/` delimiters were collapsed into a
single `/`. Now, the sequence `/.` at the end of the template, i.e.
only followed by a sequence of word characters, is collapsed into a single
`.`. This makes it easier to support suffixes on resource URLs.
For example, given a resource template of `/some/path/:id.:format`, if
the `:id` is `""` but format `"json"` then the URL is now
`/some/path.json`, rather than `/some/path/.json`.
BREAKING CHANGE: A `/` followed by a `.`, in the last segment of the
URL template is now collapsed into a single `.` delimiter. For example:
`users/.json` will become `users.json`. If your server relied upon this
sequence then it will no longer work. In this case you can now escape the
`/.` sequence with `/\.`
Extend ng-options with a new clause, "track by [trackByExpression]", which can be used when
working with objects. The `trackByExpression` should uniquely identify select options objects.
This solves the problem of previously having to match ng-options objects by identity.
You can now write: `ng-options="obj as obj.name for obj in objects track by obj.id"`
The "track by" expression will be used when checking for equality of objects.
Examples:
<select
ng-model="user.favMovieStub"
ng-options="movie as movie.name for movie in movies track by movie.id">
</select>
scope: {
user: { name: 'Test user', favMovieStub: { id: 1, name: 'Starwars' } }
movies: [{ id: 1, name: 'Starwars', rating: 5, ... }, { id: 13, ... }]
}
The select input will match user favMovieStub to the first movie in the movies array, and show
"Star Wars" as the selected item.