Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 577
anonymous Avatar asked Apr 17 '13 17:04

anonymous


1 Answers

$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.

like image 141
Mark Rajcok Avatar answered Nov 09 '22 22:11

Mark Rajcok