Führen Sie eine Steuerungsfunktion aus, wenn eine Ansicht geöffnet / angezeigt wird

81

Ich baue eine App mit Angular + Ionic, die ein klassisches Drei-Tasten-Menü unten mit drei Ion-Tabs verwendet. Wenn ein Benutzer auf eine Registerkarte klickt, wird diese Vorlage über den UI-Router geöffnet.

Ich habe Zustände wie diesen:

$stateProvider
  .state('other', {
    url: "/other",
    abstract: true,
    templateUrl: "templates/other/other.html"
})

In der Vorlage mache ich so etwas wie:

<ion-nav-view name="other" ng-init="doSomething()"></ion-nav-view>

Mir ist bewusst, dass ich die Funktion doSomething () in meinen Controller schreiben und dort einfach manuell aufrufen kann. Das gibt mir aber das gleiche Problem. Ich kann nicht mehr als einmal herausfinden, wie man die Funktion doSomething () aufruft, wenn jemand diese Ansicht öffnet.

Im Moment wird die Funktion doSomething () problemlos aufgerufen, aber nur beim ersten Öffnen dieser Ansicht / Registerkarte durch den Benutzer. Ich möchte eine Funktion aufrufen (um die Geolokalisierung zu aktualisieren), wenn ein Benutzer diese Ansicht oder Registerkarte öffnet.

Was wäre ein korrekter Weg, um das umzusetzen?

Vielen Dank für Ihre Hilfe!

Jorre
quelle
versuchen Sie {{doSomething ()}}?
Asik
1
Das Problem liegt nicht bei doSomething (), da dies einwandfrei startet. Es wird nur nicht zweimal ausgelöst. Das erste Mal, wenn die Ansicht geöffnet wird, läuft sie einwandfrei, das zweite Mal scheint es, als würde nur eine zwischengespeicherte Ansicht geladen oder so?
Jorre
ng-init ruft die Funktion nur einmal auf. Sie können ng-controller = "doSomething ()" oder {{doSomething ()}} in Ihren Teilansichten aufrufen und die Funktion wird ausgelöst, wenn der Router / Teil aufgerufen wird.
Asik
3
Setzen Sie in Ihrem Konfigurationsstatus Ihren Cache auf false. Schau dir meine Antwort an.
Yakob Ubaidi

Antworten:

46

Wenn Sie Ihrer Ansicht einen bestimmten Controller zugewiesen haben, wird Ihr Controller jedes Mal aufgerufen, wenn Ihre Ansicht geladen wird. In diesem Fall können Sie Code in Ihrem Controller ausführen, sobald er aufgerufen wird, beispielsweise auf folgende Weise:

<ion-nav-view ng-controller="indexController" name="other" ng-init="doSomething()"></ion-nav-view>

Und in Ihrem Controller:

app.controller('indexController', function($scope) {
    /*
        Write some code directly over here without any function,
        and it will be executed every time your view loads.
        Something like this:
    */
    $scope.xyz = 1;
});

Bearbeiten: Sie können versuchen, Statusänderungen zu verfolgen und dann Code auszuführen, wenn die Route geändert und eine bestimmte Route besucht wird. Beispiel:

$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){ ... })

Weitere Details finden Sie hier: Statusänderungsereignisse .

Manish Kr. Shukla
quelle
6
Danke, aber genau das mache ich. Dieser Code wird nur einmal ausgeführt, wenn die Ansicht zum ersten Mal geöffnet wurde. Ich habe versucht, etwas an meiner Konsole zu protokollieren, und es wird nur beim ersten Mal ausgelöst.
Jorre
Wenn Sie sagen, dass es in Ihrer App funktioniert, sprechen Sie auch von einer ionischen App? Ich versuche zu sehen, ob das der Fall sein könnte, es funktioniert nicht für mich.
Jorre
2
Die Arbeit mit stateChange reicht aus, wenn Sie nur auf eine Registerkarte klicken, wird sie nur einmal ausgeführt. Danke für die Bearbeitung!
Jorre
Ich denke, das hat damit zu tun, wie Ionic bestimmte Teile Ihrer App zwischenspeichert. Vielleicht cache-viewhilft die Einstellung auf false? ionicframework.com/docs/api/directive/ionView Suche nach Cache-Ansicht
Michael Trouw
Dies ist möglicherweise das Problem bei der jüngsten Veröffentlichung von ionic. Sie können den Cache jedoch auch auf Routenebene deaktivieren. Fügen Sie einfach einen Cache hinzu: false für jede einzelne Route in Ihrer Routenkonfiguration.
Manish Kr. Shukla
88

