AngularJs Ereignis, das nach dem Laden des Inhalts aufgerufen werden soll

163

Ich habe eine Funktion, die ich aufrufen möchte, nachdem der Seiteninhalt geladen wurde. Ich habe über $ viewContentLoaded gelesen und es funktioniert bei mir nicht. Ich suche so etwas wie

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

Der obige Anruf funktioniert bei AngularJs Controller nicht.

user3233772
quelle
1
Dies funktioniert gut stackoverflow.com/q/14968690/6521116
Kris Roofe

Antworten:

163

Laut Dokumentation von $ viewContentLoaded sollte es funktionieren

Wird jedes Mal ausgegeben, wenn der ngView-Inhalt neu geladen wird.

$viewContentLoaded Ereignis wird ausgegeben, was bedeutet, dass Sie zum Empfangen dieses Ereignisses einen übergeordneten Controller wie benötigen

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

Von können MainCtrlSie das Ereignis hören

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

Überprüfen Sie die Demo

Tasnim Reza
quelle
59
Das Problem bei diesem Ansatz besteht darin, dass die Steuerungen zu diesem Zeitpunkt noch nicht vollständig initialisiert wurden.
Ash Blue
12
@Reza Er hat Recht, dieses Ereignis wird ausgelöst, wenn der Dom hinzugefügt wird, aber bevor Angular die Verarbeitung des Doms beendet hat. Sie können dies testen, indem Sie eine ID oder Klasse als Winkelvariable hinzufügen und versuchen, sie in $ viewContentLoaded with jQuery zu finden. Sie werden es nicht finden.
Thomas Kekeisen
1
@Reza Ja, Thomas hat Recht, auf das Formularelement kann nicht innerhalb von $ viewContentLoaded zugreifen. Sagen wir $ scope.formName.elementName. $ SetValidity ("validateRule", false); wird "TypeError: Eigenschaft 'elementName' von undefined kann nicht gelesen werden"
Mussammil
2
Dasselbe kann auf $ rootScope-Ebene aufgerufen werden. Anstelle von $ scope. $ On sollte es $ rootScope. $ On und innerhalb des app.run ()
Vil
4
Diese Option funktioniert nicht, wenn Sie ng-repeatmehrere verschachtelte Anweisungen haben, die HTML / Inhalt basierend auf komplexen Schleifen und Bedingungen generieren. Das Rendern wird einige Zeit fortgesetzt, auch nachdem ein $viewContentLoadedEreignis ausgelöst wurde. Wie können Sie sicherstellen, dass alle Elemente vollständig gerendert wurden, und dann bestimmten Code ausführen? Irgendeine Anregung?
Tarekahf
104

Winkel <1.6.X

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

Winkel> = 1.6.X.

angular.element(function () {
    console.log('page loading completed');
});
Hariszaman
quelle
Geht das in die app.js?
Zcoon
3
Sie können es in Ihren controller.js
hariszaman
2
Funktioniert auch in der Hauptdatei app.js einwandfrei.
Loubot
Diese Antwort funktioniert bei mir! Sehen Sie einfach, dass auf der Dokumentationselementseite 'ready () (veraltet, verwenden Sie angle.element (Rückruf) anstelle von angle.element (document) .ready (Rückruf))'
Lovera
Das hat bei mir funktioniert. Der akzeptierte Antwortansatz funktioniert nicht innerhalb des Controllers.
Fabiano
76

fest - 2015.06.09

Verwenden Sie eine Direktive und die Winkelelementmethode readywie folgt:

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>

oder für diejenigen, die Controller-als- Syntax verwenden ...

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

Dies hat den Vorteil, dass Sie mit Ihrer Benutzeroberfläche so breit oder detailliert sein können, wie Sie möchten, und dass Sie die DOM-Logik von Ihren Controllern entfernen. Ich würde argumentieren, dass dies der empfohlene Winkelweg ist .

Möglicherweise müssen Sie diese Anweisung priorisieren, falls andere Anweisungen auf demselben Knoten ausgeführt werden.

