210 votes

AngularJS ng-répétition terminent la compétition

Je veux appeler un div de la fonction jQuery avec la table. Ce tableau est rempli avec ng-repeat .

Quand je l'appelle

 $(document).ready()
 

Je n'ai aucun résultat.

Aussi

 $scope.$on('$viewContentLoaded', myFunc);
 

n'aide pas

Existe-t-il un moyen d'exécuter la fonction juste après la fin de la population répétée? J'ai lu un conseil sur l'utilisation de custom directive , mais je n'ai aucune idée de comment l'utiliser avec ng-repeat et mon div ...

243voto

Tiago Roldão Points 4567

En effet, vous devez utiliser les directives, et il n'y pas d'évènement lié à la fin d'une ng-Repeat boucle (chaque élément est construit individuellement, et possède sa propre cas). Mais une) à l'aide de directives peut être tout ce dont vous avez besoin et b) il y a quelques ng-Repeat propriétés spécifiques que vous pouvez utiliser pour rendre votre "sur ngRepeat fini" de l'événement.

Plus précisément, si tout ce que vous voulez est de style/ajouter des événements à l'ensemble de la table, vous pouvez le faire en utilisant une directive qui englobe tous les ngRepeat éléments. D'autre part, si vous voulez l'adresse de chaque élément en particulier, vous pouvez utiliser une directive dans le ngRepeat, et il agira sur chaque élément, après qu'il est créé.

Ensuite, il y a le $index, $premier, $moyen $et dernier propriétés que vous pouvez utiliser pour déclencher des événements. Donc, pour ce code HTML:

<div ng-controller="Ctrl" my-main-directive>
  <div ng-repeat="thing in things" my-repeat-directive>
    thing {{thing}}
  </div>
</div>

Vous pouvez utiliser les directives de la sorte:

angular.module('myApp', [])
.directive('myRepeatDirective', function() {
  return function(scope, element, attrs) {
    angular.element(element).css('color','blue');
    if (scope.$last){
      window.alert("im the last!");
    }
  };
})
.directive('myMainDirective', function() {
  return function(scope, element, attrs) {
    angular.element(element).css('border','5px solid red');
  };
});

Le voir en action dans cette Plunker. Espérons que cela aide!

0 votes

Puis-je faire myMainDirective ne s'exécute qu'après la fin de la boucle ? J'ai besoin de mettre à jour la barre de défilement de la div parent.

2 votes

Bien sûr ! Il suffit de changer le "window.alert" en une fonction déclenchant un événement, et de l'attraper avec la directive main. J'ai mis à jour de Plunker pour faire cela, à titre d'exemple.

9 votes

Il est recommandé d'inclure la bibliothèque jQuery en premier (avant Angular). Ainsi, tous les éléments Angular seront enveloppés par jQuery (au lieu de jqLite). Ainsi, au lieu de angular.element(element).css() et $(element).children().css(), vous pouvez simplement écrire element.css() et element.children().css(). Voir aussi groups.google.com/d/msg/angular/6A3Skwm59Z4/oJ0WhKGAFK0J

69voto

karlgold Points 3636

Si vous souhaitez simplement exécuter du code à la fin de la boucle, voici une variante un peu plus simple qui ne nécessite pas de gestion d'événements supplémentaire :

<div ng-controller="Ctrl">
  <div class="thing" ng-repeat="thing in things" my-post-repeat-directive>
    thing {{thing}}
  </div>
</div>

function Ctrl($scope) {
  $scope.things = [
    'A', 'B', 'C'  
  ];
}

angular.module('myApp', [])
.directive('myPostRepeatDirective', function() {
  return function(scope, element, attrs) {
    if (scope.$last){
      // iteration is complete, do whatever post-processing
      // is necessary
      element.parent().css('border', '1px solid black');
    }
  };
});

Voir une démonstration en direct.

0 votes

Cela fonctionne-t-il si j'utilise le contrôleur comme syntaxe ? S'il vous plaît ? Si ce n'est pas le cas, existe-t-il une autre méthode qui fonctionne avec controller as ?

41voto

Joseph Oster Points 1089

Voici une directive "repeat-done" qui appelle une fonction spécifiée lorsqu'elle est vraie. J'ai découvert que la fonction appelée doit utiliser $timeout avec interval=0 avant de faire des manipulations dans le DOM, comme l'initialisation des infobulles sur les éléments rendus. jsFiddle : http://jsfiddle.net/tQw6w/

