This is a general question about AngularJS.
AngularJS does not raise an event to notify when the digest cycle has ended. AngularJS suggests using $timeout as a solution to queue your work to be run after the current digest cycle (also waits for DOM rendering to be completed by the browser).
Does anyone know how to know if $scope.$apply() and $scope.$digest() have ended without using $timeout?
You can use $scope.$digest(), before your business logic function or $scope.$apply(function(){/*your business*/}) but this method like timeout function.
Related
How does AngularJS implements the 2-way data binding? The view to model update is understandable i.e. it can be achieved through the JS listeners but I wanted to understand the model to view update? As at the core angular models are js variables, so how does the Angular listen to the change in js vars?
I know that each model has a watch which compare the new value with the old one but what triggers this check(the js implementation)?
Does it uses Javascripts watchers or a time interval for checking?
Angular defines a concept of a so called digest cycle. This cycle can
be considered as a loop, during which Angular checks if there are any
changes to all the variables watched by all the $scopes. So if you
have $scope.myVar defined in your controller and this variable was
marked for being watched, then you are explicitly telling Angular to
monitor the changes on myVar in each iteration of the loop.
Basically AngularJS binds event handlers to any element that interacts with Angular ($scope, directive, ...), every time the event fires, $apply is called which internally calls $digest which will trigger the re-evaluation of all the $watches.
AngularJS made a smart assumption that model changes happen only on user interaction / events:
DOM events
XHR responses firing callbacks
Browser's location changes
Timers (setTimout, setInterval) firing the callbacks
Or trigger on certain events
Input directives+ngModel, ngClick, ngMouseOver etc.
$http and $resource
$location
$timeout
When one of these 'assumptions' is triggered, the digest cycle is kicked off:
To quote Pawel Kozlowski, Mastering Web Application Development with AngularJS:
AngularJS does not use any kind of polling mechanism to periodically
check for model changes
More detailed insights
Have a look at https://www.youtube.com/watch?v=SYuc1oSjhgY for a really deep dive into the digest cycle.
I am using Angularjs 1.3.7 and just discovered that Promise.all does not update angularjs view after a successful response, while $q.all does. Is this later changed since Promises are included in native javascript or what is the reason behind this?
As IAmDranged mentions in a comment:
Probably yeah, because the Promise API is not integrated with the angular mechanism - meaning essentially that it doesn't trigger a digest cycle at key point of the lifecycle of the promises. Try adding a $scope.$apply() at the end of the Promise.all() callback function to trigger a digest cycle manually.
It was confirmed that Promise.all does not trigger a digest cycle.
We can abort the $timeout and $interval by using '$destroy' when the route changes. How can we abort the pending $http requests like $interval and $timeout?
Check out this article, it has some valuable information. Throughout the research I made, there is no magical solution unfortunately. You'll have to get your hands dirty and code a bit for some results.
I'm using protractor for system tasting my ui-router SPA application.
As I understands the documentation, protractor should wait for things to happen before/while angular is playing.
for instance, when the user click a button, I'm changing the state. So I'm like -
$('#addProductButton button').click();
and then -
expect(browser.getLocationAbsUrl()).toContain('#/products/new');
but it fails.
To work around that I'm using browser.wait until the location is good. but this is stink.
does someone knows why protractor is not waiting.
p.s
try to use browser.waitForAngular() doesn't work.
Found the problem.
I was using $provide.decorator to provide $httpbackend with some values, while using setTimeout instead of $timeout.
setTimeout got me out of angular world and protractor is not waiting for that.
njoy!
You can skip model dirty checking in $timeout service by setting the third parameter called invokeApply to false (see documentation).
Is it possible to achieve the same result with the $http service?
I need to call a legacy third-party restful webservice several times, but must reduce the amount of refreshes on the UI...
No, but you can use jQuery.ajax or any other ajax library to make http requests out of the digest loop.
In fact, $http will not send any request outside the digest loop. This is from the angular comments:
The $http service will not actually send the request until the next $digest() is
executed. Normally this is not an issue, since almost all the time your call to $http will
be from within a $apply() block.
If you are calling $http from outside Angular, then you should wrap it in a call to
$apply to cause a $digest to occur and also to handle errors in the block correctly.