Wie führe ich die AngularJS-Controller-Funktion beim Laden der Seite aus?


359

Derzeit habe ich eine Angular.js-Seite, auf der gesucht und Ergebnisse angezeigt werden können. Der Benutzer klickt auf ein Suchergebnis und dann auf die Schaltfläche Zurück. Ich möchte, dass die Suchergebnisse erneut angezeigt werden, kann jedoch nicht herausfinden, wie die Ausführung der Suche ausgelöst wird. Hier ist das Detail:

  • Meine Angular.js-Seite ist eine Suchseite mit einem Suchfeld und einer Suchschaltfläche. Der Benutzer kann eine Abfrage manuell eingeben und eine Taste drücken. Die Ajax-Abfrage wird ausgelöst und die Ergebnisse werden angezeigt. Ich aktualisiere die URL mit dem Suchbegriff. Das alles funktioniert gut.
  • Der Benutzer klickt auf ein Ergebnis der Suche und wird auf eine andere Seite weitergeleitet - das funktioniert auch gut.
  • Der Benutzer klickt auf die Schaltfläche "Zurück" und kehrt zu meiner Winkelsuchseite zurück. Die richtige URL wird angezeigt, einschließlich des Suchbegriffs. Alles funktioniert gut.
  • Ich habe den Suchfeldwert an den Suchbegriff in der URL gebunden, sodass er den erwarteten Suchbegriff enthält. Alles funktioniert gut.

Wie kann ich die Suchfunktion erneut ausführen, ohne dass der Benutzer die "Suchtaste" drücken muss? Wenn es jquery wäre, würde ich eine Funktion in der documentready-Funktion ausführen. Ich kann das Angular.js-Äquivalent nicht sehen.


verwenden Sie $routepProvider? Verwenden Sie diese Option, um eine Verbindung zu einem Dienst in Ihrer App herzustellen, der Daten für die Suchergebnisse bereitstellt. Denken Sie nicht document.readywie bei jQuery. Es ist schwer, viel zu helfen, ohne zu sehen, wie Sie die Suche derzeit verkabelt haben
charlietfl

Antworten:


430

Einerseits, wie @ Mark-Rajcok sagte, kann man einfach mit einer privaten inneren Funktion davonkommen:

// at the bottom of your controller
var init = function () {
   // check if there is query in url
   // and fire search in case its value is not empty
};
// and fire it after definition
init();

Sie können sich auch die ng-init- Direktive ansehen . Die Implementierung wird ähnlich sein wie:

// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>

// in controller
$scope.init = function () {
    // check if there is query in url
    // and fire search in case its value is not empty
};

Aber seien Sie vorsichtig, da die eckige Dokumentation (seit Version 1.2) impliziert , dass Sie das NICHT verwenden sollten ng-init. Wie auch immer, es hängt von der Architektur Ihrer App ab.

Ich habe verwendet, ng-initals ich einen Wert vom Back-End an die Winkel-App übergeben wollte:

<div data-ng-controller="myCtrl" data-ng-init="init('%some_backend_value%')"></div>

6
@Duke, kannst du nicht einfach den Inhalt der init () - Funktion am unteren Rand deines Controllers platzieren? Dh warum müssen Sie ng-init verwenden und eine init () -Funktion haben? Wenn der Benutzer auf die Schaltfläche "Zurück" klickt, wird davon ausgegangen, dass Sie die Ansicht wechseln. Daher wird ein neuer myCtrlController erstellt und ausgeführt.
Mark Rajcok

24
Während diese Lösung funktioniert, habe ich ein Downvoting durchgeführt, da die ng-init-Dokumentation davon abrät. Insbesondere: "Die einzig geeignete Verwendung von ngInit für das Aliasing spezieller Eigenschaften von ngRepeat, wie in der folgenden Demo gezeigt. Außerdem sollten Sie in diesem Fall Controller anstelle von ngInit verwenden, um Werte in einem Bereich zu initialisieren."
Jason Capriotti

1
Der Controller wird instanziiert, nachdem HTML an seiner Stelle ist.
Dmitry Evseev

3
Was ist, wenn der Controller auf anderen Seiten wiederverwendet wird, Sie ihn jedoch nur auf einer bestimmten Seite auslösen möchten?
Roberto Linares

3
@RobertoLinares Ich persönlich finde, dass Direktiven ein besserer Ort für wiederverwendbare Funktionen sind. Sie können eine Direktive mit einem init-Parameter haben : <div smth on-init="doWhatever()">. Natürlich hängt es von einem bestimmten Anwendungsfall ab.
Dmitry Evseev

