在$ digest之后推迟angularjs监视执行(提升DOM事件)

时间:2013-04-17 17:20:18

标签: angularjs angularjs-directive

我有一个触发DOM事件的手表:

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

问题是我有'焦点'的处理程序执行scope.$apply

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

因此,当$watch$digest内部触发时,会导致错误,因为它会尝试触发另一个$digest

我的解决方法是将触发器放在$timeout

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

这项工作......到目前为止。这是处理这个问题的正确方法吗?我不确定这是否会抓住每一个案例,并且想知道是否有一个经过角度批准的方式让一段代码在摘要之后推迟。

谢谢!

2 个答案:

答案 0 :(得分:65)

$timeout通常用于在摘要周期后运行某些内容(以及在浏览器呈现后)。

$timeout将导致在执行函数后执行另一个摘要循环。如果您的trigger不影响任何Angular,您可以将invokeApply参数设置为false,以避免运行其他摘要周期。

如果您希望回调在浏览器渲染之前运行:如果代码使用指令中的$evalAsync 进行排队,则应在DOM之后运行被Angular操纵,但在浏览器渲染之前。但是,如果代码使用来自控制器$evalAsync 进行排队,则它将在Angular操纵DOM之前(以及在浏览器呈现之前)运行。另请参阅https://stackoverflow.com/a/17303759/215945

答案 1 :(得分:0)

就像大家一直在说的那样,你不应该在你的控制器中做DOM的东西。

这是一种将双向数据绑定应用于焦点的解决方案。现在你的焦点被绑定到一个变量。因此,当您将变量设置为true时,它会将焦点设置为相应的元素,并且当元素获得焦点时,将设置变量。

http://plnkr.co/edit/CvPCVxy4MfJEM1UksrrA?p=preview

我们现在已成功将焦点与控制器代码分开。它还会处理所有$ timeout问题(我猜)。您唯一需要注意的是,您不应该使用相同的变量来绑定两个不同元素的焦点。

编辑:更新了插件,因为前一个工作正常。