jusopi
quelle
Das sieht nach einer wirklich guten Lösung aus, aber ich konnte es nicht zum Laufen bringen. es erstickte an elem.ready( $scope.$apply( readyFunc( $scope ))); Irgendwelche Ideen, warum das sein könnte? Vielleicht ist ein Update auf Angular passiert? Wie auch immer - es ist ein eleganter Ansatz, wenn es funktionieren könnte.
Domoarigato
1
nm, ich sehe, was das Problem war. Es gab einen Tippfehler auf dem attrs.onReady, sollte sein, was es jetzt ist. Das andere Problem war, dass ich es funky nannte ... ... was ich für die Konvertierung von Kaffeeskript aus dem Speicher in JS bekomme.
Jusopi
1
Ich denke, in bestimmten Fällen mag das in Ordnung sein, aber meine Argumente dagegen sind: Ich denke, die Erwartungen an seinen Code, wenn man nur einen Blick darauf wirft, sind, dass dies einen Textwert zurückgeben würde, der im DOM angezeigt wird, daher erfordert es ein sorgfältiges Auge; Es erlaubt kein Timing in Bezug auf die Direktivenpriorität. Sie stecken auf der Controller-Ebene fest, es sei denn, Sie verwenden $timeout; Sie erstellen explizit ein Addt. DOM-Knoten, um einfach Nicht-Dom-Logik auszuführen; Es ist nur wiederverwendbar, wenn sich diese Methode weit oben in der $ scope-Hierarchie befindet, sodass untergeordnete Bereiche sie erben. Ich denke nur, dass sie aus NG-Sicht schlecht aussieht.
Jusopi
5
Arbeitete für mich nach dem Hinzufügen eines $timeout(function() {})um die elem.ready(). Ansonsten wurde ein $digest already in progressFehler ausgegeben. Aber trotzdem, vielen Dank! Ich habe in der letzten Stunde damit zu kämpfen.
Rkrishnan
1
Das Durchsuchen des $ -Bereichs scheint leer zu sein. Irgendwelche Ideen?
MiloTheGreat
66

Sie können es direkt aufrufen, indem Sie {{YourFunction()}}nach dem HTML-Element hinzufügen .

Hier ist ein Plunker Link.

Blau
quelle
6
Könnten Sie bitte Ihre Antwort näher erläutern und etwas mehr Beschreibung der von Ihnen bereitgestellten Lösung hinzufügen?
Abarisone
Ich denke, Sie möchten eine Funktion aufrufen, wenn dieses HTML-Element geladen wird. Rufen Sie diese Funktion also wie oben erwähnt auf. Wenn meine Vermutung über Ihren Zweifel richtig ist, wird dies ansonsten funktionieren. Bitte erläutern Sie Ihre Frage. :)
blau
14
Beim Aufruf einer solchen Funktion. Stellen Sie sicher, dass der Digest-Zyklus einmal oder auf andere Weise unendlich ausgeführt wird und einen Fehler anzeigt
Ashan,
2
Ich mag diese Lösung, es ist wirklich so einfach
Kamuran Sönecek
1
Das ist fantastisch - nur ein Problem. Es scheint, dass meine Funktion 5 Mal ausgeführt wird, wenn ich dies verwende. Ich habe einen Zähler hinzugefügt, damit es gut funktioniert, aber ich frage mich nur, ob jemand weiß, warum das passieren würde ... Scheint ein bisschen seltsam, weißt du?
Juckreiz-Raumanzug
22

Ich musste diese Logik beim Umgang mit Google Charts implementieren. Was ich getan habe war, dass ich am Ende meines HTML-Codes innerhalb der Controller-Definition hinzugefügt habe.

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

und in dieser Funktion rufen Sie einfach Ihre Logik auf.

$scope.FunCall = function () {
        alert("Called");
}
Saad Zulfiqar
quelle
Ich habe dies verwendet, aber oben auf der Seite musste für das Init bereits ein Div geladen werden. Durch Verschieben des ng-init an den unteren Rand der Seite wurde mein Problem behoben. Ein netter Tipp, und es macht Sinn.
Gurnard
nur antworten , das half mir bei meinem Problem (jQuery Mobile leere Auswahl)
kaiser
Dies ist die eigentliche Antwort, da es sich an dynamisch geladene Steuerelemente anpasst und sehr einfach zu implementieren ist.
Jason Sebring
Diese Antwort hat mir einige Zeit gespart, so elegant und effektiv für meinen Anwendungsfall
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
    };

}] );

