AngularJS: Linking to elements in a directive that uses ng-repeat

前端 未结 5 1768
夕颜
夕颜 2020-12-05 01:00

I have a simple directive where the template uses ng-repeat inside it. I need to run some code to instantiate a jquery component against some of the elements created by the

相关标签:
5条回答
  • 2020-12-05 01:34

    I found that if created another directive that I added to the element where the ng-repeat was being created it would be notified for each element the repeat created. Then I could simply $emit an event that the parent directive could listen for. At which point it could perform the linking to the repeated elements there. This worked quite nicely especially for multiple ng-repeats within the dom because I could separate them by their event type which would be passed to the new directive.

    Here is my directive:

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

    Here is the usage of that new directive in the template:

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

    Then inside the parent directive I could do the following:

    link: function( $scope, element, attributes ) {
        $scope.$on('domain_done', function( domainElement ) {
            domainElement.find('.someElementInsideARepeatedElement').click(...);
        } );
    }
    
    0 讨论(0)
  • 2020-12-05 01:41

    $watch should work in this context. try it

    0 讨论(0)
  • 2020-12-05 01:42

    $watch should be able to achieve what you want to do:

    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
        });
    }
    

    I have created a plunk to demonstrate this solution.

    0 讨论(0)
  • 2020-12-05 01:44

    I think this is because of the angular bug.You can see this here

    One workaround is to remove the template url and use the template in the directive itself or use $templateCache.get('/app/partials/my_directive.html')

    This worked for me :)

    0 讨论(0)
  • 2020-12-05 01:50

    I just ran across this exact issue and found what I believe is a better solution. Basically, you can use $timeout to queue a task for after the ng-repeats have finished rendering.

    Note: this doesn't mean that you're actually utilizing the timer or any sort of time delay; it is just a simple way to append a function to the end of the $digest loop.

    Below is an excerpt of my code. The directive uses ng-repeat to display the tabs, thus, I have to wait until after it has been rendered to run my tabSelected() method which adds the active class to the HTML element.

    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);
      }
    }
    

    I found the solution from http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering which has a live demo that shows it in action.

    Parting words: If you are testing your code (like you should) with Karma, you will need to call $timeout.flush() in your test to ensure that it runs.

    I wound up having to run the following within my test to get it to work properly:

    // 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();
    }
    
    0 讨论(0)
提交回复
热议问题