Changelog
1.6.5 toffee-salinization (2017-07-03)
$timeout.flush()
in unit tests. See the commit message for
more info.customFilter
(ab114a,
#14891).component()
to accept object map of components
(210112,
#14579,
#16062)<a name="1.6.4"></a>
Changelog
1.6.4 phenomenal-footnote (2017-03-31)
format
string
(982271,
#15794,
#15792)<a name="1.6.3"></a>
Changelog
1.6.3 scriptalicious-bootstrapping (2017-03-08)
key.charAt
is not a function
(f27d19,
#15644,
#15660)$window
to be mocked in unit tests
(5ca0de,
#15685,
#15686)angularVersion
info to each module
(1e582e)modules
property
(742123)info()
method
(09ba69,
#15225)<a name="1.6.2"></a>
Changelog
1.6.2 llamacorn-lovehug (2017-02-07)
$digest
(b60761,
#11075,
#12571,
#15556,
#15561)history.state
(fa50fb)templateUrl
(f01212,
#15510,
#15514)history
for NW.js apps
(4a593d,
#15474,
#15633)step
validation for input[type=number/range]
(c95a67,
#15504,
#15506)ngModel
when selected option is recreated by ngRepeat
(131af8,
#15630,
#15632)value
property when value
is undefined
(05aab6
#15603,
#15605)$httpBackend
uses correct $browser
(bd63b2,
#15593)$overrideModelOptions
support
(2546c2,
#15415)<a name="1.5.11"></a>
Changelog
1.5.11 princely-quest (2017-01-13)
$cancelRequest()
in toJSON()
(4f3858,
#15244)document.cookie
(6933cf,
#15523,
#15532)<a name="1.6.1"></a>
Changelog
1.6.1 promise-rectification (2016-12-23)
document.cookie
(33f769,
#15523)selected
property unless necessary
(bc4844,
#15477)replace
directives
(5f8ed6,
#15492)$index
change simultaneously
(d52864)after()
if element has no parent
(3d68b9,
#15331,
#15475)<a name="1.5.10"></a>
Changelog
1.5.10 asynchronous-synchronization (2016-12-15)
@
-binding observers when re-assigning bindings
(f3cb6e,
#15268)ngAttr*
contains no interpolation
(229799,
#15133)bindToController
should work without controllerAs
(944989,
#15088)$onInit()
for <
-bound literals
(07e1ba,
#15118)$onChanges()
twice for NaN
initial values
(0cf5be)$digest
(a9708d,
#15422)adjustMatcher
to replace multiple *
and **
(78eecb)after()
if element has no parent
(77ed85,
#15331)$index
change simultaneously
(e3d020)$compileProvider.preAssignBindingsEnabled()
(75c83f)status
/statusText
to success callbacks
(a8da25,
#8341,
#8841)ngSwitchWhenSeparator
(0e1651,
#3410,
#3516)directive.restrict
property on directive init
(31d464)element.value
(e269ad)<a name="1.6.0"></a>
Changelog
1.6.0 rainbow-tsunami (2016-12-08)
Here are the full changes for the release of 1.6.0 that are not already released in the 1.5.x branch, consolidating all the changes shown in the previous 1.6.0 release candidates.
ngModelOptions
(296cfc,
#10922)jqLite(f)
as an alias to jqLite(document).ready(f)
(369fb7)getAttribute
(4e6c14).attr(attrName, '')
(3faf45).attr(attribute, null)
(4e3624)[]
for .val()
on <select multiple>
with no selection
(d882fd)jqLite#data
(fc0c11,
#15126)ngValue
(f02b70,
#9842)ngSwitchWhenSeparator
(0b221
#3410
#3516)toString()
function if present
(a5fd2e,
#7317,
#11406)status
/statusText
to success callbacks
(e3a378
#8341
#8841)adjustMatcher
to replace multiple *
and **
(991a2b)updateOn
triggers that are not in debounce list
(789790)$compileProvider.preAssignBindingsEnabled()
(7d9a79)step
validation for input[type=number]
/input[type=range]
(081d06,
#15257)@
-binding observers when re-assigning bindings
(586e2a
#15268)ngAttr*
contains no interpolation
(3fe3da
#15133)bindToController
should work without controllerAs
(16dcce
#15088)$onInit()
for <
-bound literals
(a1bdff
#15118)$onChanges()
twice for NaN
initial values
(7d7efb)ngIf
)
(7a667c)$httpBackend.verifyNoOutstandingRequest()
(267ee9,
#13506)$interpolate
(fa80a6)undefined
(7551b8,
#8442,
#10934)redirectTo
routes
(7f4b35,
#3332)module.decorator
order of operations is now irrelevant
(6a2ebd,
#12382)classNameFilter
(81bf7e)element.value
(3b7f29)Previously, $compileProvider.preAssignBindingsEnabled
was set to true by default. This means
bindings were pre-assigned on component/directive controller instances (which made them available
inside the constructors). In AngularJS 1.5+ the place to put the initialization logic relying on
bindings being present is the controller's $onInit
method.
To migrate follow the example below:
Before:
angular.module('myApp', [])
.component('myComponent', {
bindings: {value: '<'},
controller: function() {
this.doubleValue = this.value * 2;
}
});
After:
angular.module('myApp', [])
.component('myComponent', {
bindings: {value: '<'},
controller: function() {
this.$onInit = function() {
this.doubleValue = this.value * 2;
};
}
});
If you don't have time to migrate the code at the moment, you can flip the setting back to true:
angular.module('myApp', [])
.config(function($compileProvider) {
$compileProvider.preAssignBindingsEnabled(true);
})
.component('myComponent', {
bindings: {value: '<'},
controller: function() {
this.doubleValue = this.value * 2;
}
});
Don't do this if you're writing a library, though, as you shouldn't change global configuration then.
When using input[radio], the checked status is now determined by doing a strict comparison between the value of the input and the ngModel.$viewValue. Previously, this was a non-strict comparison (==).
This means in the following examples the radio is no longer checked:
<!-- this.selected = 0 -->
<input type="radio" ng-model="$ctrl.selected" value="0" >
<!-- this.selected = 0; this.value = false; -->
<input type="radio" ng-model="$ctrl.selected" ng-value="$ctrl.value" >
The migration strategy is to convert values that matched with non-strict conversion so that they will match with strict conversion.
ngModelOptions
(296cfc):The programmatic API for ngModelOptions
has changed. You must now read options
via the ngModelController.$options.getOption(name)
method, rather than accessing the
option directly as a property of the ngModelContoller.$options
object. This does not
affect the usage in templates and only affects custom directives that might have been
reading options for their own purposes.
One benefit of these changes, though, is that the ngModelControler.$options
property
is now guaranteed to be defined so there is no need to check before accessing.
So, previously:
var myOption = ngModelController.$options && ngModelController.$options['my-option'];
and now:
var myOption = ngModelController.$options.getOption('my-option');
jqLite#data
Previously, keys passed to the data method were left untouched.
Now they are internally camelCased similarly to how jQuery handles it, i.e.
only single (!) hyphens followed by a lowercase letter get converted to an
uppercase letter. This means keys a-b
and aB
represent the same data piece;
writing to one of them will also be reflected if you ask for the other one.
If you use Angular with jQuery, it already behaved in this way so no changes are required on your part.
To migrate the code follow the examples below:
BEFORE:
/* 1 */
elem.data('my-key', 2);
elem.data('myKey', 3);
/* 2 */
elem.data('foo-bar', 42);
elem.data()['foo-bar']; // 42
elem.data()['fooBar']; // undefined
/* 3 */
elem.data()['foo-bar'] = 1;
elem.data()['fooBar'] = 2;
elem.data('foo-bar'); // 1
AFTER:
/* 1 */
// Rename one of the keys as they would now map to the same data slot.
elem.data('my-key', 2);
elem.data('my-key2', 3);
/* 2 */
elem.data('foo-bar', 42);
elem.data()['foo-bar']; // undefined
elem.data()['fooBar']; // 42
/* 3 */
elem.data()['foo-bar'] = 1;
elem.data()['fooBar'] = 2;
elem.data('foo-bar'); // 2
Before, when Angular was used without jQuery, the key passed to the css method was more heavily camelCased; now only a single (!) hyphen followed by a lowercase letter is getting transformed. This also affects APIs that rely on the css method, like ngStyle.
If you use Angular with jQuery, it already behaved in this way so no changes are needed on your part.
To migrate the code follow the example below:
Before:
HTML:
// All five versions used to be equivalent.
<div ng-style={background_color: 'blue'}></div>
<div ng-style={'background:color': 'blue'}></div>
<div ng-style={'background-color': 'blue'}></div>
<div ng-style={'background--color': 'blue'}></div>
<div ng-style={backgroundColor: 'blue'}></div>
JS:
// All five versions used to be equivalent.
elem.css('background_color', 'blue');
elem.css('background:color', 'blue');
elem.css('background-color', 'blue');
elem.css('background--color', 'blue');
elem.css('backgroundColor', 'blue');
// All five versions used to be equivalent.
var bgColor = elem.css('background_color');
var bgColor = elem.css('background:color');
var bgColor = elem.css('background-color');
var bgColor = elem.css('background--color');
var bgColor = elem.css('backgroundColor');
After:
HTML:
// Previous five versions are no longer equivalent but these two still are.
<div ng-style={'background-color': 'blue'}></div>
<div ng-style={backgroundColor: 'blue'}></div>
JS:
// Previous five versions are no longer equivalent but these two still are.
elem.css('background-color', 'blue');
elem.css('backgroundColor', 'blue');
// Previous five versions are no longer equivalent but these two still are.
var bgColor = elem.css('background-color');
var bgColor = elem.css('backgroundColor');
Previously, all boolean attributes were reflected into the corresponding property when calling a setter and from the corresponding property when calling a getter, even on elements that don't treat those attributes in a special way. Now Angular doesn't do it by itself, but relies on browsers to know when to reflect the property. Note that this browser-level conversion differs between browsers; if you need to dynamically change the state of an element, you should modify the property, not the attribute. See https://jquery.com/upgrade-guide/1.9/#attr-versus-prop- for a more detailed description about a related change in jQuery 1.9.
This change aligns jqLite with jQuery 3. To migrate the code follow the example below:
Before:
CSS:
input[checked="checked"] { ... }
JS:
elem1.attr('checked', 'checked');
elem2.attr('checked', false);
After:
CSS:
input:checked { ... }
JS:
elem1.prop('checked', true);
elem2.prop('checked', false);
.attr(attrName, '')
Before, using the attr
method with an empty string as a value
would remove the boolean attribute. Now it sets it to its lowercase name as
was happening for every non-empty string so far. The only two values that remove
the boolean attribute are now null & false, just like in jQuery.
To migrate the code follow the example below:
Before:
elem.attr(booleanAttrName, '');
After:
elem.attr(booleanAttrName, false);
or:
elem.attr(booleanAttrName, null);
.attr(attribute, null)
Invoking elem.attr(attributeName, null)
would set the
attributeName
attribute value to a string "null"
, now it removes the
attribute instead.
To migrate the code follow the example below:
Before:
elem.attr(attributeName, null);
After:
elem.attr(attributeName, "null");
<select multiple>
with no selectionFor the jqLite element representing a select element in the multiple variant with no options chosen the .val() getter used to return null and now returns an empty array.
To migrate the code follow the example below:
Before:
HTML:
<select multiple>
<option>value 1</option>
<option>value 2</option>
</select>
JavaScript:
var value = $element.val();
if (value) {
/* do something */
}
After:
HTML:
<select multiple>
<option>value 1</option>
<option>value 2</option>
</select>
JavaScript:
var value = $element.val();
if (value.length > 0) {
/* do something */
}
ngModel
due to:Previously, only a literal false
return would resolve as the
synchronous validator failing. Now, all falsy JavaScript values
are treated as failing the validator, as one would naturally expect.
Specifically, the values 0
(the number zero), null
, NaN
and ''
(the
empty string) used to be considered valid (passing) and they are now considered
invalid (failing). The value undefined
was treated similarly to a pending
asynchronous validator, causing the validation to be pending. undefined
is
also now considered invalid.
To migrate, make sure your synchronous validators are returning either a
literal true
or a literal false
value. For most code, we expect this to
already be the case. Only a very small subset of projects will be affected.
Namely, anyone using undefined
or any falsy value as a return will now see
their validation failing, whereas previously falsy values other than undefined
would have been seen as passing and undefined
would have been seen as pending.
The use of prototype methods instead of new methods per instance removes the ability to pass NgModelController and FormController methods without context.
For example
$scope.$watch('something', myNgModelCtrl.$render)
will no longer work because the $render
method is passed without any context.
This must now be replaced with
$scope.$watch('something', function() {
myNgModelCtrl.$render();
})
or possibly by using Function.prototype.bind
or angular.bind
.
aria/ngModel
due to:$isEmpty()
method for checkboxesCustom checkbox
-shaped controls (e.g. checkboxes, menuitemcheckboxes), no longer have a custom
$isEmpty()
method on their NgModelController
that checks for value === false
. Unless
overwritten, the default $isEmpty()
method will be used, which treats undefined
, null
, NaN
and ''
as "empty".
Note: The $isEmpty()
method is used to determine if the checkbox is checked ("not empty" means
"checked") and thus it can indirectly affect other things, such as the control's validity
with respect to the required
validator (e.g. "empty" + "required" --> "invalid").
Before:
var template = '<my-checkbox role="checkbox" ng-model="value"></my-checkbox>';
var customCheckbox = $compile(template)(scope);
var ctrl = customCheckbox.controller('ngModel');
scope.$apply('value = false');
console.log(ctrl.$isEmpty()); //--> true
scope.$apply('value = true');
console.log(ctrl.$isEmpty()); //--> false
scope.$apply('value = undefined'/* or null or NaN or '' */);
console.log(ctrl.$isEmpty()); //--> false
After:
var template = '<my-checkbox role="checkbox" ng-model="value"></my-checkbox>';
var customCheckbox = $compile(template)(scope);
var ctrl = customCheckbox.controller('ngModel');
scope.$apply('value = false');
console.log(ctrl.$isEmpty()); //--> false
scope.$apply('value = true');
console.log(ctrl.$isEmpty()); //--> false
scope.$apply('value = undefined'/* or null or NaN or '' */);
console.log(ctrl.$isEmpty()); //--> true
--
If you want to have a custom $isEmpty()
method, you need to overwrite the default. For example:
.directive('myCheckbox', function myCheckboxDirective() {
return {
require: 'ngModel',
link: function myCheckboxPostLink(scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$isEmpty = function myCheckboxIsEmpty(value) {
return !value; // Any falsy value means "empty"
// Or to restore the previous behavior:
// return value === false;
};
}
};
})
$http
due to:success()/error()
$http
's deprecated custom callback methods - success()
and error()
- have been removed.
You can use the standard then()
/catch()
promise methods instead, but note that the method
signatures and return values are different.
success(fn)
can be replaced with then(fn)
, and error(fn)
can be replaced with either
then(null, fn)
or catch(fn)
.
Before:
$http(...).
success(function onSuccess(data, status, headers, config) {
// Handle success
...
}).
error(function onError(data, status, headers, config) {
// Handle error
...
});
After:
$http(...).
then(function onSuccess(response) {
// Handle success
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
}, function onError(response) {
// Handle error
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
});
// or
$http(...).
then(function onSuccess(response) {
// Handle success
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
}).
catch(function onError(response) {
// Handle error
var data = response.data;
var status = response.status;
var statusText = response.statusText;
var headers = response.headers;
var config = response.config;
...
});
Note:
There is a subtle difference between the variations showed above. When using
$http(...).success(onSuccess).error(onError)
or $http(...).then(onSuccess, onError)
, the
onError()
callback will only handle errors/rejections produced by the $http()
call. If the
onSuccess()
callback produces an error/rejection, it won't be handled by onError()
and might go
unnoticed. In contrast, when using $http(...).then(onSuccess).catch(onError)
, onError()
will
handle errors/rejections produced by both $http()
and onSuccess()
.
jsonpCallbackParam
configYou can no longer use the JSON_CALLBACK
placeholder in your JSONP requests.
Instead you must provide the name of the query parameter that will pass the
callback via the jsonpCallbackParam
property of the config object, or app-wide via
the $http.defaults.jsonpCallbackParam
property, which is "callback"
by default.
Before this change:
$http.json('trusted/url?callback=JSON_CALLBACK');
$http.json('other/trusted/url', {params: {cb:'JSON_CALLBACK'}});
After this change:
$http.json('trusted/url');
$http.json('other/trusted/url', {jsonpCallbackParam:'cb'});
All JSONP requests now require the URL to be trusted as resource URLs. There are two approaches to trust a URL:
Whitelisting with the $sceDelegateProvider.resourceUrlWhitelist()
method.
You configure this list in a module configuration block:
appModule.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow same origin resource loads.
'self',
// Allow JSONP calls that match this pattern
'https://some.dataserver.com/**.jsonp?**'
]);
}]);
Explicitly trusting the URL via the $sce.trustAsResourceUrl(url)
method.
You can pass a trusted object instead of a string as a URL to the $http
service:
var promise = $http.jsonp($sce.trustAsResourceUrl(url));
$browser.outstandingRequestCount
HTTP requests now update the outstanding request count synchronously. Previously the request count would not have been updated until the request to the server is actually in flight. Now the request count is updated before the async interceptor is called.
The new behaviour is correct but it may change the expected behaviour in a small number of e2e test cases where an async request interceptor is being used.
$q
due to:Previously, throwing an error from a promise's onFulfilled
or onRejection
handlers, would result
in passing the error to the $exceptionHandler()
(in addition to rejecting the promise with the
error as reason).
Now, a thrown error is treated exactly the same as a regular rejection. This applies to all
services/controllers/filters etc that rely on $q
(including built-in services, such as $http
and
$route
). For example, $http
's transformRequest/Response
functions or a route's redirectTo
function as well as functions specified in a route's resolve
object, will no longer result in a
call to $exceptionHandler()
if they throw an error. Other than that, everything will continue to
behave in the same way; i.e. the promises will be rejected, route transition will be cancelled,
$routeChangeError
events will be broadcasted etc.
Unhandled rejected promises will be logged to $exceptionHandler.
Tests that depend on specific order or number of messages in $exceptionHandler will need to handle rejected promises report.
ngTransclude
due to:Previously whitespace only transclusion would be treated as the transclusion being "not empty", which meant that fallback content was not used in that case.
Now if you only provide whitespace as the transclusion content, it will be assumed to be empty and the fallback content will be used instead.
If you really do want whitespace then you can force it to be used by adding a comment to the whitespace.
Previously this would not fallback to default content:
<some-component>
</some-component>
Now the whitespace between the opening and closing tags is treated as empty. To force the previous behaviour simply add a comment:
<some-component><!-- -->
</some-component>
$compile
due to:Note: Everything described below affects IE11 only.
Previously, consecutive text nodes would not get merged if they had no parent. They will now, which might have unexpected side effects in the following cases:
Passing an array or jqLite/jQuery collection of parent-less text nodes to $compile
directly:
// Assuming:
var textNodes = [
document.createTextNode('{{'),
document.createTextNode('"foo:"'),
document.createTextNode('}}')
];
var compiledNodes = $compile(textNodes)($rootScope);
// Before:
console.log(compiledNodes.length); // 3
console.log(compiledNodes.text()); // {{'foo'}}
// After:
console.log(compiledNodes.length); // 1
console.log(compiledNodes.text()); // foo
// To get the old behavior, compile each node separately:
var textNodes = [
document.createTextNode('{{'),
document.createTextNode('"foo"'),
document.createTextNode('}}')
];
var compiledNodes = angular.element(textNodes.map(function (node) {
return $compile(node)($rootScope)[0];
}));
Using multi-slot transclusion with non-consecutive, default-content text nodes (that form interpolated expressions when merged):
// Assuming the following component:
.component('someThing', {
template: '<ng-transclude><!-- Default content goes here --></ng-transclude>'
transclude: {
ignored: 'veryImportantContent'
}
})
<!-- And assuming the following view: -->
<some-thing>
{{
<very-important-content>Nooot</very-important-content>
'foo'}}
</some-thing>
<!-- Before: -->
<some-thing>
<ng-transclude>
{{ <-- Two separate
'foo'}} <-- text nodes
</ng-transclude>
</some-thing>
<!-- After: -->
<some-thing>
<ng-transclude>
foo <-- The text nodes were merged into `{{'foo'}}`, which was then interpolated
</ng-transclude>
</some-thing>
<!-- To (visually) get the old behavior, wrap top-level text nodes on -->
<!-- multi-slot transclusion directives into `<span>` elements; e.g.: -->
<some-thing>
<span>{{</span>
<very-important-content>Nooot</very-important-content>
<span>'foo'}}</span>
</some-thing>
<!-- Result: -->
<some-thing>
<ng-transclude>
<span>{{</span> <-- Two separate
<span>'foo'}}</span> <-- nodes
</ng-transclude>
</some-thing>
on-"event"
attributes to compile timeUsing interpolation in any on* event attributes (e.g. <button onclick="{{myVar}}">
) will now throw
the "nodomevents" error at compile time.
Previously the nodomevents was thrown at link time. The new behavior makes it consistent with
the "selmulti" error.
The breaking change should be rare, as it relates to incorrect API use that should not make it to
production apps in the first place.
link[href]
as a RESOURCE_URL
in $sce
link[href]
attributes are now protected via $sce
, which prevents interpolated
values that fail the RESOURCE_URL
context tests from being used in interpolation.
For example if the application is running at https://docs.angularjs.org
then the
following will fail:
<link href="{{ 'http://mydomain.org/unsafe.css' }}" rel="stylesheet">
By default, RESOURCE_URL
safe URLs are only allowed from the same domain and protocol
as the application document.
To use URLs from other domains and/or protocols, you may either whitelist them or
wrap it into a trusted value by calling $sce.trustAsResourceUrl(url)
.
White-space in attributes is no longer trimmed automatically. This includes leading and trailing white-space, and attributes that are purely white-space.
To migrate, attributes that require trimming must now be trimmed manually.
A common cases where stray white-space can cause problems is when attribute values are compared, for example in an $observer:
Before:
$attrs.$observe('myAttr', function(newVal) {
if (newVal === 'false') ...
});
To migrate, the attribute value should be trimmed manually:
$attrs.$observe('myAttr', function(newVal) {
if (newVal.trim() === 'false') ...
});
Note that $parse
trims expressions automatically, so attributes with expressions (e.g. directive
bindings) are unlikely to be affected by stray white-space.
ngRoute
due to:ngView
to be included in an asynchronously loaded templateIn cases where ngView
was loaded asynchronously, $route
(and its dependencies; e.g. $location
)
might also have been instantiated asynchronously. After this change, $route
(and its dependencies)
will - by default - be instantiated early on.
Although this is not expected to have unwanted side-effects in normal application behavior, it may
affect your unit tests: When testing a module that (directly or indirectly) depends on ngRoute
, a
request will be made for the default route's template. If not properly "trained", $httpBackend
will complain about this unexpected request.
You can restore the previous behavior (and avoid unexpected requests in tests), by using
$routeProvider.eagerInstantiationEnabled(false)
.
redirectTo
routesThe $route service no longer instantiates controllers nor calls resolves or template functions
for routes that have a redirectTo
unless the redirectTo
is a function that returns
undefined
.
resolveRedirectTo
Previously, if redirectTo
was a function that threw an Error, execution was aborted without firing
a $routeChangeError
event.
Now, if a redirectTo
function throws an Error, a $routeChangeError
event will be fired.
ngMock
due to:$httpBackend.verifyNoOutstandingRequest()
Calling $httpBackend.verifyNoOutstandingRequest()
will trigger a digest. This will ensure that
requests fired asynchronously will also be detected (without the need to manually trigger a digest).
This is not expected to affect the majority of test-suites. Most of the time, a digest is (directly
or indirectly) triggered anyway, before calling verifyNoOutstandingRequest()
.
In the unlikely case that a test needs to verify the timing of a request with respect to the digest
cycle, you should rely on other means, such as mocking and/or spying.
undefined
It is no longer valid to explicitly pass undefined
as the url
argument
to any of the $httpBackend.when...()
and $httpBackend.expect...()
methods.
While this argument is optional, it must have a defined value if it is provided.
Previously passing an explicit undefined
value was ignored but this
lead to invalid tests passing unexpectedly.
ngAria
due to:keydown
instead of keypress
in ngClick
If you were explicitly setting the value of the bindKeypress
flag, you need to change your code to
use bindKeydown
instead.
Before: $ariaProvider.config({bindKeypress: xyz})
After: $ariaProvider.config({bindKeydown: xyz})
Note:
If the element already has any of the ngKeydown
/ngKeyup
/ngKeypress
directives, ngAria
will
not bind to the keydown
event, since it assumes that the developer has already taken care of
keyboard interaction for that element.
Although it is not expected to affect many applications, it might be desirable to keep the previous
behavior of binding to the keypress
event instead of the keydown
. In that case, you need to
manually use the ngKeypress
directive (in addition to ngClick
).
Before:
<div ng-click="onClick()">
I respond to `click` and `keypress` (not `keydown`)
</div>
After:
<div ng-click="onClick()" ng-keypress="onClick()">
I respond to `click` and `keypress` (not `keydown`)
</div>
<!-- OR -->
<div ng-click="onClick()">
I respond to `click` and `keydown` (not `keypress`)
</div>
Finally, it is possible that this change affects your unit or end-to-end tests. If you are currently
expecting your custom buttons to automatically respond to the keypress
event (due to ngAria
),
you need to change the tests to trigger keydown
events instead.
ngAria will no longer add the "role" attribute to native control elements (textarea, button, select, summary, details, a, and input). Previously, "role" was not added to input, but all others in the list.
This should not affect accessibility, because native inputs are accessible by default, but it might affect applications that relied on the "role" attribute being present (e.g. for styling or as directive attributes).
$resource
due to:All owned properties of the params
object that are not used to replace URL params, will be passed
to $http
as config.params
(to be used as query parameters in the URL), even if
Object.prototype
has a property with the same name. E.g.:
Before:
var Foo = $resource('/foo/:id');
Foo.get({id: 42, bar: 'baz', toString: 'hmm'});
// URL: /foo/42?bar=baz
// Note that `toString` is _not_ included in the query,
// because `Object.prototype.toString` is defined :(
After:
var Foo = $resource('/foo/:id');
Foo.get({id: 42, bar: 'baz', toString: 'hmm'});
// URL: /foo/42?bar=baz&toString=hmm
// Note that `toString` _is_ included in the query, as expected :)
Although it shouldn't matter in practice (since both the encoded and the unencoded ;
character would
be interpreted identically by the server), this change could break some tests: For example, where
$httpBackend
was set up to expect an encoded ;
character, but the request is made to the URL with an
unencoded ;
character.
select
due to:ngValue
<option>
elements added to <select ng-model>
via ngValue
now add their values in hash form, i.e.
<option ng-value="myString">
becomes <option ng-value="myString" value="string:myString">
.
This is done to support binding options with values of any type to selects.
This should rarely affect applications, as the values of options are usually not relevant to the application logic, but it's possible that option values are checked in tests.
ngModel
Option elements will no longer set their value attribute from their text value when their select element has no ngModel associated. Setting the value is only needed for the select directive to match model values and options. If no ngModel is present, the select directive doesn't need it.
This should not affect many applications as the behavior was undocumented and not part of a public API. It also has no effect on the usual HTML5 behavior that sets the select value to the option text if the option does not provide a value attribute.
ngBind
due to:ngBind
now uses the same logic as $interpolate (i.e. {{myString}}) when
binding, which means values other than strings are now transformed as following:
Previously, ngBind would always use toString().
The following examples show the different output:
$scope.myPlainObject = {a: 1, b: 2};
$scope.myCustomObject = {a: 1, b: 2, toString: function() {return 'a+b';}};
Plain Object:
<!-- Before: -->
<span ng-bind="myPlainObject">[object Object]</span>
<!-- After: -->
<span ng-bind="myPlainObject">{'a':1,'b':2}</span>
Object with custom toString():
<!-- Before: -->
<span ng-bind="myCustomObject">[object Object]</span>
<!-- After: -->
<span ng-bind="myCustomObject">a+b</span>
If you want the output of toString()
, you can use it directly on the value in ngBind:
<span ng-bind="myObject.toString()">[object Object]</span>
$interpolate
due to:toString()
function if presentWhen converting values to strings, interpolation now uses a custom toString() function on objects
that are not Number, Array or Date (custom means that the toString
function is not the same as
Object.prototype.toString
). Otherwise, interpolation uses JSON.stringify() as usual.
Should you have a custom toString() function but still want the output of JSON.stringify(), migrate as shown in the following examples:
Before:
<span>{{myObject}}</span>
After - use the json
filter to stringify the object:
<span>{{myObject | json}}</span>
loader
due to:module.decorator
declarations are now processed as part of the module.config
queue and may result in providers being decorated in a different order if
module.config
blocks are also used to decorate providers via
$provide.decorator
.
For example, consider the following declaration order in which 'theFactory' is
decorated by both a module.decorator
and a $provide.decorator
:
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.config(function($provide) {
$provide.decorator('theFactory', provideDecoratorFn);
})
.decorator('theFactory', moduleDecoratorFn);
Prior to this fix, 'theFactory' provider would be decorated in the following order:
The result of this fix changes the order in which 'theFactory' is decorated
because now module.decorator
declarations are processed in the same order as
module.config
declarations:
$location
due to:The hash-prefix for $location
hash-bang URLs has changed from the empty
string "" to the bang "!". If your application does not use HTML5 mode
or is being run on browsers that do not support HTML5 mode, and you have
not specified your own hash-prefix then client side URLs will now contain
a "!" prefix. For example, rather than mydomain.com/#/a/b/c
will become
mydomain.com/#!/a/b/c
.
If you actually wanted to have no hash-prefix then you should configure this by adding a configuration block to you application:
appModule.config(['$locationProvider', function($locationProvider) {
$locationProvider.hashPrefix('');
}]);
input[type=range]
due to:input[type=range]
Due to the way that input[type=range]
elements behave this feature modifies the behavior of such elements
when bound to ngModel
:
input[type=number]
, it requires the model to be a Number, and will set the model to a Numbernull
, undefined
, false
..., out of bounds: greater than max, less than min)
to a valid value, the input will in turn set the model to this new valid value via $setViewValue
.
input[type=range]
(IE9) handle the input like a number input (with validation etc.)input[type=number]
due to:step
to input[type=number]
Number inputs that use ngModel
and specify a step
constraint (via step
/ngStep
attributes)
will now have a new validator (step
), which will verify that the current value is valid under the
step
constraint (according to the spec).
Previously, the step
constraint was ignored by ngModel
, treating values as valid even when there
was a step-mismatch.
If you want to restore the previous behavior (use the step
attribute while disabling step
validation), you can overwrite the built-in step
validator with a custom directive. For example:
// For all `input` elements...
.directive('input', function() {
return {
restrict: 'E',
require: '?ngModel',
link: function (scope, elem, attrs, ngModelCtrl) {
// ...that are of type "number" and have `ngModel`...
if ((attrs.type === 'number') && ngModelCtrl) {
// ...remove the `step` validator.
delete ngModelCtrl.$validators.step;
}
}
};
})
<a name="1.6.0-rc.2"></a>
Changelog
1.5.9 timeturning-lockdown (2016-11-24)
This is an interim release primarily to publish some security fixes, in particular a modification to ensure that AngularJS can pass the linter checks for Mozilla add-ons.
history.pushState
in sandboxed Chrome Packaged Apps
(367da5)<a name="1.6.0-rc.1"></a>