我正在学习/尝试角度,偶然发现一些奇怪的行为(在我看来)。我用尽可能小的例子重新创建了我的问题 - 原始代码要长得多。
我想要这样做:
用户可以输入名称。只要名称等于“错误”,其颜色将变为红色并显示警告。当用户解除警报时(通过单击“确定”),名称将重置为“初始名称”并再次变为绿色。
它不做什么:
当名称变为“错误”时,其颜色不是红色。
代码:
<html lang="en-US" ng-app="myApp" ng-controller="myCtrl">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body>
<div>
<input ng-model="name" ng-style="{color: myColor}"/>
</div>
</body>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $document) {
$scope.name = "initial name";
$scope.myColor = "green";
$scope.$watch('name', function() {
if($scope.name === "error") {
$scope.myColor = "red"; // This line has no effect?
alert("Not allowed! Resetting...");
$scope.name = "initial name";
} else {
$scope.myColor = "green";
}
});
});
</script>
我知道更改$scope.myColor
应该改变颜色(如果我删除了else子句,它永远保持红色),但似乎alert
阻止了所需的行为,出于某种原因。我也改变了if子句中行的顺序,但这没有帮助。
问题:
这里有谁可以解释为什么“错误”不会变红的天才?
(我真的不需要解决方案,我只是想知道为什么会这样。)
答案 0 :(得分:5)
alert()
是一个阻止调用,阻止其他所有内容,直到它被解除。因此$scope.myColor
更改为红色,但在角度摘要周期完成之前,警报会弹出并阻止其他所有内容。解除警报后,名称将重置,颜色将恢复正常。
由于所有事情都在几毫秒内发生,因此您无法看到它。因此,如果您将警报置于1-2秒超时,您应该能够看到错误的红色。
答案 1 :(得分:0)
alert
阻止所有脚本执行,并在摘要完成之前触发。
在角落应用程序中使用它并不是一件好事,它在引擎盖下执行的操作与常规页面不同。
我建议您使用javascript驱动的警报系统。这个
有许多可用的角度模块答案 2 :(得分:0)
由于您在手表内部将值更新为红色,但在此之后直接更改名称,将再次触发对名称上的手表的回调,将其立即更改为绿色。您可能希望在警报显示期间文本是红色的,但由于您仍在手表内并且摘要周期处于“保持”状态(由于警报),您将看不到此信息。
答案 3 :(得分:0)
Angular并不一直跟随$scope
的所有字段。它做什么 - 它不时运行$digest
。在这种情况下,$watch
函数的主体完成后。
因此,在这种情况下,您更改了字段,显示了警告,在您关闭警报后,它更改了名称,启动$digest
,再次启动此功能。
答案 4 :(得分:0)
Angular可能以一种看起来很实时的方式工作,但实际上是通过收集“监视”变量的所有更改然后将它们应用到视图来工作。在$ watch内部,您无法应用更改,直到代码结束,但警报会暂停执行。请参阅:https://www.ng-book.com/p/The-Digest-Loop-and-apply/
你可以这样解决:
<html lang="en-US" ng-app="myApp" ng-controller="myCtrl">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body>
<div>
<input ng-model="name" ng-style="{color: myColor}"/>
</div>
</body>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($timeout, $scope, $document) {
$scope.name = "initial name";
$scope.myColor = "green";
$scope.$watch('name', function() {
if($scope.name === "error") {
$timeout(function(){
$scope.myColor = "red"; // This line has no effect?
alert("Not allowed! Resetting...");
$scope.name = "initial name";
});
} else {
$scope.myColor = "green";
}
});
});
</script>
答案 5 :(得分:0)
从范围生命周期的描述中,这是因为脏检查而发生的。
您的$ watch中的作业$scope.myColor = "green";
更改了模型的值,进一步提升了$ digest。在此之前alert()
停止处理可以完成。
https://docs.angularjs.org/guide/scope
在评估表达式后,$ apply方法执行$ digest。 在$ digest阶段,范围检查所有$ watch表达式 并将它们与之前的值进行比较。这个脏检查完成了 异步。这意味着分配如 $ scope.username =&#34;角&#34;不会立即造成$ watch 通知,而$ watch通知被推迟到$ digest 相。这种延迟是可取的,因为它合并了多个模型 更新到一个$ watch通知以及保证期间 $ watch通知没有其他$ watch正在运行。如果是$ watch 更改模型的值,它将强制额外的$ digest 周期。
答案 6 :(得分:0)
好吧,有时Angular不会像你预期的那样消化,你必须强制一个消化周期来强制执行。
您可以使用
执行此操作$timeout(function(){
//Your content here
});
或者使用
$scope.apply(function(){
//Your content here
});
不建议使用最后一种方法,因为它可能会触发异常“摘要已在进行中”
我让你的代码正常工作:plunker