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
Certain versions of IE inexplicably trigger an input event in response to a placeholder
being set.
It is not possible to sniff for this behaviour nicely as the event is not triggered if
the element is not attached to the document, and the event triggers asynchronously so
it is not possible to accomplish this without deferring DOM compilation and slowing down
load times.
Closes#2614Closes#5960
This CL fixes problems and adds test cases for changes from #6421. Changes
include fixing the algorithm for preprocessing href attribute values, as
well as supporting xlink:href attributes. Credit for the original URL
parsing algorithm still goes to @richardcrichardc.
Good work, champ!
Previously, ctreq would possibly reference the incorrect directive name,
due to relying on a directiveName living outside of the closure which
throws the exception, which can change before the call is ever made.
This change saves the current value of directiveName as a property of
the link function, which prevents this from occurring.
Closes#7062Closes#7067
parseInt(Infinity, 10) will result in NaN, which becomes undesirable when the expected behaviour is
to return the entire input.
I believe this is possibly useful as a way to toggle input limiting based on certain factors.
Closes#6771Closes#7118
This modifies the injector to prevent automatic annotation from occurring for a given injector.
This behaviour can be enabled when bootstrapping the application by using the attribute
"ng-strict-di" on the root element (the element containing "ng-app"), or alternatively by passing
an object with the property "strictDi" set to "true" in angular.bootstrap, when bootstrapping
manually.
JS example:
angular.module("name", ["dependencies", "otherdeps"])
.provider("$willBreak", function() {
this.$get = function($rootScope) {
};
})
.run(["$willBreak", function($willBreak) {
// This block will never run because the noMagic flag was set to true,
// and the $willBreak '$get' function does not have an explicit
// annotation.
}]);
angular.bootstrap(document, ["name"], {
strictDi: true
});
HTML:
<html ng-app="name" ng-strict-di>
<!-- ... -->
</html>
This will only affect functions with an arity greater than 0, and without an $inject property.
Closes#6719Closes#6717Closes#4504Closes#6069Closes#3611
First, this now uses a flat object configuration, similar to
`$httpBackend`. This should make configuring this provider much more
familiar.
This adds a fourth optional argument to the `$resource()` constructor,
supporting overriding global `$resourceProvider` configuration.
Now, both of these ways of configuring this is supported:
app.config(function($resourceProvider) {
$resourceProvider.defaults.stripTrailingSlashes = false;
});
or per instance:
var CreditCard = $resource('/some/:url/', ..., ..., {
stripTrailingSlashes: false
});
The `$cancelUpdate()` method on `NgModelController` cancels any pending debounce
action and resets the view value by invoking `$render()`.
This method should be invoked before programmatic update to the model of inputs
that might have pending updates due to `ng-model-options` specifying `updateOn`
or `debounce` properties.
Fixes#6994Closes#7014
By default, any change to an input will trigger an immediate model update,
form validation and run a $digest. This is not always desirable, especially
when you have a large number of bindings to update.
This PR implements a new directive `ngModelOptions`, which allow you to
override this default behavior in several ways. It is implemented as an
attribute, to which you pass an Angular expression, which evaluates to an
**options** object.
All inputs, using ngModel, will search for this directive in their ancestors
and use it if found. This makes it easy to provide options for a whole
form or even the whole page, as well as specifying exceptions for
individual inputs.
* You can specify what events trigger an update to the model by providing
an `updateOn` property on the **options** object. This property takes a
string containing a space separated list of events.
For example, `ng-model-options="{ updateOn: 'blur' }"` will update the
model only after the input loses focus.
There is a special pseudo-event, called "default", which maps to the
default event used by the input box normally. This is useful if you
want to keep the default behavior and just add new events.
* You can specify a debounce delay, how long to wait after the last triggering
event before updating the model, by providing a `debounce` property on
the **options** object.
This property can be a simple number, the
debounce delay for all events. For example,
`ng-model-options="{ debounce: 500 }" will ensure the model is updated
only when there has been a period 500ms since the last triggering event.
The property can also be an object, where the keys map to events and
the values are a corresponding debounce delay for that event.
This can be useful to force immediate updates on some specific
circumstances (like blur events). For example,
`ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0} }"`
This commit also brings to an end one of the longest running Pull Requests
in the history of AngularJS (#2129)! A testament to the patience of @lrlopez.
Closes#1285, #2129, #6945
With 1.2.x, `$animate.enter` and `$animate.move` both insert the element at the end of the provided
parent container element when only the `parent` element is provided. If an `after` element is provided
then they will place the inserted element after that one. This works fine, but there is no way to
place an item at the top of the provided parent container using these two APIs.
With this change, if the `after` argument is not specified for either `$animate.enter` or `$animate.move`,
the new child element will be inserted into the first position of the parent container element.
Closes#4934Closes#6275
BREAKING CHANGE: $animate will no longer default the after parameter to the last element of the parent
container. Instead, when after is not specified, the new element will be inserted as the first child of
the parent container.
To update existing code, change all instances of `$animate.enter()` or `$animate.move()` from:
`$animate.enter(element, parent);`
to:
`$animate.enter(element, parent, angular.element(parent[0].lastChild));`
The default CSS driver in ngAnimate directly uses node.className when reading
the CSS class string on the given element. While this works fine with standard
HTML DOM elements, SVG elements have their own DOM property. By switching to use
node.getAttribute, ngAnimate can extract the element's className value without
throwing an exception.
When using jQuery over jqLite, ngAnimate will not properly handle SVG elements
for an animation. This is because jQuery doesn't process SVG elements within it's
DOM operation code by default. To get this to work, simply include the jquery.svg.js
JavaScript file into your application.
Closes#6030
When a async task interacts with a scope that has been destroyed already
and if it interacts with a property that is prototypically inherited from
some parent scope then resetting proto would make these inherited properties
inaccessible and would result in NPEs
The basic approach is to introduce a new elt.data() called $classCounts that keeps
track of how many times ngClass, ngClassEven, or ngClassOdd tries to add a given class.
The class is added only when the count goes from 0 to 1, and removed only when the
count hits 0.
To avoid duplicating work, some of the logic for checking which classes
to add/remove move into this directive and the directive calls $animate.
Closes#5271
Due to a known V8 memory leak[1] we need to perform extra cleanup to make it easier
for GC to collect this scope object.
V8 leaks are due to strong references from optimized code (fixed in M34) and inline
caches (fix in works). Inline caches are caches that the virtual machine builds on the
fly to speed up property access for javascript objects. These caches contain strong
references to objects so under certain conditions this can create a leak.
The reason why these leaks are extra bad for Scope instances is that scopes hold on
to ton of stuff, so when a single scope leaks, it makes a ton of other stuff leak.
This change removes references to objects that might be holding other big
objects. This means that even if the destroyed scope leaks, the child scopes
should not leak because we are not explicitly holding onto them.
Additionally in theory we should also help make the current scope eligible for GC
by changing properties of the current Scope object.
I was able to manually verify that this fixes the problem for the following
example app: http://plnkr.co/edit/FrSw6SCEVODk02Ljo8se
Given the nature of the problem I'm not 100% sure that this will work around
the V8 problem in scenarios common for Angular apps, but I guess it's better
than nothing.
This is a second attempt to enhance the cleanup, the first one failed and was
reverted because it was too aggressive and caused problems for existing apps.
See: #6897
[1] V8 bug: https://code.google.com/p/v8/issues/detail?id=2073Closes#6794Closes#6856Closes#6968
Previously, the jqLite constructor was limited and would be unable to circumvent many of the HTML5
spec's "allowed content" policies for various nodes. This led to complicated and gross hacks around
this in the HTML compiler.
This change refactors these hacks by simplifying them, and placing them in jqLite rather than in
$compile, in order to better support these things, and simplify code.
While the new jqLite constructor is still not even close to as robust as jQuery, it should be more
than suitable enough for the needs of the framework, while adding minimal code.
Closes#6941Closes#6958
Previously, constant numbers with a unary minus sign were not treated as constants. This fix corrects
this behaviour, and may provide a small performance boost for certain applications, due to constant
watches being automatically unregistered after their first listener call.
Closes#6932
Makes xhr status text accessible is $http success/error callback.
See www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-statustext
Closes#2335Closes#2665Closes#6713
$animate attempts places a `transition: none 0s` block on the element when
the first CSS class is applied if a transition animation is underway. This
works fine for structural animations (enter, leave and move), however, for
class-based animations, this poses a big problem. As of this patch, instead
of $animate placing the block, it is now the responsibility of the user to
place `transition: 0s none` into their class-based transition setup CSS class.
This way the animation will avoid all snapping and any will allow $animate to
play nicely with class-based transitions that are defined outside of ngAnimate.
Closes#6674Closes#6739
BREAKING CHANGE: Any class-based animation code that makes use of transitions
and uses the setup CSS classes (such as class-add and class-remove) must now
provide a empty transition value to ensure that its styling is applied right
away. In other words if your animation code is expecting any styling to be
applied that is defined in the setup class then it will not be applied
"instantly" default unless a `transition:0s none` value is present in the styling
for that CSS class. This situation is only the case if a transition is already
present on the base CSS class once the animation kicks off.
If a JS animation is run before a CSS animation then the JS animation may end up writing style
data to the element. If any transition or animation style data is written then it may end up
being accidentally inherited into the CSS animation hanlder that ngAnimate uses. This may result
in an unexpected outcome due to the tweaks and hacks that the CSS handler places on the element.
If the CSS animation is run before the JS animation then, if there are no transitions on the style
attribute nor within the global CSS on the page then nothing will happen and the JS animation can
work as expected.
Closes#6675
fb6062fb9d implements a
fix for NaN values causing $watchCollection to throw an infdig error. This change updates the test
by adding an assertion which explains what is actually being tested a bit better, and may also
provide better information in the event that the test ever fails.
Closes#6758
$watchCollection checks if oldValue !== newValue which does not work for NaN. This was causing
infinite digest errors, since comparing NaN to NaN in $watchCollection would always return false,
indicating that a change was occuring on each loop.
This fix adds a simple check to see if the current value and previous value are both NaN, and
if so, does not count it as a change.
Closes#4605
In some specific timezones and operating systems, it seems that
getTimezoneOffset() can return an incorrect value for negative timestamps, as
described in #5017. While this isn't something easily fixed in the mock code,
the tests can avoid that particular timeframe by using a positive timestamp.
Closes#5017Closes#6730
In Firefox, hovering over an option in an open select menu updates the selected property of option
elements. This means that when a render is triggered by the digest cycle, and the list of options
is being rendered, the selected properties are reset to the values from the model and the option
hovered over changes. This fix changes the code to only use DOM elements' selected properties in a
comparison when a change event has been fired. Otherwise, the internal new and existing option
arrays are used.
Closes#2448Closes#5994
The orderBy filter now allows string predicates passed to the orderBy filter to make use property
name predicates containing non-ident strings, such as spaces or percent signs, or non-latin
characters.
This behaviour requires the predicate string to be double-quoted.
In markup, this might look like so:
```html
<div ng-repeat="item in items | orderBy:'\"Tip %\"'">
...
</div>
```
Or in JS:
```js
var sorted = $filter('orderBy')(array, ['"Tip %"', '-"Subtotal $"'], false);
```
Closes#6143Closes#6144
Previously, non-string values stored in $cookies would be removed, without warning the user, and
causing difficulty debugging. Now, the value is converted to string before being stored, and the
value is not dropped. Serialization may be customized using the toString() method of an object's
prototype.
Closes#6151Closes#6220
Fix click busting of input click triggered by a label click quickly
following a touch event on a different element, in desktop
and mobile WebKit
To reproduce the issue fixed by this commit set up a page with
- an element with ng-click
- a radio button (with hg-model) and associated label
In a quick sequence tap on the element and then on the label.
The radio button will not be checked, unless PREVENT_DURATION has passed
Closes#6302
This change brings Angular's JSONP behaviour closer in line with jQuery's. It will no longer treat
a callback called with no data as an error, and will no longer support IE8 via the onreadystatechanged
event.
BREAKING CHANGE:
Previously, the JSONP backend code would support IE8 by relying on the readystatechanged events. This
is no longer the case, as these events do not provide adequate useful information for deeming whether
or not a response is an error.
Previously, a JSONP response which did not pass data into the callback would be given a status of -2,
and treated as an error. Now, this situation will instead be given a status of 200, despite the lack
of data. This is useful for interaction with certain APIs.
Previously, the onload and onerror callbacks were added to the JSONP script tag. These have been
replaced with jQuery events, in order to gain access to the event object. This means that it is now
difficult to test if the callbacks are registered or not. This is possible with jQuery, using the
$.data("events") method, however it is currently impossible with jqLite. This is not expected to
break applications.
Closes#4987Closes#6735
It's now possible to pass a function to match the URL in $httpBackend mocked
expectations. This gives a more sophisticate control over the URL matching
without requiring complex RegExp mantainance or the workaround of creating
an object with a `test` function in order to mimic RegExp interface.
This approach was suggested in [this
thread](https://groups.google.com/d/msg/angular/3QsCUEvvxlM/Q4C4ZIqNIuEJ)
Closes#4580
In order to make the behavior compatible with $rootScope.$watch and $rootScope.$on methods, and
make it possible to deregister an attribute observer, Attributes.$observe method now returns a
deregistration function instead of the observer itself.
BREAKING CHANGE: calling attr.$observe no longer returns the observer function, but a
deregistration function instead.
To migrate the code follow the example below:
Before:
```
directive('directiveName', function() {
return {
link: function(scope, elm, attr) {
var observer = attr.$observe('someAttr', function(value) {
console.log(value);
});
}
};
});
```
After:
```
directive('directiveName', function() {
return {
link: function(scope, elm, attr) {
var observer = function(value) {
console.log(value);
};
attr.$observe('someAttr', observer);
}
};
});
```
Closes#5609
Originally we destroyed the oldValue by incrementaly copying over portions of the newValue
into the oldValue during dirty-checking, this resulted in oldValue to be equal to newValue
by the time we called the watchCollection listener.
The fix creates a copy of the newValue each time a change is detected and then uses that
copy *the next time* a change is detected.
To make `$watchCollection` behave the same way as `$watch`, during the first iteration
the listener is called with newValue and oldValue being identical.
Since many of the corner-cases are already covered by existing tests, I refactored the
test logging to include oldValue and made the tests more readable.
Closes#2621Closes#5661Closes#5688Closes#6736
`log.empty()` is the same as `log.reset()`, except thati `empty()` also returns the current array with messages
instead of:
```
// do work
expect(log).toEqual(['bar']);
log.reset();
```
do:
```
// do work
expect(log.empty()).toEqual(['bar']);
```
If dealing with a document fragment node with a host element, and no parent, use the host
element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
to lookup parent controllers.
Closes#6637
PR #5547 introduced conversion of all 0 status codes to 404 for cases
where no response was recieved (previously this was done for the
file:// protocol only). But this mechanism is too eager and
masks legitimate cases where status 0 should be returned. This commits
reverts to the previous mechanism of handling 0 status code for the
file:// protocol (converting 0 to 404) while retaining the returned
status code 0 for all the protocols other than file://
Fixes#6074Fixes#6155
On older browser that don't support the new HTML5 inputs
and display a text input instead, the user is required to enter
the data in the corresponding ISO format. The value in `ng-model`
will always be a date.
E2e tests contain a workaround to a bug in webdriver,
see https://github.com/angular/protractor/issues/562.
Also adds weeks as format to the `dateFilter`.
Related to #757.
Closes#5864.