Die obige Methode hat bei mir funktioniert

Alok D.
quelle
3

Sie können die Javascript-Version des Onload-Ereignisses in eckigen js aufrufen. Dieses ng-load-Ereignis kann auf jedes dom-Element wie div, span, body, iframe, img usw. angewendet werden. Über den folgenden Link können Sie ng-load in Ihr vorhandenes Projekt einfügen.

Download ng-load für eckige js

Das folgende Beispiel für iframe zeigt, dass testCallbackFunction nach dem Laden im Controller aufgerufen wird

BEISPIEL

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>
Darshan Jain
quelle
Bitte fügen Sie einen Beispielcode hinzu, um zu zeigen, wie das OP das Problem lösen kann
jro
@jro Aktualisiert meine ans. Hoffe es wird hilfreich sein :)
Darshan Jain
2

Wenn Sie einen bereits laufenden $ Digest-Fehler erhalten, kann dies helfen:

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

            })
        }
    }
John Smith
quelle
0

Das Ausführen nach dem Laden der Seite sollte teilweise erfüllt werden, indem ein Ereignis-Listener auf das Fensterladeereignis gesetzt wird

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

Innerhalb module.run(function()...)des Winkels haben Sie Zugriff auf die Modulstruktur und die Abhängigkeiten.

Sie können broadcastund emitEreignisse für Kommunikationsbrücken.

Beispielsweise:

  • Modul Set Onload Event und Build Logik
  • Modul-Broadcast-Ereignis an Steuerungen, wenn die Logik dies erfordert
  • Controller hören zu und führen ihre eigene Logik basierend auf Modul-Onload-Prozessen aus.
Luis D. Vazquez Rivera
quelle
0

Ich habe {{myFunction()}}in der Vorlage verwendet, aber dann hier einen anderen Weg gefunden, indem ich $timeoutinnerhalb des Controllers verwendet habe. Ich dachte, ich würde es teilen, funktioniert großartig für mich.

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

}]);
Nhan
quelle
Ich habe alle Antworten hier ausprobiert und aus irgendeinem Grund ist $ timeout das einzige, was für mich funktioniert hat. Ich weiß nicht warum, aber es könnte etwas mit ng-include und dem Zeitpunkt der Initiierung von Diensten zu tun haben.
Drellgor
Ich habe ein Plus für {{myFunction ()}}
commonpike
0

Wenn ein bestimmtes Element vollständig geladen werden soll, verwenden Sie ng-init für dieses Element.

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

Die Funktion initModalFacultyInfo () sollte in der Steuerung vorhanden sein.

NetDeveloper
quelle
0

Ich habe festgestellt, dass bei verschachtelten Ansichten $ viewContentLoaded für jede verschachtelte Ansicht ausgelöst wird. Ich habe diese Problemumgehung erstellt, um das endgültige $ viewContentLoaded zu finden. Scheint in Ordnung zu sein, um $ window.prerenderReady wie von Prerender gefordert festzulegen (geht in .run () in der Haupt-App.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 ++;
});
Maksym
quelle
0
var myTestApp = angular.module("myTestApp", []); 
myTestApp.controller("myTestController", function($scope, $window) {
$window.onload = function() {
 alert("is called on page load.");
};
});
Shreyansh Kumar
quelle
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Rollstuhlfahrer
0

Die Lösung, die für mich funktioniert, ist die folgende

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

Der Controller-Code lautet wie folgt

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

HTML-Code ist der folgende

<tr ng-repeat="item in $data" on-finish-render="crearTooltip()">
Jorge Santos Neill
quelle
-31

Ich setIntervalwarte auf den geladenen Inhalt. Ich hoffe, dies kann Ihnen helfen, dieses Problem zu lösen.

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);
Xiangry
quelle
13
Werden die Leute 2016 noch setIntervalals Lösung empfehlen ?
Zachary Dahan
aber es gibt keine einfache api in agular ... wie ... wie geht das?
Piotr Kula