【问题标题】:Defer angularjs watch execution after $digest (raising DOM event)在 $digest 之后延迟 angularjs 监视执行(引发 DOM 事件)
【发布时间】:2013-04-17 17:20:18
【问题描述】:

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

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

谢谢!

【问题讨论】:

  • $input.trigger('focus') -> 是否试图将焦点设置在输入元素上?
  • 是的......看起来我可以改为$input.focus()

标签: angularjs angularjs-directive


【解决方案1】:

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

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

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

【讨论】:

  • "$timeout 将导致执行另一个摘要循环。" ... 奇怪的。我想如果是这种情况并且我的事件处理程序正在调用 apply 我会得到同样的“已经在 $digest”错误。
  • 哦,好吧,函数执行后它会调用$apply。所以我应该将invokeApply 参数设置为false 以避免无用的$digest。谢谢。
  • @eyston,我忘记了 invokeApply 参数。我会用那个而不是setTimeout来更新我的答案。
  • @FelikZ,试试$evalAsync 而不是 $timeout。这应该在 DOM 更新之后,但在浏览器呈现之前调用。
  • @FelikZ,如果代码使用来自 directive 的 $evalAsync 进行排队,它应该在 DOM 被 Angular 操作之后运行,但是 在浏览器呈现之前。但是,如果代码使用来自 controller 的 $evalAsync 进行排队,它将运行 before DOM 已被 Angular 操作(以及 before 浏览器渲染)。另见stackoverflow.com/a/17303759/215945
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 这一切都在一个指令中。
  • @eyston 这就是重点。你所有的 DOM 东西现在都在指令中。另外,请注意该指令不包含任何特定于应用程序的逻辑。这是逻辑的适当分离。看到这个线程:github.com/angular/angular.js/issues/1277
  • 我知道这是旧的,但你的回答并没有真正说明他的问题,因为你认为他在控制器中做所有事情。
  • @gonzofish 你检查 plunkr 了吗?
  • @gonzofish 这与焦点管理有关——这显然也是他在指令中所做的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-29
  • 1970-01-01
  • 1970-01-01
  • 2018-09-20
  • 2017-08-14
相关资源
最近更新 更多