9

状況

ディレクティブが定義されている要素内に、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>

したがって、私のディレクティブは、id in で要素の背景色をペイントするだけ$scope.elementIdです。(ちなみに、この単純な例をもっと簡単に処理できることはわかっています。一般的な問題を説明するだけです)。問題は、ng-repeat 内の要素の ID がまだ存在しないことです。コード内のコメントで指摘されているように、id は "{{ item.id }}" のままです。そのため、angular はこの部分をまだ評価していません。

質問

私の明らかな質問は次のとおりです。子孫要素が完全に評価されるのを待つようにディレクティブを作成するにはどうすればよいですか?

さらなる説明

私の実際のアプリケーションでは、ページ上の特定の要素にスクロールできるようにするディレクティブが必要です。また、ページネーション ディレクティブを使用して、表示する要素を分割します。ページネーションのため、実際に表示される要素のみが DOM にあるため、非表示の要素は既にコントローラーで除外されています。

また、すべての要素 (表示されているものだけでなく) への小さなリンクがあるサイドバーもあります。誰かがサイドバーの要素をクリックすると、次の 2 つのイベントが発生します。

  1. 正しいページにジャンプする
  2. 正しい要素までスクロールする

ページにジャンプすると、基本的に上記の状況になります。ng-repeat で処理する必要がある要素の完全な新しいリストがあります。しかし、その直後に、ID「xy」の要素をスクロールする必要があることをスクロールディレクティブに伝えようとしましたが、このIDはまだ割り当てられていません。

4

4 に答える 4

4

$scope.elementId = "Id1" を $timeout でラップして、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";
    });
});
于 2013-11-07T17:10:47.750 に答える
2

最終的に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);
});

それはまだ私の好みの解決策ではありませんが、今のところ機能し、私の問題を解決しています。しかし、これに対するより良いアプローチがあれば、私はまだ興味があります。

于 2013-11-08T13:49:57.613 に答える
0

オプションを含めてディレクティブを完成させる必要がありcontrollerます。

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

これにより、コントローラー スコープ内にすべてが作成され、このディレクティブを使用するビューのコントローラーからアクセスできるようになります。

于 2013-11-07T15:11:13.710 に答える