32

我有一个触发 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; });
});

因此,当 my$watch从内部被触发时,$digest它会导致错误,因为它试图触发另一个$digest.

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

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

这有效......到目前为止。这是处理这个问题的正确方法吗?我不确定这是否适用于所有情况,并且想看看是否有一种角度认可的方法可以在摘要之后延迟一段代码。

谢谢!

4

2 回答 2

66

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

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

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

于 2013-04-17T17:32:55.470 回答
0

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

这是一个应用两种方式数据绑定来聚焦的解决方案。现在您的焦点绑定到一个变量。因此,当您将变量设置为 true 时,它​​将焦点设置在相应的元素上,并且当元素获得焦点时,设置变量。

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

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

编辑:更新了 plunk,因为前一个不能正常工作。

于 2013-04-17T18:44:41.680 回答