Événement AngularJs à appeler après le chargement du contenu


164

J'ai une fonction que je souhaite appeler après le chargement du contenu de la page. J'ai lu sur $ viewContentLoaded et cela ne fonctionne pas pour moi. Je cherche quelque chose comme

document.addEventListener('DOMContentLoaded', function () { 
     //Content goes here 
}, false);

L'appel ci-dessus ne fonctionne pas pour moi dans le contrôleur AngularJs.


Réponses:


164

Selon la documentation de $ viewContentLoaded , il est censé fonctionner

Émis chaque fois que le contenu ngView est rechargé.

$viewContentLoaded l'événement est émis, ce qui signifie que pour recevoir cet événement, vous avez besoin d'un contrôleur parent comme

<div ng-controller="MainCtrl">
  <div ng-view></div>
</div>

De MainCtrlvous pouvez écouter l'événement

  $scope.$on('$viewContentLoaded', function(){
    //Here your view content is fully loaded !!
  });

Consultez la démo


59
Le problème avec cette approche est que les contrôleurs ne sont pas complètement initialisés à ce stade.
Ash Blue

12
@Reza Il a raison, cet événement est déclenché lorsque le dom est ajouté mais avant qu'angular n'ait fini de traiter le dom. Vous pouvez tester cela en ajoutant un identifiant ou une classe en tant que variable angulaire et essayer de le trouver dans $ viewContentLoaded avec jQuery. Vous ne le trouverez pas.
Thomas Kekeisen

1
@Reza oui, Thomas a raison, l'élément de formulaire ne peut pas accéder à l'intérieur de $ viewContentLoaded, disons $ scope.formName.elementName. $ SetValidity ("validateRule", false); lancera "TypeError: Impossible de lire la propriété 'elementName' d'undefined"
Mussammil

2
La même chose peut être appelée au niveau $ rootScope. Au lieu de $ scope. $ On, il devrait s'agir de $ rootScope. $ On et à l'intérieur du bloc app.run ()
Vil

4
Cette option ne fonctionnera pas si vous disposez de ng-repeatplusieurs directives imbriquées qui généreront du HTML / Contenu basé sur des boucles et des conditions complexes. Le rendu se poursuit pendant un certain temps, même après le $viewContentLoadeddéclenchement de l'événement. Comment pouvez-vous vous assurer que tous les éléments ont été entièrement rendus, puis exécuter certains codes? Tous les commentaires?
tarekahf

104

Angulaire <1.6.X

angular.element(document).ready(function () {
    console.log('page loading completed');
});

Angulaire> = 1,6.X

angular.element(function () {
    console.log('page loading completed');
});

Cela va-t-il dans le fichier app.js?
zcoon

3
vous pouvez l'écouter dans votre controller.js
hariszaman

2
Fonctionne aussi bien dans le fichier principal app.js.
Loubot

Cette réponse fonctionne pour moi! Voir juste cela sur la page de l'élément de documentation 'ready () (obsolète, utilisez angular.element (callback) au lieu de angular.element (document) .ready (callback))'
Lovera

Cela a fonctionné pour moi. L'approche de réponse acceptée ne fonctionne pas à l'intérieur du contrôleur.
Fabiano

76

fixe - 2015.06.09

Utilisez une directive et la readyméthode d' élément angulaire comme ceci:

js

.directive( 'elemReady', function( $parse ) {
   return {
       restrict: 'A',
       link: function( $scope, elem, attrs ) {    
          elem.ready(function(){
            $scope.$apply(function(){
                var func = $parse(attrs.elemReady);
                func($scope);
            })
          })
       }
    }
})

html

<div elem-ready="someMethod()"></div>

ou pour ceux qui utilisent la syntaxe controller-as ...

<div elem-ready="vm.someMethod()"></div>

L'avantage de ceci est que vous pouvez être aussi large ou granulaire avec votre interface utilisateur que vous le souhaitez et que vous supprimez la logique DOM de vos contrôleurs. Je dirais que c'est la méthode angulaire recommandée .

Vous devrez peut-être donner la priorité à cette directive au cas où vous auriez d'autres directives fonctionnant sur le même nœud.


cela semble être une très bonne solution, mais je ne pouvais pas la faire fonctionner. il a étouffé à elem.ready( $scope.$apply( readyFunc( $scope ))); Des idées pourquoi cela pourrait être? Peut-être qu'une mise à jour d'angular s'est produite? Quoi qu'il en soit - c'est une approche élégante, si cela peut fonctionner.
domoarigato

1
nm, je vois quel était le problème. Il y avait une faute de frappe sur le attrs.onReady, devrait être ce qu'il est maintenant. L'autre problème était que je l'appelais funky ... ... ce que j'obtiens pour la conversion de coffeescript de mémoire en JS.
jusopi

