AngularJS recalculate "nested" functions on data change - javascript

There is possibly a solution out there for this but i can't seem to find it or if i found it already i can't understand it.
I have a AngularJS app and there is the following setup:
in the view:
<button ng-click="data=data+1"></button>
<div>{{getValue("something")}}</div>
<div>{{getAnotherValue("anotherThing")}}</div>
In the controller:
$scope.getValue=function(param){
return param+$scope.otherValues+$scope.data;
}
$scope.getAnotherValue=function(param){
return param+$scope.evenOtherValues+$scope.getValue("someOtherParam");
}
When i click the button, the "getValue()" function is recalculated automatically but not the "getAnotherValue()". Is there a way to recalculate everything what is effected by the data change, even in this nested (or even more nested) situation?

Are u sure getAnotherValue() is not updating? I set up a fiddle myself and it DOES updates.
In fact angular will ensure that the data bind to UI(DOM) to be correctly presented by adding $watch (watcher keeping track of the expression) to them.
Whenever there is something changed, there will be a digest cycle in which angular will go through all the watchers and check whether the data watched has changed (by recalculating it if it is a function).
For any watcher if the value has changed, angular will repeat the check process again, until all watchers reporting there is no change in the value they are watching.
If we write the process in steps:
1.start a digest cycle
2.ask the watchers one by one if there is any change in value
3.if any watcher reports there is a change, go back to step 1
4.if no change is reported, finish digest cycle and update UI.
However there could be exception that there are too complicated and nested watchers or any watcher loops, which will cause angular to reach the maximum number of digest cycles (default is 10). Angular will break the digest process and an exception will be thrown under this circumstance.

Related

How often does code in an *ngIf condition in Angular 2+ fire?

I am curious about how *ngif works:
<img *ngif="isMediaMessage(message) === 'audio'" src="assets/img/audio1" />
1)
When I put a console inside the isMediaMessage function, the console prints out indefinitely; I wonder why it does that. Is it because of the digest loop? dirty checking? I am reading up more on these.
2) Should I use less data binding if I want to reduce rendering time?
3) Would you guys say this article is up to date?
This might be related.
This is concerning to the digest loop/detection cycle and the watches on the page.
Every time there is a change in the page and the queue of dirty checking is running then the mechanism of detection is running will reevaluate the ngIf and your code/condition of ngIf will fire.

Angular 2 property binding lifecycle

What is the defined lifecycle of property binding in Angular 2? For example I have following element in my template:
<input type="radio" name="{{choice.question_id}}" value="{{choice.id}}"
[checked]="isSelected()"
(change)="select()"
required>
When are exactly those properties and event callbacks bound? As far as I know, there is some cycle which automatically refresh the bindings. Where I can find better explanation about that cycle?
My goal above is to make radiobutton selected by default if isSelected(). Thus polling the isSelected() after initial rendering is redundant and inefficient. How can I restrict that [checked]="isSelected() just to moment when element is first added to DOM?
Bindings are evaluated at every change detection cycle.
Change detection is run after some async execution happened. Angulars zone patches most async APIs like addEventHandler, removeEventHandler, setTimeout, ... After such events are processed Angular runs change detection and checks all expressions bound to inputs ([], {{}}).
Such events happen very frequently and thus bound expressions are evaluated very frequently. Therefore it's important to make these expressions efficient. This is one of the reasons the Angular team discourages binding to functions and to rather assign the result to a property and bind to that property instead because compairsion of properties is quite efficient, or even better, bind to observables and promises (using the | async pipe) that actively notify about changes.
You can't define at what point a binding is evaluated. It is evaluated every time change detection runs. You can control though when change detection runs on your component or its child components by setting ChangeDetectionStrategy.OnPush instead of ChangeDetectionStrategy.CheckAlways (default) and invoke change detection "manually".
In devMode default, change detection also aways runs twice to check if the first change detection turn itself didn't cause any changes in the model which is considered a bug. This needs to be taken into account if you're wondering why a bound method is called so frequently. If in devMode divide the count by 2 to get the effective number as it would happen in prodMode.

Prevent angular from running diggest cycle

I am having trouble with angular running diggest cycle on data change. I am using isotope to display some images and messages and when irrelevant data is changed the view gets updated and isotope moves messages. Can I prevent diggest cycle from running when data is updated?
I would want to first check if data updated was relevant to displaying before running diggest.
I'm not sure you can stop it completely, but you can listen and intercept the $digest calls.
From the docs:
If you want to be notified whenever $digest is called, you can register a watchExpression function with no listener. (Be prepared for multiple calls to your watchExpression because it will execute multiple times in a single $digest cycle if a change is detected.)
Source

ng-repeat loop more than the number of elements

I am trying to implement ng-repeat with ng-style. It works perfectly. However, I do not understand why my method is called more than the number of elements in my ng-repeat!
Do you know why?
To complete my explanation, I created a : JSFiddle
I think that when your html code is compiled, it executes ng-style directive even if there is no data (when items == null). After that your controller changes $scope.items, forcing other calls to $scope.getStyle().
I think if you put a ng-if="items != null" within ng-repeat, your function will be called only 5 times.
Solution looks fine. The reason for multiple calls is angular digest loop. You can read about it here: http://www.benlesh.com/2013/08/angularjs-watch-digest-and-apply-oh-my.html
It works by running the loop and looking if the values changed for the watches. When they stabilize it ends. You can have multiple passes of the event loop in angular app and that is pretty normal. The limit is set afaik for 10 iterations. If bindings do not stabilize then exception is thrown.
Additional reading, highly recommended:
http://teropa.info/blog/2013/11/03/make-your-own-angular-part-1-scopes-and-digest.html
Part Keep Digesting While Dirty is the answer to your question i believe.
So it is by design.

"10 $digest() iterations reached. Aborting!" due to filter using angularjs

Take a look at the following:
https://dl.dropbox.com/u/4571/musicopeTypescript/musicopeTypescript/index.html
when you type "a" in the input box, you obtain the 10 $digest() iterations reached. Aborting! error.
Do you have any idea, why that happens?
EDIT: Here is the code that makes problems:
http://embed.plnkr.co/PTkvPc
EDIT: It looks like it is a problem of Song.clone. If I replace it by angular.copy, then it works. Anybody could explain that?
Here is the working version:
http://plnkr.co/edit/8Jk1pR?p=preview
Is your filter modifying the original data somehow? That's the only specific thing that looks like it would cause the infinite digest cycle.
EDIT: in regards to different cloning functions lead to different behavior.
I suspect one is doing deep cloning, the other is not, and in one case AngularJS is checking object equality and your filter is creating new objects each time, causing the problem.
I'd suggest breaking up some of that logic and perhaps moving some of it into the controller or additional filters. The filter that narrows down your array should only be doing that, and just return references to the original objects. Then you can write other filters to manipulate the tags, etc.
Also +1 for Abba. :P
To understand why is this is happening, it's good to understand how angular works runtime. Basically there are watchers that keep returning back different values, and so it keeps going through the $digest loop and then stops it from infinitely looping. From their $digest() documentation:
Process all of the watchers of the current scope and its children. Because a watcher's listener can change the model, the $digest() keeps calling the watchers until no more listeners are firing. This means that it is possible to get into an infinite loop. This function will throw 'Maximum iteration limit exceeded.' if the number of iterations exceeds 10.
Without knowing what your code is doing, it's hard to give a specific solution to why this is happening in your case, but this should answer your questions as to when this error is thrown.

Categories