135

Versuche dies?

$scope.$on('$viewContentLoaded', function() {
    //call it here
});

5
Vielen Dank für die Antwort, aber Dmitrys Antwort stimmte genau mit dem überein, wonach ich suche. Weitere Forschung schien gegen $ viewContentLoaded
Duke Dougal

7
Die Anwendungsfälle sind einfach unterschiedlich. Ich benutze auch immer Marks Methode.
Holographisches Prinzip

Für meinen Anwendungsfall war dies eine perfekte Lösung. Wir mussten den Text automatisch auswählen, um den Benutzer zum Kopieren zu ermutigen. Die Seite konnte viele Male neu geladen / besucht werden, sodass $ viewContentLoaded genau übereinstimmte. Vielen Dank!
Olga Gnatenko

Ist es möglich, dass dies mehrmals ausgeführt wird? Ich
bekomme

1
Dieser hat bei mir nicht funktioniert, aber $ scope. $ Watch hat funktioniert. Was ist der Hauptunterschied?
Burak Tokak

59

Ich konnte nie $viewContentLoadedfür mich arbeiten und ng-initsollte eigentlich nur in einem ng-repeat(laut Dokumentation) verwendet werden. Auch das Aufrufen einer Funktion direkt in einem Controller kann zu Fehlern führen, wenn der Code auf einem Element basiert, das noch nicht definiert wurde .

Das mache ich und es funktioniert für mich:

$scope.$on('$routeChangeSuccess', function () {
  // do something
});

Es sei denn, Sie verwenden ui-router. Dann ist es:

$scope.$on('$stateChangeSuccess', function () {
  // do something
});

1
Du bist großartig, mein Freund.
Taco

Genau das, was ich brauchte. Ich habe buchstäblich zwei Tage lang danach gesucht!
Hallojebus

