249 votes

Appel d’une fonction répétition ng terminée

Ce que je suis en train de mettre en œuvre est fondamentalement une "sur ng répéter fini de rendre" gestionnaire. Je suis en mesure de détecter quand il est fait, mais je ne peux pas comprendre comment déclencher une fonction à partir d'elle.

Vérifier le violon:http://jsfiddle.net/paulocoelho/BsMqq/3/

JS

var module = angular.module('testApp', [])
    .directive('onFinishRender', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                element.ready(function () {
                    console.log("calling:"+attr.onFinishRender);
                    // CALL TEST HERE!
                });
            }
        }
    }
});

function myC($scope) {
    $scope.ta = [1, 2, 3, 4, 5, 6];
    function test() {
        console.log("test executed");
    }
}

HTML

<div ng-app="testApp" ng-controller="myC">
    <p ng-repeat="t in ta" on-finish-render="test()">{{t}}</p>
</div>

Réponse: Travail de violon de finishingmove: http://jsfiddle.net/paulocoelho/BsMqq/4/

400voto

finishingmove Points 7927
var module = angular.module('testApp', [])
    .directive('onFinishRender', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                });
            }
        }
    }
});

Notez que je n'ai pas utiliser .ready (), mais plutôt enveloppé dans un $timeout. $timeout permet de s'assurer qu'il est exécuté lorsque le ng-éléments répétés ont VRAIMENT rendu terminé (parce que le $timeout a lieu à la fin de l'actuel digérer cycle -- et il sera également appeler $s'appliquent à l'interne, à la différence de setTimeout). Ainsi, après la ng-repeat a fini, nous utilisons $émettre d'émettre un événement à l'extérieur étendues (frère et parent étendues).

Et puis dans votre contrôleur, vous pouvez le prendre avec $sur:

$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
    //you also get the actual event object
    //do stuff, execute functions -- whatever...
});

89voto

Mark Rajcok Points 85912

Utiliser $evalAsync si vous voulez que votre rappel (c'est à dire, le test()) est exécutée lorsque le DOM est construit, mais avant le rend navigateur. Cela permettra d'éviter le scintillement -- ref.

if (scope.$last) {
   scope.$evalAsync(attr.onFinishRender);
}

Le violon.

Si vous voulez vraiment appeler votre rappel après le rendu, utilisez: $timeout:

if (scope.$last) {
   $timeout(function() { 
      scope.$eval(attr.onFinishRender);
   });
}

Je préfère $eval au lieu d'un événement. Avec un événement, nous avons besoin de connaître le nom de l'événement et ajoutez le code pour notre contrôleur pour cet événement. Avec $eval, il y a moins de couplage entre le contrôleur et la directive.

29voto

Josep Points 5467

Les réponses qui ont été données jusqu'ici ne fonctionnera que la première fois que l' ng-repeat est rendu, mais si vous avez une dynamique ng-repeat, ce qui signifie que vous allez à ajouter/supprimer/filtrage des éléments, et vous devez être notifié à chaque fois que l' ng-repeat est rendu, ces solutions ne fonctionnent pas pour vous.

Donc, si vous avez besoin d'être informé CHAQUE FOIS que l' ng-repeat obtient un nouveau rendu , et pas seulement la première fois, j'ai trouvé un moyen de le faire, c'est tout à fait "hacky", mais il fonctionnera bien si vous savez ce que vous faites. Utilisez cette $filter votre ng-repeat avant d'utiliser tout autre $filter:

.filter('ngRepeatFinish', function($timeout){
    return function(data){
        var me = this;
        var flagProperty = '__finishedRendering__';
        if(!data[flagProperty]){
            Object.defineProperty(
                data, 
                flagProperty, 
                {enumerable:false, configurable:true, writable: false, value:{}});
            $timeout(function(){
                    delete data[flagProperty];                        
                    me.$emit('ngRepeatFinished');
                },0,false);                
        }
        return data;
    };
})

Ce sera $emit un événement appelé ngRepeatFinished chaque fois que l' ng-repeat est rendu.

Comment l'utiliser:

<li ng-repeat="item in (items|ngRepeatFinish) | filter:{name:namedFiltered}" >

L' ngRepeatFinish filtre doit être appliqué directement à un Array ou Object défini dans votre $scope, vous pouvez appliquer d'autres filtres après.

Comment ne PAS l'utiliser:

<li ng-repeat="item in (items | filter:{name:namedFiltered}) | ngRepeatFinish" >

Ne pas appliquer d'autres filtres d'abord et ensuite appliquer l' ngRepeatFinish filtre.

Quand devrais-je utiliser?

Si vous souhaitez appliquer des styles css dans le DOM après la liste a fini de rendre, parce que vous devez avoir en compte les nouvelles dimensions des éléments du DOM qui ont été rendus par l' ng-repeat. (BTW: ces opérations doivent être effectuées à l'intérieur d'une directive)

Quoi NE PAS faire dans la fonction qui gère l' ngRepeatFinished événement:

  • Ne pas effectuer l' $scope.$apply dans cette fonction ou de vous mettre Angulaire dans une boucle sans fin qui Angulaire de ne pas être en mesure de détecter.

  • Ne pas l'utiliser pour faire des changements dans la $scope propriétés, car ces modifications ne seront pas prises en compte dans votre vue jusqu'à la prochaine $digest boucle, et puisque vous ne pouvez pas effectuer de $scope.$apply ils ne seront pas de toute utilisation.

"Mais les filtres ne sont pas destinés à être utilisés comme ca!!!!"

Non, ils ne le sont pas, c'est un hack, si vous ne l'aimez pas, ne l'utilisez pas. Si vous connaissez un meilleur moyen pour accomplir la même chose s'il vous plaît laissez-moi savoir.

Résumant

C'est un hack, et de l'aide dans le mauvais sens est dangereux de l'utiliser uniquement pour l'application de styles après l' ng-repeat a fini de rendre et vous ne devriez pas avoir de problèmes.

5voto

John Harley Points 11

Les autres solutions fonctionnent bien sur le chargement initial de la page, mais en l'appelant $timeout du contrôleur est la seule façon de s'assurer que votre fonction est appelée lorsque le modèle change. Ici, c'est un travail de violon qui utilise $timeout. Pour votre exemple, il serait:

.controller('myC', function ($scope, $timeout) {
$scope.$watch("ta", function (newValue, oldValue) {
    $timeout(function () {
       test();
    });
});

ngRepeat évaluera uniquement d'une directive, lorsque la ligne de contenu est nouveau, donc, si vous supprimez des éléments de votre liste, onFinishRender ne se déclenchera pas. Par exemple, essayez d'entrer les valeurs de filtre dans ces violons émettent.

0voto

rajkamal Points 3409

S’il vous plaît jeter un oeil sur le violon, http://jsfiddle.net/yNXS2/. Étant donné que la directive que vous avez créé n’a pas créé une nouvelle portée, que j’ai continué dans la voie.

``fait qu’arriver.

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