If a directive provides a template but is not explicitly requesting transclusion
then the compiler should not pass a transclusion function to the directives
within the template.
If you have two directives that both expect to receive transcluded content
the outer directive works but the inner directive never receives a
transclusion function. This only failed if the first transclude directive
was not the first directive found in compilation.
Handles the regression identified in e994259739Fixes#7240Closes#7387
Transitions that are run through ngAnimate which contain a specific property
cause any inline styles to be erased after the animation is done. This has
something to do with how the browsers handle transitions that do not use
"all" as a transition property.
Closes#7503
Expressions that start with `::` will be binded once. The rule
that binding follows is that the binding will take the first
not-undefined value at the end of a $digest cycle.
Watchers from $watch, $watchCollection and $watchGroup will
automatically stop watching when the expression(s) are bind-once
and fulfill.
Watchers from text and attributes interpolations will
automatically stop watching when the expressions are fulfill.
All directives that use $parse for expressions will automatically
work with bind-once expressions. E.g.
<div ng-bind="::foo"></div>
<li ng-repeat="item in ::items">{{::item.name}};</li>
Paired with: Caitlin and Igor
Design doc: https://docs.google.com/document/d/1fTqaaQYD2QE1rz-OywvRKFSpZirbWUPsnfaZaMq8fWI/edit#Closes#7486Closes#5408
The feature has been deprecated in #4317
BREAKING CHANGE: promise unwrapping has been removed.
It has been deprecated since 1.2.0-rc.3.
It can no longer be turned on.
Two methods have been removed:
* $parseProvider.unwrapPromises
* $parseProvider.logPromiseWarnings
If a directives specifies `replace:true` and the template of the directive contains
a root element with an attribute which already exists at the place
where the directive is used with the same value, don't duplicate the value.
Closes#7463
When a event is finished propagating through Scope hierarchy the event's `currentScope` property
should be reset to `null` to avoid accidental use of this property in asynchronous event handlers.
In the previous code, the event's property would contain a reference to the last Scope instance that
was visited during the traversal, which is unlikely what the code trying to grab scope reference expects.
BREAKING CHANGE: $broadcast and $emit will now reset the `currentScope` property of the event to
null once the event finished propagating. If any code depends on asynchronously accessing thei
`currentScope` property, it should be migrated to use `targetScope` instead. All of these cases
should be considered programming bugs.
Closes#7445Closes#7523
This CL enables interpolation expressions to be escaped, by prefixing each character of their
start/end markers with a REVERSE SOLIDUS U+005C, and to render the escaped expression as a
regular interpolation expression.
Example:
`<span ng-init="foo='Hello'">{{foo}}, \\{\\{World!\\}\\}</span>` would be rendered as:
`<span ng-init="foo='Hello'">Hello, {{World!}}</span>`
This will also work with custom interpolation markers, for example:
module.
config(function($interpolateProvider) {
$interpolateProvider.startSymbol('\\\\');
$interpolateProvider.endSymbol('//');
}).
run(function($interpolate) {
// Will alert with "hello\\bar//":
alert($interpolate('\\\\foo//\\\\\\\\bar\\/\\/')({foo: "hello", bar: "world"}));
});
This change effectively only changes the rendering of these escaped markers, because they are
not context-aware, and are incapable of preventing nested expressions within those escaped
markers from being evaluated.
Therefore, backends are encouraged to ensure that when escaping expressions for security
reasons, every single instance of a start or end marker have each of its characters prefixed
with a backslash (REVERSE SOLIDUS, U+005C)
Closes#5601Closes#7517
Calling `$commitViewValue` was was dirtying the input, even if no update to the view
value was made.
For example, `updateOn` triggers and form submit may call `$commitViewValue` even
if the the view value had not changed.
Closes#7457Closes#7495
If you have two directives that both expect to receive transcluded content
the outer directive works but the inner directive never receives a
transclusion function. This only failed if the first transclude directive
was not the first directive found in compilation.
Fixes#7240Closes#7387
This attribute is useful for text that should still be selectable
by the mouse and not trigger the swipe action.
This also adds an optional third argument to `$swipe.bind` to define
the pointer types that should be listened to.
Closes#6627Fixes#6626
Currently Angular monkey-patches a few jQuery methods that remove elements
from the DOM. Since methods like .remove() have multiple signatures
that can change what's actually removed, Angular needs to carefully
repeat them in its patching or it can break apps using jQuery correctly.
Such a strategy is also not future-safe.
Instead of patching individual methods on the prototype, it's better to
hook into jQuery.cleanData and trigger custom events there. This should be
safe as e.g. jQuery UI needs it and uses it. It'll also be future-safe.
The only drawback is that $destroy is no longer triggered when using $detach
but:
1. Angular doesn't use this method, jqLite doesn't implement it.
2. Detached elements can be re-attached keeping all their events & data
so it makes sense that $destroy is not triggered on them.
3. The approach from this commit is so much safer that any issues with
.detach() working differently are outweighed by the robustness of the code.
BREAKING CHANGE: the $destroy event is no longer triggered when using the
jQuery detach() method. If you want to destroy Angular data attached to the
element, use remove().
All isolated scope directives that do not have `templateUrl` were marked
as `$isolateScopeNoTemplate` even if they did have a `template` attribute.
This caused `jqLite#scope()` to return the wrong value for child elements
within the directive's template.
Closes#6942
Use the new `NgModelController.$commitViewValue()` method to commit the
`$viewValue` on all the child controls (including nested `ngForm`s) when the form
receives the `submit` event. This will happen immediately, overriding any
`updateOn` and `debounce` settings from `ngModelOptions`.
If you wish to access the committed `$modelValue`s then you can use the `ngSubmit`
directive to provide a handler. Don't use `ngClick` on the submit button, as this
handler would be called before the pending `$viewValue`s have been committed.
Closes#7017
Move responsibility for pending and debouncing model updates into `NgModelController`.
Now input directives are only responsible for capturing changes to the input element's
value and then calling `$setViewValue` with the new value.
Calls to `$setViewValue(value)` change the `$viewValue` property but these changes are
not committed to the `$modelValue` until an `updateOn` trigger occurs (and any related
`debounce` has resolved).
The `$$lastCommittedViewValue` is now stored when `$setViewValue(value)` updates
the `$viewValue`, which allows the view to be "reset" by calling `$rollbackViewValue()`.
The new `$commitViewValue()` method allows developers to force the `$viewValue` to be
committed through to the `$modelValue` immediately, ignoring `updateOn` triggers and
`debounce` delays.
BREAKING CHANGE:
This commit changes the API on `NgModelController`, both semantically and
in terms of adding and renaming methods.
* `$setViewValue(value)` -
This method still changes the `$viewValue` but does not immediately commit this
change through to the `$modelValue` as it did previously.
Now the value is committed only when a trigger specified in an associated
`ngModelOptions` directive occurs. If `ngModelOptions` also has a `debounce` delay
specified for the trigger then the change will also be debounced before being
committed.
In most cases this should not have a significant impact on how `NgModelController`
is used: If `updateOn` includes `default` then `$setViewValue` will trigger
a (potentially debounced) commit immediately.
* `$cancelUpdate()` - is renamed to `$rollbackViewValue()` and has the same meaning,
which is to revert the current `$viewValue` back to the `$lastCommittedViewValue`,
to cancel any pending debounced updates and to re-render the input.
To migrate code that used `$cancelUpdate()` follow the example below:
Before:
```
$scope.resetWithCancel = function (e) {
if (e.keyCode == 27) {
$scope.myForm.myInput1.$cancelUpdate();
$scope.myValue = '';
}
};
```
After:
```
$scope.resetWithCancel = function (e) {
if (e.keyCode == 27) {
$scope.myForm.myInput1.$rollbackViewValue();
$scope.myValue = '';
}
}
```
It is reasonable to expect a digest to occur between an input element
compiling and the first user interaction. Rather than add digests to
each test this change moves it into the `compileInput` helper function.
Due to a regression introduced several releases ago, the ability for multiple transclude functions
to work correctly changed, as they would break if different case labels had different numbers of
transclude functions.
This CL corrects this by not assuming that previous elements and scope count have the same length.
Fixes#7372Closes#7373
Because of how the logic was set up, a value of `0` was assumed to be the
same as `undefined`, which meant that you couldn't override the default
debounce delay with a value of zero.
For example, the following assigned a debounce delay of 500ms to the `blur`
event.
```
ngModelOptions="{ updateOn: 'default blur', debounce: {'default': 500, 'blur':
0} }"
```
Closes#7205
Input controls require `ngModel` which in turn brings in the `ngModelOptions`
but since ngModel does this initialization in the post link function, the
order in which the directives are run is relevant.
Directives are sorted by priority and name but `ngModel`, `input` and `textarea`
have the same priority. It just happens that `textarea` is alphabetically
sorted and so linked before `ngModel` (unlike `input`).
This is a problem since inputs expect `ngModelController.$options`
to exist at post-link time and for `textarea` this has not happened.
This is solved easily by moving the initialization of `ngModel` to the
pre-link function.
Closes#7281Closes#7292
The encodeEndities function encode non-alphanumeric characters to entities with charCodeAt.
charCodeAt does not return one value when their unicode codeponts is higher than 65,356.
It returns surrogate pair, and this is why the Emoji which has higher codepoints is garbled.
We need to handle them properly.
Closes#5088Closes#6911
BREAKING CHANGE
If `bar` is `undefined`, before `<img src="foo/{{bar}}.jpg">` yields
`<img src="foo/.jpg">`. With this change, the binding will not set `src`.
If you want the old behavior, you can do this: `<img src="foo/{{bar || ''}}.jpg">`.
The same applies for `srcset` as well.
Closes#6984
The ngMessages module provides directives designed to better support
handling and reusing error messages within forms without the need to
rely on complex structural directives.
Please note that the API for ngMessages is experimental and may possibly change with
future releases.
This change ensures that a module's config blocks are always invoked after all of its providers are
registered.
BREAKING CHANGE:
Previously, config blocks would be able to control behaviour of provider registration, due to being
invoked prior to provider registration. Now, provider registration always occurs prior to configuration
for a given module, and therefore config blocks are not able to have any control over a providers
registration.
Example:
Previously, the following:
angular.module('foo', [])
.provider('$rootProvider', function() {
this.$get = function() { ... }
})
.config(function($rootProvider) {
$rootProvider.dependentMode = "B";
})
.provider('$dependentProvider', function($rootProvider) {
if ($rootProvider.dependentMode === "A") {
this.$get = function() {
// Special mode!
}
} else {
this.$get = function() {
// something else
}
}
});
would have "worked", meaning behaviour of the config block between the registration of "$rootProvider"
and "$dependentProvider" would have actually accomplished something and changed the behaviour of the
app. This is no longer possible within a single module.
Fixes#7139Closes#7147
546cb42 introduced a regression, which would cause the function returned from
$interpolate to throw a ReferenceError if `context` is undefined. This change
prevents the error from being thrown.
Closes#7230Closes#7237
Code cleanup! response interceptors have been deprecated for some time, and it is confusing to have
two APIs, one of which is slightly "hidden" and hard to see, which perform the same task. The newer
API is a bit cleaner and more visible, so this is naturally preferred.
BREAKING CHANGE:
Previously, it was possible to register a response interceptor like so:
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return function(promise) {
return promise.then(function(response) {
// do something on success
return response;
}, function(response) {
// do something on error
if (canRecover(response)) {
return responseOrNewPromise
}
return $q.reject(response);
});
}
});
$httpProvider.responseInterceptors.push('myHttpInterceptor');
Now, one must use the newer API introduced in v1.1.4 (4ae46814), like so:
$provide.factory('myHttpInterceptor', function($q) {
return {
response: function(response) {
// do something on success
return response;
},
responseError: function(response) {
// do something on error
if (canRecover(response)) {
return responseOrNewPromise
}
return $q.reject(response);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
More details on the new interceptors API (which has been around as of v1.1.4) can be found at
https://docs.angularjs.org/api/ng/service/$http#interceptorsCloses#7266Closes#7267
Previously, templates would always be assumed to be valid HTML nodes. In some cases, it is
desirable to use SVG or MathML or some other language.
For the time being, this change is only truly meaningful for SVG elements, as MathML has
very limited browser support. But in the future, who knows?
Closes#7265
This change undoes the use of watchGroup by code that uses $interpolate, by
moving the optimizations into the $interpolate itself. While this is not ideal,
it means that we are making the existing api faster rather than require people
to use $interpolate differently in order to benefit from the speed improvements.
BREAKING CHANGE: the function returned by $interpolate
no longer has a `.parts` array set on it.
It has been replaced by two arrays:
* `.expressions`, an array of the expressions in the
interpolated text. The expressions are parsed with
$parse, with an extra layer converting them to strings
when computed
* `.separators`, an array of strings representing the
separations between interpolations in the text.
This array is **always** 1 item longer than the
`.expressions` array for easy merging with it
Given an array of expressions, if any one expression changes then the listener function fires
with an arrays of old and new values.
$scope.watchGroup([expression1, expression2, expression3], function(newVals, oldVals) {
// newVals and oldVals are arrays of values corresponding to expression1..3
...
});
Port of angular/angular.dart@a3c31ce1dd