我遇到一个非常简单的Angular应用程序的问题。 Here's a CodePen;相同的代码如下。
在这个应用程序中,您单击一个按钮吃香蕉,并且您已经吃过的香蕉总数显示在页面上。每次点击后,你应该有一秒钟的冷却时间才可以吃另一根香蕉。
为实现这一目标,我做了以下工作:
$scope.cooling_down
是一个布尔值。
$scope.can_eat_banana
是一个返回true
或false
的函数,指示“吃香蕉”按钮是否可用。基本上,如果$scope.cooling_down
为false,则返回true。
“吃香蕉”按钮有ng-disabled="!can_eat_banana()"
。
当用户点击“吃香蕉”按钮时,我将$scope.cooling_down
设置为true
,并使用window.setTimeout()
安排回调以将其设置回{ {1}}一秒钟之后。
(你可能会问:为什么不完全摆脱false
,只需在按钮上使用$scope.can_eat_banana()
?答案:因为,随着游戏的发展,决定玩家是否可以的逻辑吃一根香蕉会变得更加复杂。把这种逻辑放在视野中似乎很麻烦。)
所以,当我运行这个测试用例时,会发生这种情况:
我加载页面。最初,该按钮已启用。
点击“吃香蕉”按钮。正如所料,我的代码将ng-disabled="cooling_down"
设置为$scope.cooling_down
,并且该按钮被禁用。到目前为止,非常好。
一秒钟之后,我传入true
的回调开始了。 (我有一个window.setTimeout()
作为回调中的第一行,以确认它正在运行。)此回调将console.log()
设置回$scope.cooling_down
。 (您可以查看控制台以确认该值已更新。) 但是: Angular没有注意到该值已更改。该按钮未重新启用,并且页面上的false
令牌仍停留在{{cooling_down}}
上。
为什么呢?为什么Angular会注意到值更改的第一个时间(当用户点击按钮后它变为true
时),但没有注意到第二个时间(当回调触发并将其设置回true
)时?
false
答案 0 :(得分:6)
Angular在window.setTimeout()
之后不会再次运行其摘要循环(事实上,它甚至没有通知它)。
改为使用$timeout()
。
答案 1 :(得分:1)
更新模型(范围的属性)时,必须对该更改进行摘要以影响UI。当window.setTimeout完成时,原始摘要(由点击引起)早已完成而另一个未启动,因此UI永远不会更新。
要解决此问题,请将window.setTimeout
替换为$timeout
服务,该服务将在超时完成时启动另一个摘要。