使用ng-if或ng-show在角度应用程序中按钮“闪烁”

时间:2015-08-26 03:58:00

标签: javascript angularjs angularjs-scope

我在两个不同的角度应用程序中遇到了同样的问题,但是我一直无法找到任何关于这个问题的讨论 - 这让我觉得也许我错过了一些东西。假设我有一个“任务”的视图,它可以处于许多不同的状态,包括“待定”,“接受”和“完成”。将根据任务的状态显示不同的操作按钮,例如:

<button ng-if="task.status === 'pending'" ng-click="ctrl.acceptTask()">Accept</button>

<button ng-if="task.status !== 'accepted'" ng-click="ctrl.acceptTask()">Flag</button>
<button ng-if="task.status === 'accepted'" ng-click="ctrl.flagTask()">Complete</button>

问题是当用户点击接受按钮时,短时间内将显示以下两个按钮。就好像angular通过DOM顺序工作一样,在ng-ifs之间的短暂时间内,显示'flag'和'complete'按钮,因为只有一个已更新。对于ng-show也会发生这种情况。

请注意,这不是一个可以用ng-cloak解决的问题,它只是为了防止在角度完成魔法之前显示模板。

鉴于我在两个大角度应用程序中遇到过这个问题,我一直在努力,这一定是个常见问题。关于如何解决这个问题的任何建议? (PS,上面的HTML只是我的意思的一个例子,它不是我的实际模板。)

1 个答案:

答案 0 :(得分:4)

这是因为ngIf完全删除并重新创建DOM中的元素。使用ngIf删除元素时,其范围将被销毁,并且在还原元素时会创建新范围。在ngIf中创建的作用域使用原型继承从其父作用域继承。另外,ngIf使用编译状态重新创建元素。

确实将ngIf评估为false将删除该元素。但是,只有当它没有立即设置为true时,因为angular只有在有机会时才刷新DOM(你的HTML),即在当前的同步代码块之后。

以下代码段没有任何效果:

$scope.task.status= 'pending'; <br/>
$scope.task.status= 'accept';

这将

$scope.task.status= 'pending';
// $timeout will wait for a digest cycle before executing the code
// Angular will remove the button from the DOM
$timeout(function() {
   $scope.task.status= 'accept';
   // Here a second digest cycle happen, angular will put the button back into the DOM
});

请注意,由于DOM内容较多,可能是由于您的角度应用程序出现了许多观察者。我已经制作了一个simple plunker来复制你的场景,但没有面对它。您可以通过添加可用的Chrome插件和/或许多其他方式(例如this)来检查和减少观察者。只需谷歌它,你就可以找到许多有用的信息,以提高你的应用程序的观察者数量。

好的,现在我知道了你在这里需要的东西:)看!! This是角度文档告诉我们的“特别注意强大的 ng-switch 应该用来代替几个互斥的ng-shows。”其中一个good读了“何时使用!!!”。因此,如果您在这些实例中使用ng-switch,我希望不会出现闪烁的按钮,或者我们可以通过使用指令初始化函数进行实例间通信来实现非常通用的解决方案,而无需担心当前范围。请参阅this,其中我以相互排斥的方式将类应用于多个按钮。