[英]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.