What Is New in AngularJS 1.6?
AngularJS 1.6 focuses on stability, aligning with modern promise standards, and refining the component lifecycle. This release introduces breaking changes for long-term health and adds several quality-of-life improvements.
| Category | Key Changes |
|---|---|
| Breaking Changes | Default `$location` hash prefix changed to `'!'`. `$http` success/error methods removed in favor of `then`/`catch`. Pre-assigning bindings on `$compile` is now disabled by default. |
| New Features | New `$onInit` lifecycle hook for components. `ngModelOptions` supports `allowInvalid`. New `$templateRequest` service and `$compileProvider.preAssignBindingsEnabled`. |
| Improvements | Better error messages for common mistakes. `ngAnimate` CSS-driven animations are more consistent. `$http` uses native ES2015 promises where available. |
| Deprecations | `$http`'s `success()` and `error()` methods are deprecated. The `ng-click` and other event directives expression execution order changed. |
Why did the $http service change in AngularJS 1.6?
The `$http` service was updated to use standard ES2015 promise semantics. The legacy `success` and `error` callback methods were removed, requiring the use of `then` and `catch`.
This matters because it aligns AngularJS with the native Promise API, making code more portable and consistent with other libraries. In practice, you must update your callbacks:
$http.get('/api/data').then(function(response) {
// Handle data via response.data
}).catch(function(error) {
// Handle error
});
What's the deal with the new $location hash prefix?
The default hash prefix for the `$location` service changed from an empty string to `'!'`. This is a breaking change for applications using hashbang URLs (`#/path`).
This change was made for SEO compatibility and to better distinguish hash fragments used for routing from those used for page anchors. You can revert to the old behavior by configuring `$locationProvider.hashPrefix('')`.
How does the new $onInit lifecycle hook help?
The `$onInit` hook provides a defined place for initialization logic in components and directives. It runs after all controllers on the element have been constructed and after their bindings are assigned.
In practice, this solves the problem of accessing bindings that were undefined in the controller's constructor function. You can now move initialization code from the constructor into `$onInit`.
angular.module('app').component('myComp', {
bindings: { input: '<' },
controller: function() {
this.$onInit = function() {
// this.input is now guaranteed to be available
};
}
});
What changed with binding pre-assignment in $compile?
Pre-assigning component bindings before the controller constructor runs is now disabled by default. This was a common source of bugs where bindings appeared as `undefined` in the constructor.
This change pushes developers toward using the `$onInit` hook for reliable initialization. You can re-enable the old behavior globally via `$compileProvider.preAssignBindingsEnabled(true)`, but it's not recommended for new code.
Are there any ngModel validation improvements?
Yes, `ngModelOptions` now includes an `allowInvalid` option. This allows a model to temporarily hold invalid values, which is useful for validation that requires async server calls or complex user input flows.
Before this, invalid input would immediately clear the model value. With `allowInvalid: true`, the model can reflect the invalid view value until validation passes, giving you more control.
FAQ
My $http calls broke after upgrading. What's the quick fix?
Replace all uses of `.success(callback)` and `.error(callback)` with `.then(callback)` and `.catch(callback)`. The callback argument changes from a decomposed object (data, status, headers, config) to a single response object where the data is on `response.data`.
My URLs suddenly have a bang (!) in them. How do I remove it?
Inject `$locationProvider` into your app config and set the hash prefix to an empty string: `$locationProvider.hashPrefix('')`. This restores the pre-1.6 behavior.
Should I use $onInit instead of my controller's constructor?
Yes, for any initialization logic that depends on bindings. Bindings are guaranteed to be available inside `$onInit`, while they may be `undefined` in the constructor. Keep lightweight setup in the constructor if needed.
Why are my component bindings undefined in the constructor now?
Because `preAssignBindingsEnabled` defaults to `false` in 1.6. Either move your code to the `$onInit` lifecycle hook (recommended) or enable the old behavior via `$compileProvider.preAssignBindingsEnabled(true)` in your config phase.
Did the order of ng-click expression execution change?
Yes. In 1.5, `ng-click` and similar event directives executed the expression before checking if the element was disabled. In 1.6, it checks for the `disabled` property first. This aligns with standard browser behavior but could break apps relying on the old order.