AngularJS - $apply(), $digest() and $watch() - angularjs

what is difference between in angularjs
$apply(), $digest() and $watch() ?
Please use below tool to explain if it is possible
http://plnkr.co/edit/dgCQ4tC6ZsrxLgxs8KO9?p=preview

Basically these three are different.
When You want to watch a variable. It means if you want, On change of a variable some code should be executed.then you will use watch.
Syntax $watch('variableName',function());
For example, On your page you have a variable which have some value and on change on that value from server or any other source you want to update it then you can apply watch on it. In your function you can write the code which will update the value.
$digest :- Angular internally uses this method. $digest will iterate all the watches and if its find the values of any variable is changed then it will execute the respective function. we can also call this in our code.
$apply :- when we want some code is executed and after that $apply should be executed then we can call $apply.This will execute the code n internally when $apply will be excute then it will be call $digest.

Related

Angular doesn't update the view

I have worked with angular for long time without facing many problems until now. I have a controller which calls a function when a ng-change event occurs. I have a set of different reports that are generated depending on some select filters defined in the main controller called Principal (PrincipalController).
Most of the controllers work fine and generate what they suppose, however with the last one (AnalisisEvaluacionController) I am struggling.
Its view is loaded correctly in the beginning. I print the name in the view but when I called the method from a ng-change event the name does not change. I also have a ng-repeat over $scope.notas which does not work. Actually that is the real issue. I have read about it and I have tried with
$scope.$apply() and $scope.$digest() but the error
angular.js:14800 Error: [$rootScope:inprog] $apply already in progress is thrown
I have created a snippet with the code https://bitbucket.org/snippets/jorguerra/Ee6G6y
I basically have a ng-repeat over evaluacion.notas which is reloaded when the function generarInforme is call, which call a factory that brings a JSON back which is assigned to $scope.evaluacion in the controller. The problem is that I can iterate or show the data I need to display
You don't need to call $scope.$apply (or $digest) in ng-change handler, as it's handler is already wrapped in $scope.$apply block. If you, however need to call $scope.$apply (or $digest) in some situations (e.g. your ng-change handler does some asynchronous operation after which you need to sync the view model), you can prevent the error this way:
(scope.$$phase || scope.$root.$$phase) ? fn() : scope.$apply(fn);
You can also wrap your fn in $timeout block
$timeout(fn)
which safely applies $scope.$apply.
I could solve my problem by creating a function init inside of AnalisisEvaluacionController which calls the method generarInforme and changing set all the required variables.

AngularJS - How to throttle unnecessary calls to functions [duplicate]

I have defined a function on scope. And when I call it from the view inside {{}} it executes X number of times.
Controller
function testCtrl($scope) {
$scope.myFunc = function(name) {
return "Hello " + name;
}
}
HTML
<div>{{myFunc('Joe')}}</div>
You can see it in this example: http://jsfiddle.net/rbRvD/2/
Or with Plunker: http://plnkr.co/edit/LLQ7cKs2fEoBwv0C5XPE
I guess this is done the wrong way, but why is it executed so many times?
Your function is run 10 times. Why 10? Why not 100?
The answer is in the docs:
The watch listener may change the model, which may trigger other
listeners to fire. This is achieved by rerunning the watchers until no
changes are detected. The rerun iteration limit is 10 to prevent an
infinite loop deadlock.
When you see this happening, it means you are changing the model in such a way that Angular has to rerun the digest and fire the watches again. In your particular case you are calling a function that updates a counter, which is displayed on the page. When the counter value changes it runs the digest again, which calls the function that updates the counter, etc, etc.
Angular expects you (and indeed encourages you) to change the model and let the view respond to those changes, rather than the other way around.
This is expected behaviour. Angular expressions ({{expression}}) are re-evaluated on each $digest loop (sometimes multiple times per loop). This means that expressions should stay light in computational terms.
For that matter, expression evaluation should not result in an AJAX call or some other intensive or asynchronous operation, or if it has to, than you should be caching the results.
AngularJs does not suggest you to change scope's model on rendering. If you want to change your scope's model, do it in Controller or Directive.
Think of view as a place to display data (scope values in this case) only, all the modifying of the data should be in Controller or Directive.

Angular $scope.$digest vs $scope.$apply