1
Je pense que dans certains cas, cela peut être bien, mais mes arguments contre sont les suivants: je pense que les attentes de son code quand il suffit de jeter un coup d'œil sont que cela renverrait une valeur de texte à afficher dans le DOM, ergo cela nécessite un œil attentif; Il n'autorise aucun timing en termes de priorité directive, vous êtes bloqué au niveau du contrôleur à moins que vous n'utilisiez $timeout; Vous créez explicitement un addt. Nœud DOM simplement pour exécuter une logique non-dom; Elle n'est réutilisable que si cette méthode se trouve loin dans la hiérarchie $ scope de telle sorte que les étendues enfants en héritent, je pense juste que ça a l'air mauvais dans une perspective NG;
jusopi

5
A travaillé pour moi après avoir ajouté un $timeout(function() {})autour du elem.ready(). Sinon, c'était une $digest already in progresserreur. Mais de toute façon, merci beaucoup! Je me débat avec cela depuis une heure.
rkrishnan

1
Creuser dans la portée $ semble être vide. Des idées?
MiloTheGreat

66

Vous pouvez l'appeler directement en ajoutant {{YourFunction()}}après l'élément HTML.

Voici un Plunker Link.


6
Pourriez-vous s'il vous plaît élaborer davantage votre réponse en ajoutant un peu plus de description de la solution que vous fournissez?
abarisone

Je pense que vous voulez appeler une fonction lorsque cet élément html est chargé. Appelez donc cette fonction comme mentionné ci-dessus. Si je suppose que votre doute est juste, cela fonctionnera sinon, veuillez élaborer votre question. :)
bleu

14
Lors de l'appel d'une fonction comme celle-ci. Assurez-vous qu'il est invoqué une fois ou sinon le cycle de digestion fonctionnera à l'infini et affiche une erreur
Ashan

2
j'aime cette solution, c'est vraiment si simple
Kamuran Sönecek

1
C'est fantastique - un seul problème. Il semble que ma fonction s'exécute 5 fois lorsque je l'utilise. J'ai ajouté un compteur donc ça marche bien mais je me demande juste si quelqu'un sait pourquoi cela se produirait ... Cela semble un peu étrange vous savez?
itchyspacesuit

22

J'ai dû implémenter cette logique lors de la manipulation des graphiques Google. ce que j'ai fait, c'est qu'à la fin de ma définition de contrôleur html inside, j'ai ajouté.

  <body>
         -- some html here -- 
--and at the end or where ever you want --
          <div ng-init="FunCall()"></div>
    </body>

et dans cette fonction, appelez simplement votre logique.

$scope.FunCall = function () {
        alert("Called");
}

J'utilisais cela mais en haut de la page, l'initialisation nécessitait déjà le chargement de certains div, donc en déplaçant le ng-init vers le bas de la page, j'ai résolu mon problème, une belle astuce et cela a du sens.
Gurnard

seule réponse qui m'a aidé avec mon problème (sélection vide de jquery mobile)
kaiser

C'est la vraie réponse car il s'adapte aux contrôles chargés dynamiquement et est super facile à mettre en œuvre.
Jason Sebring

cette réponse m'a fait gagner du temps, si élégant et efficace pour mon cas d'utilisation
Sello

4
var myM = angular.module('data-module');

myM.directive('myDirect',['$document', function( $document ){

    function link( scope , element , attrs ){

        element.ready( function(){

        } );

        scope.$on( '$viewContentLoaded' , function(){

            console.log(" ===> Called on View Load ") ;

        } );

    }

    return {
        link: link
    };

}] );

La méthode ci-dessus a fonctionné pour moi


3

vous pouvez appeler la version javascript de l'événement onload dans angular js. cet événement ng-load peut être appliqué à n'importe quel élément dom comme div, span, body, iframe, img etc. Voici le lien pour ajouter ng-load dans votre projet existant.

télécharger ng-load pour angular js

Voici un exemple pour iframe, une fois qu'il est chargé testCallbackFunction sera appelé dans le contrôleur

EXEMPLE

JS

    // include the `ngLoad` module
    var app = angular.module('myApp', ['ngLoad']);
    app.controller('myCtrl', function($scope) {
        $scope.testCallbackFunction = function() {
          //TODO : Things to do once Element is loaded
        };

    });  

HTML

  <div ng-app='myApp' ng-controller='myCtrl'> 
      <iframe src="test.html" ng-load callback="testCallbackFunction()">  
  </div>

Veuillez ajouter un exemple de code pour montrer comment l'OP peut résoudre le problème
jro

@jro a mis à jour mes ans. J'espère que cela vous sera utile :)
Darshan Jain

2

Si vous obtenez une erreur $ digest déjà en cours, cela peut aider:

