After you have upgraded from Angular 1.2 to 1.3 you need to use a few new features right away. These are simple to use and require only minimal code changes.
Turn on strict dependency injection
By default the AngularJS dependency injection reads the names of the things to inject from function's arguments list
1 | angulr.module('MyModule') |
This quickly breaks when the code is minified and the argument names are shortened
1 | angulr.module('MyModule') |
To prevent injection errors after code minification you can use explicit annotations, passing names of the arguments as an array of strings. The minification step does not change strings, thus preserving injection targets.
1 | // full source |
In Angular 1.2 you had no way of catching these errors unless you ran your unit tests against minified code too, and the unit tests had to cover every code path. There is ng-annotate module, but it is unreliable in detecting every method that needs to be wrapped in explicit annotations.
Luckily Angular 1.3 solves this problem. You can just flip the flag when bootstrapping your application and even unminified code will require explicit annotations, making finding problems earlier much simpler.
1 | <body ng-app="MyModule" ng-strict-di> |
That is it! If you bootstrap the application yourself, you can pass this as an option
1 | angular.bootstrap(document.body, ['MyModule'], { strictDi: true }); |
Remove debug info
Have you noticed all these class="ng-scope"
node attributes in your DOM? Angular adds these tags to enable
testing tools like Protractor and Batarang to run. But these also take time to generate and put into DOM.
Luckily these are simple to disable for extra performance boost.
1 | app.config(['$compileProvider', function ($compileProvider) { |
If you need debug info during debugging, like when executing Angular commands from the browser console or running code snippets, just execute the following call from the console first
1 | angular.reloadWithDebugInfo(); |
The page will be reloaded with all the debug DOM attributes.
Watch multiple scope expressions
If you watch multiple scope properties, and execute a listener function, you might execute it multiple times. For example
1 | $scope.minRent = 0; |
This happens because filterProperties
gets executed when each expression changes separately.
Instead we are interested if any expression changes.
1 | $scope.minRent = 0; |
The callback in this case receives a single combined list of changes as an array
1 | filterProperties(/* new values */ [0, 10000, 0, 5], |
See $watchGroup for more details.
Use controllerAs AND bindToController to get rid of scopes
I hope by now you use as many isolate scopes as possible. I also hope that you use controllerAs
syntax to
prevent accidental scope property overrides (see Binding to Directive Controllers as source
for the example below).
When using AngularJS 1.2 you had to watch isolate scope properties in order to update them on the controller and be able to use them for two way binding.
1 | app.directive('someDirective', function () { |
We had to watch name
because it was shared via two way binding from the parent scope and would not
be reflected in the template using ctrl.name
expression. The template shows ctrl.name
which lives in
the controller instance, which is separate from the $scope
object.
In Angular 1.3 you can tell the $compile
to actually bind isolate scope directly to the controller
without you managing the updates yourself.
1 | app.directive('someDirective', function () { |
Any changes to name
property in the parent scope will be reflected in the controller name
property and then
in the template. Same with the reverse - any updates to the ctrl.name
will be automatically propagating back
to the parent scope.
For more details on controllerAs
and bindToController
see Separate model from view in Angular.