簡體   English   中英

在循環內執行$ watch

[英]execution of $watch inside loop

我正在讀一本書,遇到以下代碼(有一個2D數組,稱為product,具有3行)-

html

<div unordered-list="products" list-property="price | currency"></div>

和JS

angular.module("exampleApp", [])
.directive("unorderedList", function () {

return function (scope, element, attrs) {

    var data = scope[attrs["unorderedList"]];
    var propertyExpression = attrs["listProperty"];

    if (angular.isArray(data)) {

        var listElem = angular.element("<ul>");
        element.append(listElem);

        for (var i = 0; i < data.length; i++) {

            var itemElement = angular.element('<li>');
            listElem.append(itemElement);

            var watcherFn = function (watchScope) {             
                                return watchScope.$eval(propertyExpression, data[i]);               
                            }

            scope.$watch(watcherFn, function (newValue, oldValue) {
                itemElement.text(newValue);
            });
        }
    }
}
})

該書說:“ AngularJS評估了三個觀察程序函數,它們在循環終止后引用了data [i]”。 “通過時間循環終止,i的值為3,這意味着所有三個觀察程序函數都嘗試訪問數據數組中不存在的對象,這就是該指令不起作用的原因”。

watcher函數位於循環內部,並從scope。$ watch調用,為什么會這樣呢?

這是由於javascript的可變作用域如何工作。

您可以在以下位置閱讀有關此問題的完整答案: 循環內的JavaScript關閉–簡單的實際示例

好吧,問題在於每個匿名函數中的變量i都綁定到函數外部的同一變量。

javascript觀察者也是如此,它們應用在不同的tick tick表示下一個事件循環執行。 要了解更多信息,請閱讀有關angular的摘要循環的更多信息。

因此,變量的值已經更改,直到函數執行完畢。

簡單解決方案1-特定於角度

一個特定於angular的簡單解決方案是為$watch構造一個字符串表達式。

因此$scope.$watch('products[1].price | currency', ..)應該可以工作。 根據您的代碼片段將其轉換為變量

 $scope.$watch(`${attrs['unorderdList']}[${i}].${attrs['listProperty']}`, function(newValue){ ... }) 

或類似的東西應該工作。 我將需要更多信息來提供一個運行示例。

簡單解決方案2-無角度限制

不特定於角度的另一種解決方案是將其綁定到其他范圍。 因此,如果循環的第一行是

for (let i = 0; i < data.length; i++) {

只需用let替換var它將起作用。 該解決方案利用了新的JavaScript let語法,該語法具有塊范圍而不是函數范圍。

   for (let i = 0; i < data.length; i++) {
        var itemElement = angular.element('<li>');
        listElem.append(itemElement);

        var watcherFn = function (watchScope) {             
                            return watchScope.$eval(propertyExpression, data[i]);               
                        }

        scope.$watch(watcherFn, function (newValue, oldValue) {
            itemElement.text(newValue);
        });
    }

發生這種情況是因為這些函數將與閉包一起工作,閉包表示執行時外部JS函數作用域的狀態。 這就是為什么在循環停止后變量i會引用最后分配的值:3。

為了使變量i等於迭代時的值,您需要創建中間范圍,並通過附加函數將其包裝起來:

var watcherFn = (function(i)
  return function (watchScope) {             
      return watchScope.$eval(propertyExpression, data[i]);               
  }
}(i));

您可以通過以下答案閱讀有關JS中閉包的更多信息: JavaScript閉包如何工作?

暫無
暫無

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

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