使用'alert'时出现意外的角度行为

时间:2015-10-08 07:16:44

标签: javascript angularjs

我正在学习/尝试角度,偶然发现一些奇怪的行为(在我看来)。我用尽可能小的例子重新创建了我的问题 - 原始代码要长得多。

我想要这样做:
用户可以输入名称。只要名称等于“错误”,其颜色将变为红色并显示警告。当用户解除警报时(通过单击“确定”),名称将重置为“初始名称”并再次变为绿色。

它不做什么:
当名称变为“错误”时,其颜色不是红色。

Name is still green

代码:

<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子句中行的顺序,但这没有帮助。

问题:
这里有谁可以解释为什么“错误”不会变红的天才? (我真的不需要解决方案,我只是想知道为什么会这样。)

7 个答案:

答案 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