Standardmäßig waren Ihre Controller Cache und deshalb wurde Ihr Controller nur einmal ausgelöst. Um das Caching für einen bestimmten Controller zu deaktivieren, müssen Sie Ihren ändern .config(..).stateund die cacheOption auf setzen false. z.B :

  .state('myApp', {
    cache: false,
    url: "/form",
    views: {
      'menuContent': {
        templateUrl: "templates/form.html",
        controller: 'formCtrl'
      }
    }
  })

Weitere Informationen finden Sie unter http://ionicframework.com/docs/api/directive/ionNavView/.

Yakob Ubaidi
quelle
2
Sehr nützlich für einen Logout-Controller
Mrwaim
3
Es ist wirklich bedauerlich, dass das Caching in ionic standardmäßig aktiviert ist. Scheint so, als ob dies eine Opt-In-Funktion sein sollte, anstatt sie standardmäßig hinzuzufügen.
Oalbrecht
Ich musste nur einen Status neu laden, also verwendete ich: $state.go('app.statename', {}, {reload:true});( weitere Informationen , Quelle ).
Sjoerd Pottuit
1
Während dies funktioniert, ist es nicht genau der richtige Weg, dies zu tun. Es wird Ihre App verlangsamen - vorausgesetzt, Sie möchten nicht jedes Mal, wenn der Benutzer zu dieser Ansicht wechselt, die gesamte Controller-Init-Prozedur durchlaufen, denke ich, dass die Antwort von jczaplew ein besserer Ansatz ist.
Chris Rae
Tolles Zeug. Ich hatte das Caching für die gesamte App deaktiviert. Ich bin froh, dass ich auf diese Antwort gestoßen bin
Robert Ngetich
50

Verfolgen Sie die Antwort und den Link von AlexMart funktioniert so etwas:

.controller('MyCtrl', function($scope) {
  $scope.$on('$ionicView.enter', function() {
     // Code you want executed every time view is opened
     console.log('Opened!')
  })
})
jczaplew
quelle
3
$ionicView.beforeEnterist wahrscheinlich was du willst. $ionicView.enterwird ausgelöst, nachdem "die Ansicht vollständig eingegeben wurde" . Wenn Sie animierte Ansichtsübergänge verwenden, wird die $ionicView.beforeEnterAusführung ausgeführt, bevor der Übergang beginnt. Dies bedeutet, dass Sie Ihren Code während des Übergangs ausführen können, was wahrscheinlich zu einem "schnelleren" Gefühl in Ihrer App führt.
Rinogo
Ich denke, das ist nur die einfachste und sauberste Antwort. In Bezug auf den @rinogo-Kommentar denke ich, dass jeder Programmierer entscheiden kann, ob er "enter" oder "beforeEnter" verwendet, je nachdem, was in der Ansicht / im Controller passiert. Das Wichtigste dabei ist, dass Sie mit Lebenszyklusereignissen umgehen können, um bei jeder Eingabe Ihrer Ansicht eine Funktion aufzurufen.
Jcarballo
12

Ich hatte das gleiche Problem, und hier überlasse ich den Grund für dieses Verhalten allen anderen mit dem gleichen Problem.

Lebenszyklus anzeigen

Um die Leistung zu verbessern, haben wir die Fähigkeit von Ionic verbessert, Ansichtselemente und Bereichsdaten zwischenzuspeichern. Sobald ein Controller initialisiert wurde, kann er während der gesamten Lebensdauer der App bestehen bleiben. Es ist nur versteckt und aus dem Uhrenzyklus entfernt. Da wir den Bereich nicht neu erstellen, haben wir Ereignisse hinzugefügt, auf die wir achten sollten, wenn Sie erneut in den Überwachungszyklus eintreten.

Eine vollständige Beschreibung und $ ionicView-Ereignisse finden Sie unter: http://ionicframework.com/blog/navigating-the-changes/

AlexMart
quelle
9

Warum deaktivieren Sie den Ansichtscache nicht mit cache-view = "false" ?

Fügen Sie in Ihrer Ansicht Folgendes zur Ion-Navi-Ansicht hinzu:

<ion-nav-view name="other" cache-view="false"></ion-nav-view>

Oder in Ihrem StateProvider:

$stateProvider.state('other', {
   cache: false,
   url : '/other',
   templateUrl : 'templates/other/other.html'
})

In beiden Fällen wird Ihr Controller immer aufgerufen.

