簡體   English   中英

使用“警報”時出現意外的Angular行為

[英]Unexpected Angular behavior when using 'alert'

我正在學習/實驗角度,偶然發現了一些奇怪的行為(在我看來)。 我用最小的示例重新創建了問題-原始代碼長了很多。

我要這樣做:
用戶可以輸入名稱。 每當名稱等於“錯誤”時,其顏色將變為紅色並顯示警報。 當用戶取消警報時(通過單擊“確定”),該名稱將重置為“初始名稱”並再次變為綠色。

它不起作用:
名稱變為“錯誤”時,其顏色不是紅色。

名字仍然是綠色的

碼:

<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子句中各行的順序,但這無濟於事。

題:
這里有任何天才可以解釋為什么“錯誤”沒有變成紅色?
(我真的不需要解決方案,我只想知道為什么會這樣。)

alert()是一個阻止調用,它將阻止所有其他操作,直到將其關閉。 因此, $scope.myColor更改為紅色,但在角度摘要循環完成之前,警報彈出並阻止其他所有內容。 解除警報后,將重命名名稱,並將顏色重新設置為正常顏色。

由於一切都以毫秒為單位,所以您看不到它。 因此,如果將警報設置為1-2秒超時,則應該能夠看到紅色的錯誤。

正如其他人提到的那樣, alert阻止所有處理,直到alert關閉。 您可以使用其他系統,例如ui-bootstrap中的$modal (您可能想要這樣做),但是如果您絕對要使用alert ,則可以使用setTimeout/$timeout來確保alert在開始時發生下一個 $digest循環的時間。

$timeout(function() {
  alert('hello, world')
}, 0)

但是,這不能保證按您想要的順序執行,因此,我真的只建議使用ui-bootstrap或類似其他建議的工具。

alert阻止所有腳本執行,並且會在摘要完成之前觸發。

在有角度的應用程序中使用它不是一件好事,它在后台執行的功能與常規頁面中不同。

我建議您使用JavaScript驅動的警報系統。 為此有許多可用的角度模塊

由於您將手表內部的值更新為紅色,但還立即更改了名稱,此后將再次觸發對手表名稱的回調,立即將其更改回綠色。 您可能希望在警報可見期間文本為紅色,但是由於您仍在手表內,並且摘要周期處於“保持”狀態(由於警報),因此您不會看到此文本。

Angular並非一直都遵循$scope所有字段。 它的作用-有時會運行$digest 在這種情況下, $watch函數的主體完成后。

因此,在這種情況下,您更改了字段,顯示了警報,並在關閉警報后更改了名稱,啟動了$digest ,再次啟動了此功能。

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>

從范圍生命周期的描述中,這是由於臟檢查而發生的。

您的分配$scope.myColor = "green"; 在您的$ watch更改中,模型的值將進一步引發$ digest。 alert()在可以完成之前停止處理。

https://docs.angularjs.org/guide/scope

評估表達式后,$ apply方法執行$ digest。 在$ digest階段,范圍將檢查所有$ watch表達式並將它們與先前的值進行比較。 這種臟檢查是異步完成的。 這意味着諸如$ scope.username =“ angular”之類的分配不會立即導致通知$ watch,而是將$ watch通知延遲到$ digest階段。 此延遲是可取的,因為它將多個模型更新合並到一個$ watch通知中,並保證在$ watch通知期間沒有其他$ watch正在運行。 如果$ watch更改了模型的值,它將強制執行附加的$ digest循環。

好吧,有時Angular不會像您期望的那樣進行消化,因此您必須強制執行消化周期來強制執行。

您可以使用

$timeout(function(){
    //Your content here
});

或使用

$scope.apply(function(){
    //Your content here
});

不建議使用最后一種方法,因為它可能會觸發“已在消化的消化道”異常

我讓你一個plunker與您的代碼工作: plunker

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM