簡體   English   中英

angularJS:等待在指令加載之前評估模板

[英]angularJS: wait for template to be evaluated before directive loads

情況

假設我有一個指令,它必須通過ID在定義指令的元素內訪問某些元素。 可能出現的問題是,在評估指令時,子元素還沒有。 結果是,我無法通過其ID訪問這些元素。

小提琴

<div ng-controller="MyCtrl">
  <div color="elementId">
      <div ng-repeat="item in items" id="{{ item.id }}">
          {{ item.name }}
      </div>
  </div>
</div>

<script>
    var myApp = angular.module('myApp',[]);

    myApp.directive("color", function () {
        return {
            restrict: "A",   
            link: function (scope, element, attributes) {

                var name = attributes.color,
                    el = element[0];

                scope.$watch(name, function () {
                    var id = scope[name];
                    console.log(id); //id1
                    console.log(element.children().eq(0).attr("id")); //{{ item.id }}
                    element.find("#"+id).css("background-color","red");
                });
            }        
        };
    });

    function MyCtrl($scope) {
        $scope.items = [
            { id:"id1", name:"item1" },
            { id:"id2", name:"item2" }
        ];

        $scope.elementId="id1";
    }

</script>

因此,我的指令應該只使用$scope.elementId的id $scope.elementId元素的背景顏色。 (順便說一句。我知道我可以更輕松地處理這個簡單的例子,它應該只是說明一般問題)。 問題是,ng-repeat中的元素的id還沒有。 正如代碼中的注釋所指出的那樣,id仍然是“{{item.id}}”。 因此,角度尚未評估此部分。

我現在明顯的問題是:如何讓我的指令等待后代元素被完全評估?

進一步解釋

在我的實際應用程序中,我希望有一個指令,使我能夠滾動到頁面上的某些元素。 我還使用分頁指令來分割我想要顯示的元素。 由於分頁,只有真正可見的元素在DOM中,因此隱形元素已經在我的控制器中被過濾掉了。

我還有一個側邊欄,其中有所有元素的小鏈接(不僅是可見元素)。 當有人點擊側邊欄中的元素時,應該發生兩個事件:

  1. 跳轉到正確的頁面
  2. 滾動到corrent元素

當我跳到頁面時,我基本上都有這種情況,我在上面描述過。 我有一個完整的新元素列表,必須由ng-repeat處理。 但是在那之后,我嘗試告訴我的scroll-directive,它應該使用ID“xy”滾動元素,但是這個ID還沒有分配。

用$ timeout包裝$ scope.elementId =“Id1”以通知angular調用偵聽器。 (也可以使用$ scope。$ apply()來完成,但這會導致另一個問題)

這是jsfiddle鏈接

代碼是 -

    var myApp = angular.module('myApp',[]);

    myApp.directive("color", ['$timeout',  function ($timeout) {
        return {
            restrict: "A",   
            link: function (scope, element, attributes) {
                console.log(element)
                var name = attributes.color,
                    el = element[0];

                 scope.$watch(name, function () {
                     var id = scope[name];
                     console.log(id); //id1
                     console.log(element.find("#"+id)); //{{ item.id }}
                     element.find("#"+id).css("background-color","red");
                 });
            }        
        };
    }]);

myApp.controller("MyCtrl", function($scope, $timeout) {
    $scope.items = [
        { id:"id1", name:"item1" },
        { id:"id2", name:"item2" }
    ];

    $timeout(function() {
        $scope.elementId="id1";
    });
});

如果最終編寫了一個getElementById輔助函數,它返回一個promise並有一個內部間隔,如果該元素存在與否則每100ms檢查一次:

更新了小提琴

function getElementById(elementId) {
    var deferred = $q.defer(),
        intervalKey,
        counter = 0, 
        maxIterations = 50;

    intervalKey = setInterval(function () {
        var element = document.getElementById(elementId);
        if (element) {
            deferred.resolve(element);
            clearInterval(intervalKey);
        } else if (counter >= maxIterations) {
            deferred.reject("no element found");
            clearInterval(intervalKey);
        }
        counter++;
    }, 100);

    return deferred.promise;
}

在我給出的例子中,我會像這樣使用它:

getElementById(id).then(function (element) {
    $(element).css("background-color","red");
}, function (message) {
    console.log(message);
});

它仍然不是我的首選解決方案,但它現在可以解決我的問題。 但我仍然很好奇,如果有更好的方法。

根據Jim Hoskins的文章,以下代碼段可以幫助您。

  scope.$watch(name, function () {
    setTimeout(function () {
      scope.$apply(function () {
        var id = scope[name];
        console.log(id); //id1
        console.log(element.find("#"+id)); //{{ item.id }}
        element.find("#"+id).css("background-color","red");
      }  
    }, 200))
  });

發布此答案可幫助人們節省一些時間(當然,閱讀完整文章會很有幫助)

您應該完成指令,包括controller選項。

controller: function ($scope){
     $scope.items = [
        { id:"id1", name:"item1" },
        { id:"id2", name:"item2" }
    ];
}

這將在控制器范圍內創建所有內容,然后您可以從使用此指令的視圖的控制器訪問它。

暫無
暫無

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

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