0

This is a very common question, but I have never found the answer that works properly. I have come across three answers, but none always works.

  1. $apply: This will force an update, but will randomly through an error if it gets called while a digest is in progress.

  2. "safe apply" where there is a check for a digest in progress before calling $apply. This doesn't always update the view for some reason I haven't been able to determine. In addition, there is a small chance that a digest will start between the check and $apply.

  3. $timeout: according to the documentation, this should work reliably but doesn't seem to always update the view.

from $timeout documentation, the parameter invokeApply:

If set to false skips model dirty checking, otherwise will invoke fn within the $apply block. (default: true)

It never throughs an error, but sometimes doesn't update the view during a page load.

Here is a code sample where the problem occurs during page initialization:

EditService.getEvents(Gparams.curPersonID)
.then(function successCallback(response) {
    if (response.status=='200') {
        do some stuff
    } else {
        handle an error
    }   

    var timer = $timeout(function() { }) 
        .then(function successCallback(response) {
            do something
    });                                                                     
    $scope.$on("$destroy", function(event {
     $timeout.cancel(timer)});
});                                                                                     });     

What is the correct answer? Please don't just say what but also discuss why.

Fred
  • 1
  • 1
  • 2
  • http://stackoverflow.com/questions/23070822/angular-scope-apply-vs-timeout-as-a-safe-apply – Sachila Ranawaka Feb 26 '17 at 13:57
  • 1
    Calling $apply() does not "randomly" throw an error. It throws one if you incorrectly call it when you're already in a digest, which, IMHO, indicates that you're not understanding what you're doing. You should only have to call $apply when not using angular built-in services and directives to handle events, AJAX requests, etc. If you're doing that, then you should be aware of it, and $apply() is fine. – JB Nizet Feb 26 '17 at 14:06
  • Trying to reenter a `$digest` or `$apply` while one of them is already in progress is typically a sign of programming error that needs to be fixed. So AngularJS will throw this error when that occurs. This is to prevent very hard to detect bugs from entering your application. – georgeawg Feb 26 '17 at 21:43

1 Answers1

0

Here is a code sample where the problem occurs during page initialization

A common cause of .then methods not updating the DOM is that the promise is not an AngularJS $q service promise. The solution is to convert the suspect promise to a $q service promise with the $q.when method.

//EditService.getEvents(Gparams.curPersonID)
//CONVERT to $q service promise
$q.when(EditService.getEvents(Gparams.curPersonID))
.then(function successCallback(response) {
    if (response.status=='200') {
        do some stuff
    } else {
        handle an error
    }   

The .then method of a $q service promise is integrated with the AngularJS framework and its digest cycle. Changes to the scope model will automatically update the DOM.

when

Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.

--AngularJS $q Service API Reference - $q.when

georgeawg
  • 48,608
  • 13
  • 72
  • 95