return {
        restrict: 'A',
        link: function( $scope, elem, attrs ) {
            elem.ready(function(){

                if(!$scope.$$phase) {
                    $scope.$apply(function(){
                        var func = $parse(attrs.elemReady);
                        func($scope);
                    })
                }
                else {

                    var func = $parse(attrs.elemReady);
                    func($scope);
                }

            })
        }
    }

0

L'exécution après le chargement de la page doit être partiellement satisfaite en définissant un écouteur d'événement sur l'événement de chargement de fenêtre

window.addEventListener("load",function()...)

À l'intérieur module.run(function()...)de angular, vous aurez tous accès à la structure du module et aux dépendances.

Vous pouvez broadcastet des emitévénements pour les ponts de communication.

Par exemple:

  • module définit l'événement onload et la logique de construction
  • événement de diffusion du module aux contrôleurs lorsque la logique l'exige
  • les contrôleurs écouteront et exécuteront leur propre logique basée sur les processus de chargement du module.

0

J'utilisais {{myFunction()}}dans le modèle, mais j'ai ensuite trouvé un autre moyen d' utiliser ici$timeout le contrôleur. Je pensais que je le partagerais, cela fonctionne très bien pour moi.

angular.module('myApp').controller('myCtrl', ['$timeout',
function($timeout) {
var self = this;

self.controllerFunction = function () { alert('controller function');}

$timeout(function () {
    var vanillaFunction = function () { alert('vanilla function'); }();
    self.controllerFunction();
});

}]);

J'ai essayé toutes les réponses ici et pour une raison quelconque, $ timeout est la seule chose qui a fonctionné pour moi. Je ne sais pas pourquoi, mais cela pourrait avoir quelque chose à voir avec ng-include et le moment du lancement des services.
Drellgor

J'ai ajouté un plus un pour {{myFunction ()}}
commonpike

0

Si vous voulez que certains éléments soient complètement chargés, utilisez ng-init sur cet élément.

par exemple <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>

la fonction initModalFacultyInfo () doit exister dans le contrôleur.


0

J'ai trouvé que si vous avez des vues imbriquées - $ viewContentLoaded est déclenché pour chacune des vues imbriquées. J'ai créé cette solution de contournement pour trouver le $ viewContentLoaded final. Semble bien fonctionner pour définir $ window.prerenderReady comme requis par Prerender (va dans .run () dans l'application principale.js):

// Trigger $window.prerenderReady once page is stable
// Note that since we have nested views - $viewContentLoaded is fired multiple
// times and we need to go around this problem
var viewContentLoads = 0;
var checkReady = function(previousContentLoads) {
  var currentContentLoads = Number(viewContentLoads) + 0; // Create a local copy of the number of loads
  if (previousContentLoads === currentContentLoads) { // Check if we are in a steady state
    $window.prerenderReady = true; // Raise the flag saying we are ready
  } else {
    if ($window.prerenderReady || currentContentLoads > 20) return; // Runaway check
    $timeout(function() {checkReady(currentContentLoads);}, 100); // Wait 100ms and recheck
  }
};
$rootScope.$on('$stateChangeSuccess', function() {
  checkReady(-1); // Changed the state - ready to listen for end of render
});
$rootScope.$on('$viewContentLoaded', function() {
  viewContentLoads ++;
});

0
var myTestApp = angular.module("myTestApp", []); 
myTestApp.controller("myTestController", function($scope, $window) {
$window.onload = function() {
 alert("is called on page load.");
};
});

Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
rollstuhlfahrer

0

La solution qui fonctionne pour moi est la suivante

app.directive('onFinishRender', ['$timeout', '$parse', function ($timeout, $parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                    if (!!attr.onFinishRender) {
                        $parse(attr.onFinishRender)(scope);
                    }
                });
            }

            if (!!attr.onStartRender) {
                if (scope.$first === true) {
                    $timeout(function () {
                        scope.$emit('ngRepeatStarted');
                        if (!!attr.onStartRender) {
                            $parse(attr.onStartRender)(scope);
                        }
                    });
                }
            }
        }
    }
}]);

Le code du contrôleur est le suivant

$scope.crearTooltip = function () {
     $('[data-toggle="popover"]').popover();
}

Le code HTML est le suivant

<tr ng-repeat="item in $data" on-finish-render="crearTooltip()">

-31

J'attends setIntervalle contenu chargé. J'espère que cela peut vous aider à résoudre ce problème.

var $audio = $('#audio');
var src = $audio.attr('src');
var a;
a = window.setInterval(function(){
    src = $audio.attr('src');
    if(src != undefined){
        window.clearInterval(a);
        $('audio').mediaelementplayer({
            audioWidth: '100%'
        });
    }
}, 0);

13
Les gens sont-ils toujours recommandés setIntervalcomme solution en 2016 ?
Zachary Dahan

mais il n'y a pas d'API simple dans agular ... comment .. comment faire?
Piotr Kula
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.