# 1.6.0-rc.0 bracing-vortex (2016-10-26) ## Major notes Please read the [Sandbox Removal Blog Post](http://angularjs.blogspot.com/2016/09/angular-16-expression-sandbox-removal.html). ## Bug Fixes - **input:** fix `step` validation for `input[type=number]`/`input[type=range]` ([081d06](https://github.com/angular/angular.js/commit/081d06ffd15c2c6c539ce97b5eb63fa8e2403818) [#15257](https://github.com/angular/angular.js/issues/15257)) - **jqLite:** - camelCase keys in `jqLite#data` ([fc0c11](https://github.com/angular/angular.js/commit/fc0c11db845d53061430b7f05e773dcb3fb5b860) [#15126](https://github.com/angular/angular.js/issues/15126)) - align jqLite camelCasing logic with JQuery ([73050c](https://github.com/angular/angular.js/commit/73050cdda04675bfa6705dc841ddbbb6919eb048) [#7744](https://github.com/angular/angular.js/issues/7744)) - **$parse:** - treat falsy values as defined in assignment expressions ([4f44e0](https://github.com/angular/angular.js/commit/4f44e018948c45bfb07f0170de4f703d22778d71)) - call once stable bind-once expressions with filter ([3b5751](https://github.com/angular/angular.js/commit/3b5751dce8d6c699dc76e47cfa544c30b38b9771)) - Handle sign of `-undefined` consistently ([c1eaf3](https://github.com/angular/angular.js/commit/c1eaf3480b9a88e5309ff4931a720f3f62bd7606)) - **ngModel:** treat synchronous validators as boolean always ([7bc71a](https://github.com/angular/angular.js/commit/7bc71adc63bb6bb609b44dd2d3ea8fb0cd3f300b) [#14734](https://github.com/angular/angular.js/issues/14734)) - **$q:** treat thrown errors as regular rejections ([e13eea](https://github.com/angular/angular.js/commit/e13eeabd7e34a78becec06cfbe72c23f2dcb85f9) [#3174](https://github.com/angular/angular.js/issues/3174) [#15213](https://github.com/angular/angular.js/issues/15213)) - **ngTransclude:** use fallback content if only whitespace is provided ([32aa7e](https://github.com/angular/angular.js/commit/32aa7e7395527624119e3917c54ee43b4d219301) [#15077](https://github.com/angular/angular.js/issues/15077)) - **$compile:** - don't throw tplrt error when there is a whitespace around a top-level comment ([76d3da](https://github.com/angular/angular.js/commit/76d3dafdeaf2f343d094b5a34ffb74adf64bb284) [#15108](https://github.com/angular/angular.js/issues/15108)) - disallow linking the same element more than once ([1e1fbc](https://github.com/angular/angular.js/commit/1e1fbc75f5e20e8541f517a5cf6f30f8f2eed53f)) - lower the $sce context for src on video, audio, and track. ([ad9a99](https://github.com/angular/angular.js/commit/ad9a99d6895e1c07c950f7141bb0edfc1d4aaf61)) - correctly merge consecutive text nodes on IE11 ([13c252](https://github.com/angular/angular.js/commit/13c2522baf7c8f616b2efcaab4bffd54c8736591) [#14924](https://github.com/angular/angular.js/issues/14924)) - secure `link[href]` as a `RESOURCE_URL`s in `$sce`. ([04cad4](https://github.com/angular/angular.js/commit/04cad41d26ebaf44b5ee0c29a152d61f235f3efa) [#14687](https://github.com/angular/angular.js/issues/14687)) - don't add leading white-space in attributes for a specific merge case ([305ba1](https://github.com/angular/angular.js/commit/305ba1a3fb3529cb3fdf04c12ac03fbb4f634456)) - don't trim white-space in attributes ([97bbf8](https://github.com/angular/angular.js/commit/97bbf86a1979d099802f0d631c17c54b87563b40) [#5513](https://github.com/angular/angular.js/issues/5513) [#5597](https://github.com/angular/angular.js/issues/5597)) - move check for interpolation of on-event attributes to compile time ([b89c21](https://github.com/angular/angular.js/commit/b89c2181a9a165e06c027390164e08635ec449f4) [#13267](https://github.com/angular/angular.js/issues/13267)) - **select:** - add/remove selected attribute for selected/unselected options ([c75698](https://github.com/angular/angular.js/commit/c75698df55f5a026bcd7fcecbb9d4ff0bc3ebc3e)) - don't register options when select has no ngModel ([e8c2e1](https://github.com/angular/angular.js/commit/e8c2e119758e58e18fe43932d09a8ff9f506aa9d)) - handle model updates when options are manipulated ([47c15f](https://github.com/angular/angular.js/commit/47c15fbcc10f118170813021e8e605ffd263ad84)) - remove workaround for Chrome bug ([87eff2](https://github.com/angular/angular.js/commit/87eff27e971414fb163e2b5a7cfe78cb097a1951)) - **select, ngOptions:** make the handling of unknown / empty options consistent ([2785ad](https://github.com/angular/angular.js/commit/2785ad72599ca5f9558a116baecd83a5bebe3292)) - **ngValue:** set the element's value property in addition to the value attribute ([e6afca](https://github.com/angular/angular.js/commit/e6afca00c9061a3e13b570796ca3ab428c1723a1) [#14031](https://github.com/angular/angular.js/issues/14031)) - **aria/ngModel:** do not overwrite the default `$isEmpty()` method for checkboxes ([975a61](https://github.com/angular/angular.js/commit/975a6170efceb2a5e6377c57329731c0636eb8c8) [#14621](https://github.com/angular/angular.js/issues/14621)) - **$resource:** - fulfill promise with the correct value on error ([5f6949](https://github.com/angular/angular.js/commit/5f6949fdae57b15340c1213cce379c6e6f8aff62) [#14837](https://github.com/angular/angular.js/issues/14837)) - pass all extra, owned properties as params ([acb545](https://github.com/angular/angular.js/commit/acb545ec3ebf099db68561033645941c900973b5) [#14866](https://github.com/angular/angular.js/issues/14866)) - add semicolon to whitelist of delimiters to unencode in URL params ([2456ab](https://github.com/angular/angular.js/commit/2456ab63a613902d21c151445f9c697a76ab43b3)) - **$http:** - avoid `Possibly Unhandled Rejection` error when the request fails ([47583d](https://github.com/angular/angular.js/commit/47583d98005f6a498d397dbe2cedaadac69f0b47) [#13869](https://github.com/angular/angular.js/issues/13869)) - properly increment/decrement `$browser.outstandingRequestCount` ([4f6f2b](https://github.com/angular/angular.js/commit/4f6f2bce4ac93b85320e42e5023c09d099779b7d) [#13782](https://github.com/angular/angular.js/issues/13782) [#14921](https://github.com/angular/angular.js/issues/14921)) - **ngMock:** trigger digest in `$httpBackend.verifyNoOutstandingRequest()` ([267ee9](https://github.com/angular/angular.js/commit/267ee9c892b0eb40908700ee2435793f8c6c1c84) [#13506](https://github.com/angular/angular.js/issues/13506)) - **ngAria:** - bind to `keydown` instead of `keypress` in `ngClick` ([ad41ba](https://github.com/angular/angular.js/commit/ad41baa1fdc057db3fe529ff87735b173b164b4c) [#14063](https://github.com/angular/angular.js/issues/14063)) - don't add roles to native control elements ([9978de](https://github.com/angular/angular.js/commit/9978de11b7295fec1a2f4cb8fbeb9b62b54cb711) [#14076](https://github.com/angular/angular.js/issues/14076)) - **ngBind:** use same string representation as `$interpolate` ([fa80a6](https://github.com/angular/angular.js/commit/fa80a61a05a3b49a2c770d5544cb8480907a18d3)) - **ngMock/$httpBackend:** fail if a url is provided but is `undefined` ([7551b8](https://github.com/angular/angular.js/commit/7551b8975a91ee286cc2cf4af5e78f924533575e) [#8442](https://github.com/angular/angular.js/issues/8442) [#10934](https://github.com/angular/angular.js/issues/10934)) - **$route:** don't process route change controllers and templates for `redirectTo` routes ([7f4b35](https://github.com/angular/angular.js/commit/7f4b356c2bebb87f0c26b57a20415b004b20bcd1) [#3332](https://github.com/angular/angular.js/issues/3332)) - **loader:** `module.decorator` order of operations is now irrelevant ([6a2ebd](https://github.com/angular/angular.js/commit/6a2ebdba5df27e789e3cb10f11eedf90f7b9b97e) [#12382](https://github.com/angular/angular.js/issues/12382)) - **ngAnimate:** make svg elements work with `classNameFilter` ([81bf7e](https://github.com/angular/angular.js/commit/81bf7ed73ee67f9eb997da869c52839449ca02b3)) ## New Features - **jqLite:** - implement `jqLite(f)` as alias to `jqLite(document).ready(f)` ([369fb7](https://github.com/angular/angular.js/commit/369fb7f4f73664bcdab0350701552d8bef6f605e)) - don't throw for elements with missing `getAttribute` ([4e6c14](https://github.com/angular/angular.js/commit/4e6c14dcae4a9a30b3610a288ef8d20db47c4417)) - don't remove a boolean attribute for `.attr(attrName, '')` ([3faf45](https://github.com/angular/angular.js/commit/3faf4505732758165083c9d21de71fa9b6983f4a)) - remove the attribute for `.attr(attribute, null)` ([4e3624](https://github.com/angular/angular.js/commit/4e3624552284d0e725bf6262b2e468cd2c7682fa)) - return `[]` for `.val()` on `` with no selection For 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: ``` ``` JavaScript: ``` var value = $element.val(); if (value) { /* do something */ } ``` After: HTML: ``` ``` JavaScript: ``` var value = $element.val(); if (value.length > 0) { /* do something */ } ``` ### `ngModel` due to: - **[7bc71a](https://github.com/angular/angular.js/commit/7bc71adc63bb6bb609b44dd2d3ea8fb0cd3f300b)**: treat synchronous validators as boolean always Previously, only a literal `false` return would resolve as the synchronous validator failing. Now, all traditionally false 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. - **[9e24e7](https://github.com/angular/angular.js/commit/9e24e774a558143b3478536911a3a4c1714564ba)**: change controllers to use prototype methods 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`. - **[975a61](https://github.com/angular/angular.js/commit/975a6170efceb2a5e6377c57329731c0636eb8c8)**: do not overwrite the default `$isEmpty()` method for checkboxes Custom `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: ```js var template = ''; 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: ```js var template = ''; 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: ```js .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: - **[b54a39](https://github.com/angular/angular.js/commit/b54a39e2029005e0572fbd2ac0e8f6a4e5d69014)**: remove deprecated callback methods: `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: ```js $http(...). success(function onSuccess(data, status, headers, config) { // Handle success ... }). error(function onError(data, status, headers, config) { // Handle error ... }); ``` After: ```js $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()`. - **[fb6634](https://github.com/angular/angular.js/commit/fb663418710736161a6b5da49c345e92edf58dcb)**: JSONP callback must be specified by `jsonpCallbackParam` config You 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'}); ``` - **[6476af](https://github.com/angular/angular.js/commit/6476af83cd0418c84e034a955b12a842794385c4)**: JSONP requests now require a trusted resource URL 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)); ``` - **[4f6f2b](https://github.com/angular/angular.js/commit/4f6f2bce4ac93b85320e42e5023c09d099779b7d)**: properly increment/decrement `$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: - **[e13eea](https://github.com/angular/angular.js/commit/e13eeabd7e34a78becec06cfbe72c23f2dcb85f9)**: treat thrown errors as regular rejections 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. - **[c9dffd](https://github.com/angular/angular.js/commit/c9dffde1cb167660120753181cb6d01dc1d1b3d0)**: report promises with non rejection callback 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: - **[32aa7e](https://github.com/angular/angular.js/commit/32aa7e7395527624119e3917c54ee43b4d219301)**: use fallback content if only whitespace is provided 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. ### `ngModelOptions` due to: - **[87a2ff](https://github.com/angular/angular.js/commit/87a2ff76af5d0a9268d8eb84db5755077d27c84c)**: allow options to be inherited from ancestor `ngModelOptions` Previously, if a setting was not applied on `ngModelOptions`, then it would default to undefined. Now the setting will be inherited from the nearest ngModelOptions ancestor. It is possible that an `ngModelOptions` directive that does not set a property, has an ancestor ngModelOptions that does set this property to a value other than `undefined`. This would cause the `ngModel` and input controls below this `ngModelOptions` directive to display different behaviour. This is fixed by explictly setting the property in the `ngModelOptions` to prevent it from inheriting from the ancestor. For example if you had the following HTML: ```
``` Then before this change the input would update on the default event not blur. After this change the input will inherit the option to update on blur. If you want the original behaviour then you will need to specify the option on the input as well: ```
``` The programmatic API for `ngModelOptions` has changed. You must now read options via the `getOption` method, rather than accessing the option directly as a property of the 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. ### `$compile` due to: - **[13c252](https://github.com/angular/angular.js/commit/13c2522baf7c8f616b2efcaab4bffd54c8736591)**: correctly merge consecutive text nodes on IE11 **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 unexpectd side effects in the following cases: 1. Passing an array or jqLite/jQuery collection of parent-less text nodes to `$compile` directly: ```js // 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]; })); ``` 2. Using multi-slot transclusion with non-consecutive, default-content text nodes (that form interpolated expressions when merged): ```js // Assuming the following component: .compoent('someThing', { template: '' transclude: { ignored: 'veryImportantContent' } }) ``` ```html {{ Nooot 'foo'}} {{ <-- Two separate 'foo'}} <-- text nodes foo <-- The text nodes were merged into `{{'foo'}}`, which was then interpolated {{ Nooot 'foo'}} {{ <-- Two separate 'foo'}} <-- nodes ``` - **[b89c21](https://github.com/angular/angular.js/commit/b89c2181a9a165e06c027390164e08635ec449f4)**: move check for interpolation of on-event attributes to compile time Using interpolation in any on* event attributes (e.g. `