22

テンプレートが内部で ng-repeat を使用する単純なディレクティブがあります。ng-repeat ディレクティブによって作成されたいくつかの要素に対して jquery コンポーネントをインスタンス化するコードを実行する必要があります。問題は、このコードをリンク関数に入れた場合です。ng-repeat はこれらの要素をまだ構築していないため、何もインスタンス化されていません。

App.directive('myDirective', ['$compile', '$timeout', function($compile, $timeout) {
  return {
    scope: {
        domains: '='
    },
    templateUrl: '/app/partials/my_directive.html',
    link: function($scope, element, attributes) {
        element.find('.standard-help').tooltip('destroy');
        element.find('.standard-help').tooltip({placement: 'top', trigger: 'click hover focus'});
    }
  };
}

テンプレートは次のようになります。付けようとしている

<ul class="media-list domainList">
  <li class="media" style="position:relative;" ng-repeat="domain in domains">
    <a class="domainHeader" href="javascript://">
        <span class="domainHeader">{{domain.tag}}</span>
    </a>
    <div class="media-body" style="margin-left: 52px;">
        <ul class="standardsList">
            <li ng-class="{ standardDisplayed: lessonLayout == 'standards' }" ng-hide="standard.lessons.length == 0" ng-repeat="standard in domain.standards">
                <a href="javascript://" title="{{standard.description}}" ng-show="lessonLayout == 'standards'" class="standard-help pull-right"><i class="icon-question-sign"></i></a>
                <h6 ng-show="lessonLayout == 'standards'">{{standard.tag}}</h6>
                <ul class="lessonsList">
                    <li ng-class="{ lesson: true }" ng-repeat="lesson in standard.lessons" ng-click="onLessonSelected(lesson)">
                        <i class="icon-lock lesson-locked"></i>
                        <div>{{lesson.title}}</div>
                    </li>
                </ul>
            </li>
        </ul>
    </div>
  </li>
</ul>

$watch() と $observe() を使用して、ドメインが変更されたときにコールバックを登録し、ツールチップ コードをインスタンス化しようとしました。しかし、私はそれを適切なタイミングで呼び出すことができないようです。私が見逃しているアイデアはありますか?

4

5 に答える 5

23

ng-repeat が作成された要素に追加した別のディレクティブを作成すると、repeat が作成された要素ごとに通知されることがわかりました。次に、親ディレクティブがリッスンできるイベントを単純に $emit できます。その時点で、そこで繰り返される要素へのリンクを実行できます。これは、新しいディレクティブに渡されるイベント タイプによってそれらを分離できるため、特に dom 内の複数の ng-repeat に対して非常にうまく機能しました。

これが私の指示です:

App.directive("onRepeatDone", function() {
    return {
        restrict: 'A',
        link: function($scope, element, attributes ) {
            $scope.$emit(attributes["onRepeatDone"] || "repeat_done", element);
        }
    }
});

テンプレートでのその新しいディレクティブの使用法は次のとおりです。

<ul>
    <li on-repeat-done="domain_done" ng-repeat="domain in domains">...</li>
</ul>

次に、親ディレクティブ内で次のことができます。

link: function( $scope, element, attributes ) {
    $scope.$on('domain_done', function( domainElement ) {
        domainElement.find('.someElementInsideARepeatedElement').click(...);
    } );
}
于 2013-07-16T21:36:08.053 に答える
10

$watchあなたがやりたいことを達成できるはずです:

link: function(scope, elem, attrs) {
    var init = function() {
        // your initialization code
    };
    var ulElem = elem.children()[0]; // ul element

    var unreg = scope.$watch(function() {
        return ulElem.children.length === scope.domains.length; // check if all "li" are generated
    }, function() {
        // at this point, the ul is rendered
        init();
        unreg(); // unregister the watcher for performance, since the init function only need to be called once
    });
}

このソリューションを示すためにプランクを作成しました。

于 2013-07-15T05:55:45.943 に答える
2

私はまさにこの問題に出くわし、より良い解決策であると信じているものを見つけました. 基本的に、 を使用して、のレンダリングが完了$timeoutした後にタスクをキューに入れることができます。ng-repeat

注:これは、実際にタイマーや何らかの時間遅延を利用しているという意味ではありません。$digestループの最後に関数を追加する簡単な方法です。

以下は私のコードの抜粋です。ディレクティブはタブを表示するために使用されるため、HTML 要素にクラスを追加するメソッドをng-repeat実行するには、ディレクティブがレンダリングされるまで待つ必要があります。tabSelected()active

link($scope:ng.IScope, element:JQuery, attributes:ng.IAttributes):void {
  if (this.autoActivateFirstTab && this.tabs && this.tabs.length > 0) {
    var self = this;

    var selectFirstTab = function() {
      self.tabSelected(self.tabs[0]);
    };

    // Add a $timeout task to the end of the $digest loop to select the
    // first tab after the loop finishes
    self.$timeout(selectFirstTab, 0);
  }
}

http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-renderingから解決策を見つけました。これには、実際にそれを示すライブデモがあります。

別れの言葉: Karma を使用してコードをテストしている場合 (そうすべきであるように)、コードが実行される$timeout.flush()ことを確認するためにテストを呼び出す必要があります。

テストを適切に機能させるには、テスト内で次を実行する必要がありました。

// Re-digest to ensure we see the changes
scope.$digest();

// Flush any pending $timeout tasks to ensure we see changes
try {
  this.$timeout.verifyNoPendingTasks();
} catch ( aException ) {
  this.$timeout.flush();
}
于 2014-12-23T17:26:38.697 に答える
1

これはAngularのバグによるものだと思います。ここで見ることができます

1 つの回避策は、テンプレートの URL を削除し、ディレクティブ自体でテンプレートを使用するか、$templateCache.get('/app/partials/my_directive.html') を使用することです。

これは私のために働いた:)

于 2013-11-13T13:57:44.917 に答える