I have an ng-repeat and inside that ng-repeat i have
<p style="color:red">Booked Ref : {{agencyref(contentzz.Ref)}}</p>
With the way angular works it's constantly running the function, but that function has a HTTP request inside it, i just want to run it once. Is there something else i can use?
You're able to use the one-time binding syntax (::).
When using one-time binding the expression will only be evaluated once. After evaluation the watcher will be removed, thus the output of the expression will not be updated the next time the digest cycle is being triggered
Using one-time binding:
<p style="color:red">Booked Ref : {{::agencyref(contentzz.Ref)}}</p>
More info in docs: https://docs.angularjs.org/guide/expression#one-time-binding
If you wish to run this just once, why do you want to include it in ng-repeat?
Suggestion 1 : I suggest you can use ng-init in the parent tag and use the result later.
Suggestion 2 : You can make use of .run method of your angular module, however this is a very specific requirement. With your current question I am not sure if this will fit you or not, but this is another way of executing the method just once.
Use this
<p style="color:red" ng-if="$first">Booked Ref : {{agencyref(contentzz.Ref)}}</p>
So, this will get executed for the first element only.
Related
As we all know AngularJS uses the simplest form of $watch when we bind to variable in template like this {{ $ctrl.obj }}.
It should compare value of $ctrl.obj by reference, but if I mutate $ctrl.obj the change is reflected in view. The reference doesn't changed, so why?
When we use brackets ({{}}) angular does not use any watch (ers) for detecting changes on the expression placed inside them. Instead this expression is dirty checked and refreshed in every $digest cycle, even if it is not necessary.
See this post: AngularJS : Why ng-bind is better than {{}} in angular?
I recently started studying about digest and performance improvements in AngulaJs and found on my website that I'm using tons of ng-if.
Sometimes in ng-if there is a variable that may change, but often is fixed at the startup of the controller and then never changes.
What should I do so to improve performance avoiding digest to evaluate every loop those unchangeable ng-if? Should I change directive? With what?
E.g
In my header template I have a div that can be seen only by particular type of user. It's just a div, so I don't want to call some different template.
I put <div ng-if="userIsSuperior()"> ... </div>
When first evaluated, the return vale of userIsSuperior() never changes (during this session of course), but I know that AngularJs Digest evaluates it every loop.
How can I avoid this? Or am I missing something?
I think what you are looking for is one-time binding.
If you use:
<div ng-if="::userIsSuperior()"> ... </div>
Then the value of userIsSuperior() will only be calculated once and will stick to that value.
See demo.
First answer solutions needs AngularJS > 2.
I found a valid solutions in using OnceJS, library for one-time-binding.
Here
I need to initialize an object in my view and assign a reference to it.
Can I achieve this by using ng-init? Is it an assignment by value or reference?
<ANY ng-init="objA = objB"> ... </ANY>
Any help will be appreciated!
Move assignment to controller init() method.
ng-init is directive that have a very lot of side effects and hardly to trace it down. For example: when you use ng-init in directive template for creating/editing item and you assign some model value in it - you will achieve problem with editing that actually should use already existing value.
As well side effect of it is executing few times when you add ng-if.
Usage ng-init in templates are your own risk.
Right way: controller data should be defined at start of module - in any case any view started in order: $state -> resolve() -> controller -> template -> directive. It's not a good idea to fool yourself with not existing data until it will be created by magic.
In case of repeaters when you have for example empty {} and you need to display it like possibility to fill yet empty input, as I mentioned - you need to run function on init that can define empty or extend existing model by passing actual model.
Ok so I have read in several places that using ng-bind is better for performance.
But looking at these jsperfs makes me a bit confused :)
https://jsperf.com/angular-bind-vs-brackets
http://jsperf.com/ng-bind-vs-brackets/14
So what is the best way when it comes to performance?
{{::value}}
or
<div ng-bind="value"></div>
You should use ng-bind. Its a directive that puts a watcher on that variable so it only updates when the variable changes, while {{}} will dirty-check and refreshes the variable in every digest cycle.
See this answer
Also :: is called "bindonce" and will only set the variable once and wont update afterwards.
e: The jsperf tests binding from variable to html (I think), while the linked answer focuses on the behaviour afterwards. If you got 100 curly braces and you update one model, every {{}} gets updated. While ng-bind only updates if the variable itself changes, because it creates a watcher for that variable.
When it comes to one-time-binding, then you should also use the colon in ng-bind as well.
So use ng-bind="::value"
for filter or expressions you have to use brackets: ng-bind="::(value | number:2)"
use ng-bind is better . If javascript files is not loaded , {{ }} will show on the page .
I have multiple custom directives in my ngApp. The demo code is:
<top-nav></top-nav>
<left-sidebar></left-sidebar>
<div class="content">
....
</div>
The height of the 'left-sidebar' needs to be adjusted according to the height of the 'top-nav'.
Similarly there are other interdependent UI tasks. I want to run the post-load code (say app.initializeUI();) only after ALL the directives have been loaded and rendered.
Now, How do I achieve that?
EDIT :
Currently I am using the following code :
App.run(function($timeout){
$timeout(function(){ app.init() },0);
});
This runs fine, however, I am not sure this is the perfect way of doing this.
EDIT 2:
For people who want to avoid setting styles in js - use CSS Flexbox. I find it much better than calculating heights post page load. I got a good understanding of flexbox here
I would create an attribute directive with isolated scope, set terminal=true and add it to your body tag. Then in your link function, setup a $watch - isInitialized which is initially false. In your $watch handler, call your app.init(), and then de-register the $watch, so that it is always initialized once.
Setting up a terminal directive has consequences - no other directive can run after the terminal directive on the same element. Make sure this is what you want. An alternative is to give your directive the lowest possible value so that it is compiled first, and linked last.
The important pieces to this solution are:
By adding your Directive to the body tag, you ensure that it is linked last.
By adding a $watch, you ensure that all other directives have gone through a digest cycle, so by the time your $watch handler is called, all other directives should have already rendered.
Note of caution: The digest cycle may run several times before scope changes stabalise. The above solution only runs after the first cycle, which may not be what you want if you really want the final rendering.