Dans $scope.layoutDone, essayez de commenter la ligne $timeout et de décommenter la ligne "NOT CORRECT !" pour voir la différence dans les infobulles.

<ul>
    <li ng-repeat="feed in feedList" repeat-done="layoutDone()" ng-cloak>
    <a href="{{feed}}" title="view at {{feed | hostName}}" data-toggle="tooltip">{{feed | strip_http}}</a>
    </li>
</ul>

JS :

angular.module('Repeat_Demo', [])

    .directive('repeatDone', function() {
        return function(scope, element, attrs) {
            if (scope.$last) { // all are rendered
                scope.$eval(attrs.repeatDone);
            }
        }
    })

    .filter('strip_http', function() {
        return function(str) {
            var http = "http://";
            return (str.indexOf(http) == 0) ? str.substr(http.length) : str;
        }
    })

    .filter('hostName', function() {
        return function(str) {
            var urlParser = document.createElement('a');
            urlParser.href = str;
            return urlParser.hostname;
        }
    })

    .controller('AppCtrl', function($scope, $timeout) {

        $scope.feedList = [
            'http://feeds.feedburner.com/TEDTalks_video',
            'http://feeds.nationalgeographic.com/ng/photography/photo-of-the-day/',
            'http://sfbay.craigslist.org/eng/index.rss',
            'http://www.slate.com/blogs/trending.fulltext.all.10.rss',
            'http://feeds.current.com/homepage/en_US.rss',
            'http://feeds.current.com/items/popular.rss',
            'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml'
        ];

        $scope.layoutDone = function() {
            //$('a[data-toggle="tooltip"]').tooltip(); // NOT CORRECT!
            $timeout(function() { $('a[data-toggle="tooltip"]').tooltip(); }, 0); // wait...
        }

    })

0 votes

Je ne voulais pas utiliser un $timeout, mais quand vous avez dit qu'il pouvait être mis à 0, j'ai décidé d'essayer et cela a bien fonctionné. Je me demande si c'est une question de digestion, et s'il y a un moyen de faire ce que fait $timeout sans utiliser $timeout.

0 votes

Pouvez-vous expliquer pourquoi cela fonctionne ? J'essaie d'accéder à des identifiants dynamiques et cela ne fonctionne qu'après un délai d'attente de 0. J'ai vu cette solution "hacky" dans plusieurs posts mais personne n'explique pourquoi elle fonctionne.

30voto

dshap Points 313

Voici une approche simple utilisant ng-init qui ne nécessite même pas de directive personnalisée. Cela a bien fonctionné pour moi dans certains scénarios, par exemple lorsqu'il s'agit de faire défiler automatiquement une div d'éléments ng-repeated vers un élément particulier au chargement de la page, de sorte que la fonction de défilement doit attendre jusqu'à ce que l'élément ng-repeated soit affiché. ng-repeat a terminé le rendu dans le DOM avant de pouvoir être déclenché.

<div ng-controller="MyCtrl">
    <div ng-repeat="thing in things">
        thing: {{ thing }}
    </div>
    <div ng-init="fireEvent()"></div>
</div>

myModule.controller('MyCtrl', function($scope, $timeout){
    $scope.things = ['A', 'B', 'C'];

    $scope.fireEvent = function(){

        // This will only run after the ng-repeat has rendered its things to the DOM
        $timeout(function(){
            $scope.$broadcast('thingsRendered');
        }, 0);

    };
});

Notez que cela n'est utile que pour les fonctions que vous devez appeler une fois après le rendu initial du ng-repeat. Si vous avez besoin d'appeler une fonction à chaque fois que le contenu de ng-repeat est mis à jour, vous devrez utiliser l'une des autres réponses de ce fil de discussion avec une directive personnalisée.

1 votes

Magnifique, ce produit a fait l'affaire. Je voulais sélectionner automatiquement du texte dans une boîte de texte, et le délai d'attente a fait l'affaire. Sinon, le texte {{model.value}} était sélectionné puis désélectionné lorsque le model.value lié aux données était injecté.

4voto

Cody Points 1198

Cela peut également s'avérer nécessaire lorsque vous vérifiez le scope.$last pour entourer votre déclencheur d'une variable setTimeout(someFn, 0) . A setTimeout 0 est une technique acceptée en javascript et elle était impérative pour mon projet de directive pour fonctionner correctement.

0 votes

J'ai trouvé le même problème. à la fois dans backbone + angular, si vous avez besoin de faire quelque chose comme lire les valeurs des propriétés css appliquées à un élément DOM, je n'ai pas pu trouver un moyen sans le hack du timeout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X