...
Warning |
---|
Please dont use angular batarang (stable) plugin when checking for the watchers. This plugin is not the official one of Batarang. It gives the false count. |
One-time binding ( :: )
Angular brings in support for one way binding from 1.3 but there are more things. One-time binding can be used in cases where the expression will not change once the value is set.
For example:Code Block language xml title one-time binding <span>{{::patient.identifier}}</span>
Since patient's identifier wont change once set, it is a good candidate for one-time binding. Angular doc says,
"One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value ". There is a catch here. Watchers will stay alive till the expression is 'undefined'. As long as patient.identifier is undefined, watcher will be alive.Another example:
Code Block <span ng-if="::observation.isRequired()" class="asterick">*</span>
Code Block title observation.js isRequired: function () { return this.conceptUIConfig.required; },
In this example, if 'required' property is not present in conceptUIConifg, it will always return undefined and watcher will be alive always. Instead the condition can be changed to 'this.conceptUIConfig.required == true' .
Also we should pass attributes to directive as one-time binding wherever necessary.
Example:Code Block title Passing attributes to directive as one-time binding <section address-fields data-address-levels="::addressLevels" data-address="patient.address" field-validation="::fieldValidation"></section>
'address-levels' and 'field-validation' are read only attributes for 'address-fields' directive. i.e. It does not update anything in addressLevels and fieldValidation, so it can be added as one-time binding attributes.
Example: Here is a real-world example of a commit to improve performance in a display control by switching to one-time binding.
Directive's optional attributes
Angular directive can have attributes declared as optional using '=?'.
Lets say, we have a directive called 'attribute-types' with isolated scopeCode Block language js title attributeTypes.js scope : { targetModel : '=', attribute : '=', fieldValidation : '=', isAutoComplete: '&', getAutoCompleteList: '&', getDataResults: '&', isReadOnly: '&', isForm : '=' }
And it is used in two different places as follows:
Code Block language xml title Usage 1 <attribute-types target-model="patientProgram.patientProgramAttributes" attribute="attributeType"></attribute-types>
Code Block language xml title Usage 2 <attribute-types target-model="patient" attribute="::attribute" field-validation="::fieldValidation" is-auto-complete="isAutoComplete" get-auto-complete-list="getAutoCompleteList" get-data-results="getDataResults" is-read-only="isReadOnly"></attribute-types>
Usage 1 passes only two attributes and usage 2 passes more than two. So with the usage 1, attributes other than 'targetModel' and 'attribute' will be undefined. So watchers will be alive for the other attributes 'fieldValidation' and 'isForm'. To avoid this, those attributes can be marked as optional using '=?' instead of '='. When we do that, watcher will be added if attribute is passed and if it is not passed, no watcher will be added to the attribute.
Use track by with ng-repeat.
http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/Disable DebugInfo in production
Angular by default adds some classes like ng-binding, ng-scope, ng-isolate-scope to the DOM elements using jquery data property all the way through DOM hierarchy which takes some significant time while loading.
We can disable it in production using
Code Block language js title app.js $compileProvider.debugInfoEnabled(false);
More info on: https://docs.angularjs.org/guide/production
This gave us a significant performance boost.
Use css class to show and hide small elements instead of ng-if/ng-show
For example:
The arrow that we show in the image is used to indicate whether the section has been expanded or collapsed.
Instead of hiding and showing it using ng-show like below:Code Block <div toggle="displayPatientContactDetails"> <i class="fa fa-caret-right" ng-hide="displayPatientContactDetails"></i> <i class="fa fa-caret-down" ng-show="displayPatientContactDetails"></i> <span>Patient Contact Details</span> </div>
The 'toggle' directive toggles the value of 'displayPatientContactDetails' and adds a class called 'active' to the div based on whether displayPatientContactDetails is true or not . The arrow can be shown or hidden using css of 'active' class.
Code Block language css div{ &.active{ .fa-caret-right{ display: none; } .fa-caret-down{ display: block; } } .fa-caret-down{ display:none; } }
So the html can be changed to:
Code Block language xml <div toggle="displayPatientContactDetails"> <i class="fa fa-caret-right"></i> <i class="fa fa-caret-down"></i> <span>Patient Contact Details</span> </div>
This is one such example. The same approach can be used for multiple small elements which does not have any data binding or handlers.
...