Diogo Medeiros
quelle
Wird dies keine Leistungsnebenwirkungen haben? Ich nahm an, dass die Ansicht zwischengespeichert wird, damit nicht jedes Mal die gesamte Ansicht neu geladen wird. Das Deaktivieren dieser Funktion würde nicht dazu führen, dass die gesamte Seite erneut geladen wird, während nur ein Teil des Codes erneut ausgeführt werden soll.
Sindarus
Wahrscheinlich ja @Sindarus. Es gibt jedoch einige Fälle, die notwendig sind. Für mich hat ich eine Plugin-Zeichnung in der Ansicht und konnte nicht herausfinden, wie ich sie bereinigen soll.
Diogo Medeiros
Dies war eine perfekte Lösung für meinen Fall. Ich habe den Benutzer abgemeldet und dann den Controller erneut besucht. Ich möchte nicht zwischenspeichern und alles sollte neu initialisiert werden. Danke!
Firas Abd Alrahman
5

Zum Beispiel an @Michael Trouw,

Geben Sie diesen Code in Ihren Controller ein. Dies wird jedes Mal ausgeführt, wenn dieser Status eingegeben oder aktiv ist. Sie müssen sich keine Gedanken über das Deaktivieren des Caches machen und es ist ein besserer Ansatz.

.controller('exampleCtrl',function($scope){
$scope.$on('$ionicView.enter', function(){
        // Any thing you can think of
        alert("This function just ran away");   
    });
})

Sie können weitere Beispiele für Flexibilität wie $ ionicView.beforeEnter -> verwenden, die ausgeführt werden, bevor eine Ansicht angezeigt wird. Und da steckt noch mehr dahinter.

Wang'l Pakhrin
quelle
2

In Anbetracht der oben erwähnten Fähigkeit von Ionic, Ansichtselemente und Bereichsdaten zwischenzuspeichern, kann dies eine andere Möglichkeit sein, wenn Sie den Controller jedes Mal ausführen möchten, wenn die Ansicht geladen wird. Sie können den von ionic verwendeten Caching-Mechanismus global deaktivieren, indem Sie Folgendes tun:

$ionicConfigProvider.views.maxCache(0);

Sonst war es so, wie ich es für mich arbeiten ließ

$scope.$on("$ionicView.afterLeave", function () {
     $ionicHistory.clearCache();
}); 

Dies dient dazu, den Cache zu leeren, bevor Sie die Ansicht verlassen, um den Controller bei jeder erneuten Eingabe erneut auszuführen.

Rajush
quelle
1

Dies ist wahrscheinlich das, wonach Sie gesucht haben:

Ionic speichert Ihre Ansichten und damit Ihre Controller standardmäßig zwischen (maximal 10) Http://ionicframework.com/docs/api/directive/ionView/

Es gibt Ereignisse, an die Sie sich anschließen können, damit Ihr Controller bestimmte Dinge basierend auf diesen ionischen Ereignissen ausführen kann. Ein Beispiel finden Sie hier: http://ionicframework.com/blog/navigating-the-changes/

Michael Trouw
quelle
1
Kann verbessert werden, indem Beispielcode angezeigt wird, anstatt einfach einen Link zu teilen
Lawrence Weru
Gibt es so etwas auch bei Angular Js?
Wang'l Pakhrin
@ Wang'lPakhrin Standardmäßig wird jeder Code, IIFE oder jede Funktion, die Sie deklarieren und in Ihrer Hauptcontrollerfunktion ausführen, jedes Mal ausgeführt, wenn die Ansicht (und damit der Controller) geladen wird. Wenn Sie Ereignisse wie das einmalige Ausführen einer Funktion in der Lebensdauer Ihrer Anwendung benötigen, überprüfen Sie die klebrigen Zustände ViewContentLoadingund ViewContentLoadedEreignisse des Winkel-UI-Routers :)
Michael Trouw
0

Ich hatte ein ähnliches Problem mit ionic, bei dem ich versuchte, die native Kamera zu laden, sobald ich die Registerkarte Kamera auswählte. Ich habe das Problem behoben, indem ich den Controller auf die Ionenansichtskomponente für die Registerkarte "Kamera" (in tabs.html) eingestellt und dann die Methode "$ scope" aufgerufen habe, mit der meine Kamera geladen wird (addImage).

In www / templates / tabs.html

  <ion-tab title="Camera" icon-off="ion-camera" icon-on="ion-camera" href="#/tab/chats" ng-controller="AddMediaCtrl" ng-click="addImage()">
    <ion-nav-view  name="tab-chats"></ion-nav-view>
  </ion-tab>

Die in AddMediaCtrl definierte addImage-Methode lädt die native Kamera jedes Mal, wenn der Benutzer auf die Registerkarte "Kamera" klickt. Ich habe nicht müssen für diese Arbeit etwas im Winkel Cache ändern. Ich hoffe das hilft.

Chukkwagon
quelle