3
$scope.$on('$routeChangeSuccess'wird jedes Mal ausgelöst, wenn Parameter in der URL geändert werden ( $locationz. B. über), und daher können Sie nur verwenden $scope.$on('$locationChangeSuccess'. Wenn Sie beim Laden / Neuladen einer Seite einen Auslöser benötigen, können Sie diesen $scope.$watch('$viewContentLoaded'wie hier vorgeschlagen verwenden. Es wird nicht ausgelöst, wenn sich die URL-Parameter ändern.
Neurotransmitter

Mit AngularJS 1.17.2 hat der Controller $ routeChangeSuccess erstaunlich funktioniert ... es lebe adam0101 ...
ArifMustafa

43
angular.element(document).ready(function () {

    // your code here

});

4
Muss die akzeptierte Antwort sein, dies ist der sicherere Weg, dies zu tun
Marwen Trabelsi

Das ist gut, wenn wir nicht mit $scopeund stattdessen arbeiten this.
Akash

Wohin muss das gehen? Ich habe es in meiner Vorlage und es wird nicht ausgelöst.
Dave

Wäre es in diesem Fall nicht am besten, $ document zu injizieren? angle.element ($ document) .ready ...
Jamie

4
Erklärung wäre dankbar
Hidayt Rahman

32

Die Lösung von Dimitri / Mark hat bei mir nicht funktioniert, aber die Verwendung der $ timeout- Funktion scheint gut zu funktionieren, um sicherzustellen, dass Ihr Code erst ausgeführt wird, nachdem das Markup gerendert wurde.

# Your controller, including $timeout

var $scope.init = function(){
 //your code
}

$timeout($scope.init)

Ich hoffe es hilft.


3
Schließlich. Dies ist der einzige, der für mich gearbeitet hat. Vielen Dank.
Zmirc

1
Das funktioniert. Vergessen Sie auch nicht, das Zeitlimit mit $ timeout.cancel (Timer) zu löschen, wenn Sie var timer = $ timeout ($ scope.init, Millisekunden) haben. Sobald Ihre Initialisierung abgeschlossen ist. Ich denke auch nicht, dass $ scope eine 'var'-Def in Ihrem obigen Code haben sollte
Emmanuel NK

Dies sollte die akzeptierte Antwort sein. Es war das einzige, das für mich funktioniert hat (habe alle Antworten oben ausprobiert). Es funktioniert sogar, wenn Sie auf das Laden eines Iframes warten.
hallo_fr1end

Das funktioniert ! viewcontentLoaded hat bei mir nicht funktioniert
dunkler Ritter

28

Sie können dies tun, wenn Sie das viewContentLoaded-DOM-Objekt beobachten möchten, um es zu ändern, und dann etwas tun möchten. Die Verwendung von $ scope. $ on funktioniert ebenfalls, jedoch anders, insbesondere wenn Sie einen Seitenmodus für Ihr Routing haben.

 $scope.$watch('$viewContentLoaded', function(){
    // do something
 });

7
Insbesondere wenn Sie $ rootScope. $ Watch anstelle von $ rootScope. $ On verwenden, wird es bei Routenänderungen nicht ausgelöst, sodass Sie eine Logik verwenden können, die für das anfängliche Laden der Seite spezifisch ist.
Csahlman

19

Sie können das $ window-Objekt von angle verwenden:

$window.onload = function(e) {
  //your magic here
}


3

Eine weitere Alternative, wenn Sie einen Controller haben, der nur für diese Seite spezifisch ist:

(function(){
    //code to run
}());

3

Wenn Sie $ routeProvider verwenden, können Sie .state auflösen und Ihren Dienst booten. Dies bedeutet, dass Sie Controller und View erst laden, nachdem Sie Ihren Dienst aufgelöst haben:

UI-Routen

 .state('nn', {
        url: "/nn",
        templateUrl: "views/home/n.html",
        controller: 'nnCtrl',
        resolve: {
          initialised: function (ourBootstrapService, $q) {

            var deferred = $q.defer();

            ourBootstrapService.init().then(function(initialised) {
              deferred.resolve(initialised);
            });
            return deferred.promise;
          }
        }
      })

Bedienung

function ourBootstrapService() {

 function init(){ 
    // this is what we need
 }
}

3

Fand Dmitry Evseev Antwort sehr nützlich.

Fall 1: Verwenden von angleJs allein:
Um eine Methode beim Laden der Seite auszuführen, können Sie ng-initin der Ansicht die Methode init verwenden und deklarieren, obwohl die Verwendung einer schwereren Funktion gemäß den Angular Docs on ng-init nicht empfohlen wird :

Diese Anweisung kann missbraucht werden, um Ihren Vorlagen unnötig viel Logik hinzuzufügen. Es gibt nur wenige geeignete Anwendungen von ngInit, z. B. zum Aliasing spezieller Eigenschaften von ngRepeat, wie in der folgenden Demo dargestellt. und zum Einfügen von Daten über serverseitiges Scripting. Abgesehen von diesen wenigen Fällen sollten Sie Controller anstelle von ngInit verwenden, um Werte für einen Bereich zu initialisieren.

HTML:

<div ng-controller="searchController()">
    <!-- renaming view code here, including the search box and the buttons -->
</div>

Regler:

app.controller('SearchCtrl', function(){

    var doSearch = function(keyword){
        //Search code here
    }

    doSearch($routeParams.searchKeyword);
})

Warnung: Verwenden Sie diesen Controller nicht für eine andere Ansicht, die für eine andere Absicht bestimmt ist, da sonst die Suchmethode auch dort ausgeführt wird.

Fall 2: Verwenden von Ionic:
Der obige Code funktioniert. Stellen Sie einfach sicher, dass der Ansichtscache im route.jsas deaktiviert ist :

route.js

.state('app', {
    url           : '/search',
    cache         : false, //disable caching of the view here
    templateUrl   : 'templates/search.html'   ,
    controller    : 'SearchCtrl'
  })

Hoffe das hilft


1
Dieser hatte nur einen oben und war ganz unten, froh, dass ich den ganzen Weg runter gegangen bin, der cache: falsehat es für mich getan - danke!
Rani Kheir

3

Ich hatte das gleiche Problem und nur diese Lösung funktionierte für mich (sie führt eine Funktion aus, nachdem ein vollständiges DOM geladen wurde). Ich verwende dies zum Scrollen zum Ankern, nachdem die Seite geladen wurde:

angular.element(window.document.body).ready(function () {

                        // Your function that runs after all DOM is loaded

                    });

2

Sie können die Suchergebnisse in einem allgemeinen Dienst speichern, der von überall verwendet werden kann und beim Navigieren zu einer anderen Seite nicht gelöscht wird. Anschließend können Sie die Suchergebnisse mit den gespeicherten Daten für die Schaltfläche "Zurück" festlegen

function search(searchTerm) {
    // retrieve the data here;
    RetrievedData = CallService();
    CommonFunctionalityService.saveSerachResults(RetrievedData);
} 

Für deinen Backbutton

function Backbutton() {
    RetrievedData = CommonFunctionalityService.retrieveResults();
}

0

Rufen Sie die Anfangsmethoden innerhalb der Selbstinitialisierungsfunktion auf.

(function initController() {

    // do your initialize here

})();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.