Evento AngularJs da chiamare dopo il caricamento del contenuto


163

Ho una funzione che desidero chiamare dopo il caricamento del contenuto della pagina. Ho letto di $ viewContentLoaded e non funziona per me. Sto cercando qualcosa di simile

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

La chiamata sopra non funziona per me nel controller AngularJs.


1
Questo metodo funziona bene stackoverflow.com/q/14968690/6521116
Kris Roofe

Risposte:


163

Secondo la documentazione di $ viewContentLoaded , dovrebbe funzionare

Emesso ogni volta che viene ricaricato il contenuto di ngView.

$viewContentLoaded viene emesso un evento che significa che per ricevere questo evento è necessario un controller genitore simile

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

Da MainCtrlte puoi ascoltare l'evento

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

Controlla la demo


59
Il problema con questo approccio è che i controller non sono stati completamente inizializzati a questo punto.
Ash Blue,

12
@Reza Ha ragione, questo evento viene generato quando viene aggiunto il dom ma prima che angular abbia terminato l'elaborazione del dom. Puoi verificarlo aggiungendo un ID o una classe come variabile angolare e provare a trovarlo in $ viewContentLoaded con jQuery. Non lo troverai.
Thomas Kekeisen l'

1
@Reza sì, Thomas ha ragione, l'elemento form non può accedere all'interno di $ viewContentLoaded, ad esempio $ scope.formName.elementName. $ SetValidity ("validateRule", false); genererà "TypeError: impossibile leggere la proprietà 'elementName' di undefined"
Mussammil,

2
Lo stesso può essere chiamato a livello di $ rootScope. Invece di $ scope. $ On, dovrebbe essere $ rootScope. $ On e all'interno del blocco app.run ()
Vil

4
Questa opzione non funzionerà in presenza di ng-repeatdiverse direttive nidificate che genereranno HTML / contenuto in base a cicli e condizioni complessi. Il rendering continua per qualche tempo, anche dopo l' $viewContentLoadedattivazione dell'evento. Come puoi assicurarti che tutti gli elementi siano stati completamente renderizzati e quindi eseguire un determinato codice? Qualche feedback?
tarekahf,

104

Angolare <1.6.X

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

Angolare> = 1.6.X

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

Questo va all'interno di app.js?
Zcoon,

3
puoi ascoltarlo nel tuo controller.js
hariszaman

2
Funziona bene anche nel file app.js principale.
Loubot,

Quella risposta funziona per me! Basta vedere che nella pagina dell'elemento della documentazione 'ready () (deprecato, usa angular.element (callback) invece di angular.element (document) .ready (callback))'
Lovera

Questo ha funzionato per me. L'approccio con risposta accettata non funziona all'interno del controller.
Fabiano,

76

fisso - 09.06.2015

Utilizzare una direttiva e il readymetodo dell'elemento angolare in questo modo:

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>

o per coloro che usano la sintassi del controller come ...

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

Il vantaggio di questo è che puoi essere ampio o granulare con la tua UI come preferisci e stai rimuovendo la logica DOM dai tuoi controller. Direi che questo è il modo angolare raccomandato .

Potrebbe essere necessario dare la priorità a questa direttiva nel caso in cui ci siano altre direttive che operano sullo stesso nodo.


sembra un'ottima soluzione, ma non sono riuscito a farlo funzionare. è soffocato a elem.ready( $scope.$apply( readyFunc( $scope ))); Qualche idea sul perché potrebbe essere? Forse è successo un aggiornamento angolare? Comunque - è un approccio elegante, se potesse funzionare.
domoarigato,

1
nm, vedo quale fosse il problema. C'era un refuso sul attrs.onReady, dovrebbe essere quello che è ora. L'altro problema era che lo stavo chiamando funky .... ... quello che ottengo per convertire il coffeescript dalla memoria a JS.
jusopi,

1
Penso che in alcuni casi possa andare bene, ma le mie argomentazioni contrarie sono: penso che le aspettative del suo codice quando guardo solo sia che restituirebbe un valore di testo da visualizzare nel DOM, ergo richiede un occhio attento; Non consente alcun timing in termini di priorità della direttiva, a meno che non si utilizzi, si è bloccati a livello di controller $timeout; Stai creando esplicitamente un addt. Nodo DOM semplicemente per eseguire la logica non dom; È riutilizzabile solo se quel metodo risiede nella gerarchia $ scope in modo tale che gli ambiti figlio lo ereditino; penso solo che sembri male in una prospettiva NG;
jusopi,

5
Ha lavorato per me, dopo l'aggiunta di un $timeout(function() {})intorno al elem.ready(). Altrimenti stava generando un $digest already in progresserrore. Ma comunque, grazie mille! Ho lottato con questo per l'ultima ora.
rkrishnan,

1
Scavare attraverso $ scope sembra essere vuoto. Qualche idea?
MiloTheGreat

66

