Defer angularjs watch execution after $digest (raising DOM event)

21,509

$timeout is normally what is used to run something after a digest cycle (and after the browser renders).

$timeout will cause another digest cycle to be executed after the function is executed. If your trigger does not affect anything Angular, you can set the invokeApply argument to false to avoid running another digest cycle.

If you want your callback to run before the browser renders: If code is queued using $evalAsync from a directive, it should run after the DOM has been manipulated by Angular, but before the browser renders. However, if code is queued using $evalAsync from a controller, it will run before the DOM has been manipulated by Angular (and before the browser renders). See also https://stackoverflow.com/a/17303759/215945.

Share:
21,509
anonymous
Author by

anonymous

Updated on November 04, 2020

Comments

  • anonymous
    anonymous over 3 years

    I have a watch that triggers a DOM event:

    scope.$watch(function() { return controller.selected; }, function(selected) {
        if (selected) {
            $input.trigger('focus');
        }
    });
    

    The issue is that I have a handler on 'focus' that does a scope.$apply.

    $input.bind('focus', function() {
        scope.$apply(function() { controller.focused = true; });
    });
    

    So when my $watch is fired from inside a $digest it causes an error because it tries to trigger another $digest.

    The workaround I have is to put the trigger in a $timeout.

    scope.$watch(function() { return controller.selected; }, function(selected) {
        if (selected) {
            $timeout(function() { $input.trigger('focus'); });
        }
    });
    

    This works ... so far. Is this the proper way to handle this? I'm not sure if this catches every case and would like to see if there is an angular approved way to have a piece of code defer for after the digest.

    Thanks!