68 votes

Exécuter le code jQuery après qu'AngularJS ait terminé le rendu du HTML

Dans le contrôleur, je reçois des données JSON en utilisant les services $http ou $resource. Ensuite, j'écris ces données dans $scope et AngularJS met à jour la structure HTML de la page. Mon problème est que j'ai besoin de savoir quelle est la nouvelle taille (largeur et hauteur) de la liste (je veux dire, l'élément HTML DOM) qui est remplie par AngularJS. ng-repeat directive. Par conséquent, je dois exécuter du code javascript juste après qu'Angular ait fini de mettre à jour la structure du DOM. Quelle est la bonne façon de procéder ? J'ai cherché sur Internet pendant les quatre dernières heures mais je n'ai pas trouvé de solution à mon problème.

C'est ainsi que je reçois des données JSON :

var tradesInfo = TradesInfo.get({}, function(data){
    console.log(data);
    $scope.source.profile = data.profile;
            $scope.trades = $scope.source.profile.trades;
        $scope.activetrade = $scope.trades[0];
        $scope.ready = true;

    init();  //I need to call this function after update is complete

});

Et c'est ce qui se passe dans init() fonction :

function init(){
    alert($('#wrapper').width());
    alert($('#wrapper').height());
}

Je sais qu'il doit exister un moyen simple de résoudre ce problème, mais je n'arrive pas à le trouver maintenant. Merci d'avance.

63voto

Olivér Kovács Points 1471

En fait, dans ce cas, la méthode angulaire n'est pas la méthode facile, mais la seule méthode correcte :)

Vous devez écrire une directive et l'attacher à l'élément dont vous voulez connaître la hauteur. Et depuis le contrôleur, vous $broadcast un événement, la directive va attraper l'événement et là vous pouvez faire la manipulation du DOM. JAMAIS dans le contrôleur.

var tradesInfo = TradesInfo.get({}, function(data){
    console.log(data);
    $scope.source.profile = data.profile;
    ...

    $scope.$broadcast('dataloaded');
});

directive('heightStuff', ['$timeout', function ($timeout) {
    return {
        link: function ($scope, element, attrs) {
            $scope.$on('dataloaded', function () {
                $timeout(function () { // You might need this timeout to be sure its run after DOM render.
                    element.width()
                    element.height()
                }, 0, false);
            })
        }
    };
}]);

5voto

user3484816 Points 1

Une autre suggestion consiste à travailler avec JQuery. J'ai dû travailler sur une grille qui a été générée dans une directive. Je voulais faire défiler jusqu'à une ligne spécifique de la grille. Utilisez $emit pour diffuser de la directive au contrôleur parent :

Dans le contrôleur :

    ['$timeout',function($timeout){
...
 $scope.$on('dataloaded', function () {
            $timeout(function () { // You might need this timeout to be sure its run after DOM render.
                $scope.scrollToPosition();
            }, 0, false);
        });
        $scope.scrollToPosition = function () {
            var rowpos = $('#row_' + $scope.selectedActionID, "#runGrid").position();
            var tablepost = $('table', "#runGrid").position();
            $('#runGrid').scrollTop(rowpos.top - tablepost.top);
        }

Dans la directive

.directive('runGrid',['$timeout', function ($timeout) {
        // This directive generates the grip of data
        return {
            restrict: 'E',  //DOM Element
            scope: {    //define isolated scope
                list: '=',   //use the parent object
                selected: "="
            },

            templateUrl: '/CampaignFlow/StaticContent/Runs/run.grid.0.0.0.0.htm',  //HTML template URL

            controller: ['$scope', function ($scope) {  //the directive private controller, whith its private scope
                //$scope.statusList = [{ data_1: 11, data_2: 12 }, { data_1: 21, data_2: 22 }, { data_1: 31, data_2: 32 }];
                //Controller contains sort functionallity

                $scope.sort = { column: null, direction: 1 }
                $scope.column = null;
                $scope.direction = "asc";
                $scope.sortColumn = function (id) {
                    if(id!=$scope.column) {
                        $scope.column = id;
                        $scope.direction = "asc";
                    } else {
                        $scope.column = null;
                    }
                }
                $scope.toggleDir = function () {
                    $scope.direction = ($scope.direction == "asc") ? "desc" : "asc";
                }
               $scope.$emit('dataloaded');
            }]

        };
    }])

Et voici un extrait du modèle html de la directive de la grille :

 <div style="overflow-y:auto;height: 200px;" id="runGrid">
            <table class="table table-striped" style="table-layout:fixed">
           <tbody>
                <tr  ng-repeat="status in list" id="row_{{status.action_id}}" ng-class="(status.action_id==selected)?'selected':''">
                    <td>

les paramètres de la liste et de la sélection sont injectés depuis le html qui utilise la directive.

<run-grid list="list" selected="selectedActionID"></run-grid>

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