为什么Angular没有注意到这个变量的值已经改变了?

时间:2015-01-15 22:02:44

标签: javascript angularjs

我遇到一个非常简单的Angular应用程序的问题。 Here's a CodePen;相同的代码如下。

在这个应用程序中,您单击一个按钮吃香蕉,并且您已经吃过的香蕉总数显示在页面上。每次点击后,你应该有一秒钟的冷却时间才可以吃另一根香蕉。

为实现这一目标,我做了以下工作:

  • $scope.cooling_down是一个布尔值。

  • $scope.can_eat_banana是一个返回truefalse的函数,指示“吃香蕉”按钮是否可用。基本上,如果$scope.cooling_down为false,则返回true。

  • “吃香蕉”按钮有ng-disabled="!can_eat_banana()"

  • 当用户点击“吃香蕉”按钮时,我将$scope.cooling_down设置为true,并使用window.setTimeout()安排回调以将其设置回{ {1}}一秒钟之后。

(你可能会问:为什么不完全摆脱false,只需在按钮上使用$scope.can_eat_banana()?答案:因为,随着游戏的发展,决定玩家是否可以的逻辑吃一根香蕉会变得更加复杂。把这种逻辑放在视野中似乎很麻烦。)

所以,当我运行这个测试用例时,会发生这种情况:

  1. 我加载页面。最初,该按钮已启用。

  2. 点击“吃香蕉”按钮。正如所料,我的代码将ng-disabled="cooling_down"设置为$scope.cooling_down,并且该按钮被禁用。到目前为止,非常好。

  3. 一秒钟之后,我传入true的回调开始了。 (我有一个window.setTimeout()作为回调中的第一行,以确认它正在运行。)此回调将console.log()设置回$scope.cooling_down。 (您可以查看控制台以确认该值已更新。) 但是: Angular没有注意到该值已更改。该按钮未重新启用,并且页面上的false令牌仍停留在{{cooling_down}}上。

  4. 为什么呢?为什么Angular会注意到值更改的第一个时间(当用户点击按钮后它变为true时),但没有注意到第二个时间(当回调触发并将其设置回true)时?

    false

2 个答案:

答案 0 :(得分:6)

Angular在window.setTimeout()之后不会再次运行其摘要循环(事实上,它甚至没有通知它)。

改为使用$timeout()

答案 1 :(得分:1)

更新模型(范围的属性)时,必须对该更改进行摘要以影响UI。当window.setTimeout完成时,原始摘要(由点击引起)早已完成而另一个未启动,因此UI永远不会更新。

要解决此问题,请将window.setTimeout替换为$timeout服务,该服务将在超时完成时启动另一个摘要。