Puoi chiamarlo direttamente aggiungendo {{YourFunction()}}dopo l'elemento HTML.

Ecco a Plunker Link.


6
Potresti per favore elaborare di più la tua risposta aggiungendo un po 'più di descrizione sulla soluzione che offri?
abarisone,

Penso che tu voglia chiamare una funzione quando viene caricato quell'elemento html. Quindi chiama quella funzione come menzionato sopra. Se la mia ipotesi ha ragione sul tuo dubbio, allora funzionerà altrimenti, per favore, elabora la tua domanda. :)
blu,

14
Quando si chiama una funzione come questa. Assicurati che venga richiamato una volta o altrimenti il ​​ciclo digest verrà eseguito all'infinito e mostrerà un errore
Ashan,

2
mi piace questa soluzione, è davvero così semplice
Kamuran Sönecek il

1
Questo è fantastico - solo un problema. Sembra che la mia funzione venga eseguita 5 volte quando la utilizzo. Ho aggiunto un contatore, quindi funziona bene, ma mi chiedo solo se qualcuno sa perché ciò potrebbe accadere ... Sembra un po 'strano, sai?
itchyspacesuit

22

Ho dovuto implementare questa logica durante la gestione con i grafici di Google. quello che ho fatto è stato che alla fine del mio html all'interno della definizione del controller ho aggiunto.

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

e in quella funzione chiama semplicemente la tua logica.

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

Lo stavo usando ma nella parte superiore della pagina, l'init richiedeva che alcuni div fossero già caricati, quindi spostando ng-init in fondo alla pagina ho risolto il mio problema, un bel suggerimento e ha senso.
Gurnard,

unica risposta che mi ha aiutato con il mio problema (selezione vuota mobile jquery)
kaiser

Questa è la vera risposta in quanto si adatta ai controlli caricati dinamicamente ed è super facile da implementare.
Jason Sebring,

questa risposta mi ha fatto risparmiare un po 'di tempo, così elegante ed efficace per il mio caso d'uso
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
    };

}] );

Il metodo sopra ha funzionato per me


3

puoi chiamare la versione javascript dell'evento onload in js angolare. questo evento ng-load può essere applicato a qualsiasi elemento dom come div, span, body, iframe, img ecc. Di seguito è riportato il link per aggiungere ng-load nel progetto esistente.

scarica ng-load per js angolari

Di seguito è riportato un esempio di iframe, una volta caricato testCallbackFunction verrà chiamato nel controller

ESEMPIO

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>

Aggiungi un codice di esempio per mostrare come l'OP può risolvere il problema
jro

@jro Aggiornato il mio ans. Spero che ti sia utile :)
Darshan Jain,

2

Se ricevi un errore $ digest già in corso, questo potrebbe aiutare:

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'esecuzione dopo il caricamento della pagina dovrebbe essere parzialmente soddisfatta impostando un listener di eventi sull'evento di caricamento della finestra

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

All'interno di module.run(function()...)of angular avrai tutto l'accesso alla struttura del modulo e alle dipendenze.

È possibile broadcasted emiteventi per ponti di comunicazione.

Per esempio:

  • il modulo imposta l'evento onload e costruisce la logica
  • il modulo trasmette l'evento ai controller quando la logica lo richiede
  • i controller ascolteranno ed eseguiranno la propria logica in base ai processi di caricamento del modulo.

0

Stavo usando {{myFunction()}}nel modello, ma poi ho trovato un altro modo qui usando $timeoutall'interno del controller. Ho pensato di condividerlo, funziona benissimo per me.

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

}]);

Ho provato tutte le risposte qui e per qualche motivo, $ timeout è l'unica cosa che ha funzionato per me. Non so perché, ma potrebbe avere qualcosa a che fare con ng-include e i tempi di avvio dei servizi.
Drellgor,

Ne ho aggiunto uno positivo per {{myFunction ()}}
commonpike

0

Se vuoi che un determinato elemento sia completamente caricato, usa ng-init su quell'elemento.

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

la funzione initModalFacultyInfo () dovrebbe esistere nel controller.


0

Ho scoperto che se hai viste nidificate - $ viewContentLoaded viene attivato per ciascuna delle viste nidificate. Ho creato questa soluzione alternativa per trovare $ viewContentLoaded finale. Sembra funzionare bene per l'impostazione di $ window.prerenderReady come richiesto da Prerender (va in .run () in app.js principale):

// 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.");
};
});

Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
rollstuhlfahrer,

0

La soluzione che funziona per me è la seguente

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

Il codice controller è il seguente

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

Il codice HTML è il seguente

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

-31

Io uso setIntervaldi aspettare per il contenuto caricato. Spero che questo possa aiutarti a risolvere quel problema.

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
Le persone raccomandano ancora setIntervalcome soluzione nel 2016 ?
Zachary Dahan,

ma non esiste una semplice API in agular ... come .. come si fa?
Piotr Kula,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.