I just want to know how to use $digest. Inside a controller the following code works fine and it updates the DOM after 3 seconds:
setTimeout(function(){
$scope.$apply(function(){
$scope.name = 'Alice';
});
}, 3000);
However by using
setTimeout(function(){
$scope.$digest(function(){
$scope.name = 'Alice';
});
}, 3000);
nothing happens...
I thought that they do the same thing. Am I wrong?
$apply() and $digest() have some similarities and differences. They are similar in that they both check what's changed and update the UI and fire any watchers.
One difference between the two is how they are called. $digest() gets called without any arguments. $apply() takes a function that it will execute before doing any updates.
The other difference is what they affect. $digest() will update the current scope and any child scopes. $apply() will update every scope. So most of the time $digest() will be what you want and more efficient.
The final difference which explains why $apply() takes a function is how they handle exceptions in watchers. $apply() will pass the exceptions to $exceptionHandler (uses try-catch block internally), while $digest() will require you handle the exceptions yourself.
I think you must go through documents $apply
$apply() is used to execute an expression in angular from outside of
the angular framework
Usually, you don't call $digest() directly in controllers or in
directives. Instead, you should call $apply() (typically from within a
directive), which will force a $digest().
Also as suggest by Jorg, use $timeout
In angularjs $scope object is having different functions like $watch(), $digest() and $apply() and we will call these functions as central functions.
The angularjs central functions $watch(), $digest() and $apply are used to bind data to variables in view and observe changes happening in variables.
Generally in angularjs we use $scope object to bind data to variables and use that variables values wherever we required in application. In angularjs whatever the variables we assigned with $scope object will be added to watch list by using $scope.$watch() function.
In angularjs once variables added to watch list $scope.digest() function will iterates through the watch list variables and check if any changes made for that variables or not. In case if any changes found for that watch list variables immediately corresponding event listener function will call and update respective variable values with new value in view of application.
The $scope.$apply() function in angularjs is used whenever we want to integrate any other code with angularjs. Generally the $scope.$apply() function will execute custom code and then it will call $scope.$digest() function forcefully to check all watch list variables and update variable values in view if any changes found for watch list variables.
In most of the time angularjs will use $scope.watch() and $scope.digest() functions to check and update values based on the changes in variable values.
A better understanding of $watch, $apply, and $digest is provided in this article.
Simply,
$watch that is used to detect changes in the UI
$apply would tell the $digest loop what changes should be applied
$digest loop would run and will ask every $watch for changes, the DOMs would change accordingly for what has what has been applied
You should call $apply only.

when to use $scope.$apply in angular

I am a little confused about how $scope.$apply and digest loops function. From what I understand, since digest loops runs at regular intervals and not always, we can force the digest loop to run on certain scope variables which we want to update immediately. Also in the description here, it's given that $scope.$apply should be used when an async call is made, so that variables can be updated. My doubt is if digest loop doesn't run always, how are scope variables almost instantaneously updated in the view/controller?
Simply, use $scope.$apply() whenever you're outside the angular scope. For example within setTimeout function, as it is outside the world of angular.

Angular scope function executed twice when it should only run once?

Demo here
Quick question: in the following code I only call the function isSpecificPage() once, why it console.log twice?
<div ng-hide="isSpecificPage()">
<p>Hello!</p>
</div>
Angular puts a watch on your ng-hide function so that every digest cycle it can see if the results changed (and thus if it needs to change from hiding to showing your element or vice-versa).
When watched functions are evaluated (during $digest) if any of them have changed from the previous $digest then Angular knows that change might ripple through to other watched functions (perhaps the changed variable is used in another watched function). So every watch is re-evaluated (also called dirty processing) until none of the watches results in a change. Thus typically you'll see 2 calls to watched functions per digest and sometimes more (up to 10- at 10 loops through it gives up and reports an error saying it can't stabilize).
Here's more on watch and digest:
http://docs.angularjs.org/api/ng.$rootScope.Scope
http://www.benlesh.com/2013/08/angularjs-watch-digest-and-apply-oh-my.html
ng-hide is one of the directives that uses $watch internally. Since $watch uses digest cycle(which runs atleast 2 times to check if the value has changed or not), so your function isSpecificPage has run twice.
For a list of directives that use $watch internally, refer this stackoverflow answer directives that add watch internally.

Resources