Uruchom funkcję kontrolera za każdym razem, gdy widok jest otwarty / pokazany

81

Tworzę aplikację z angular + ionic, która używa klasycznego menu z trzema przyciskami na dole i trzema zakładkami jonowymi. Gdy użytkownik klika kartę, szablon otwiera się za pośrednictwem routera ui.

Mam takie stany:

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

W szablonie robię coś takiego:

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

Zdaję sobie sprawę, że mogę napisać funkcję doSomething () w moim kontrolerze i po prostu wywołać ją ręcznie. To jednak daje mi ten sam problem. Nie potrafię wymyślić, jak wywołać funkcję doSomething () więcej niż raz, kiedy ktoś otworzy ten widok.

W tej chwili funkcja doSomething () jest wywoływana dobrze, ale tylko przy pierwszym otwarciu widoku / karty przez użytkownika. Chciałbym wywołać funkcję (aktualizującą geolokalizację) za każdym razem, gdy użytkownik otworzy ten widok lub kartę.

Jaki byłby prawidłowy sposób na wdrożenie tego?

Dzięki za pomoc!

Jorre
źródło
spróbować {{doSomething ()}}?
Asik
1
problem nie dotyczy metody doSomething (), która uruchamia się dobrze, po prostu nie uruchamia się dwukrotnie. Za pierwszym razem, gdy widok się otwiera, działa dobrze, za drugim razem wydaje się, że po prostu ładuje buforowany widok czy coś?
Jorre
ng-init wywołuje funkcję tylko raz. możesz wywołać ng-controller = "doSomething ()" lub {{doSomething ()}} w swoich widokach częściowych, a funkcja zostanie uruchomiona za każdym razem, gdy zostanie wywołany router / Part.
Asik
3
w stanie konfiguracji ustaw pamięć podręczną na false. Sprawdź moją odpowiedź.
Yakob Ubaidi

Odpowiedzi:

46

Jeśli przypisałeś określony kontroler do swojego widoku, twój kontroler będzie wywoływany za każdym razem, gdy twój widok zostanie załadowany. W takim przypadku możesz wykonać jakiś kod w swoim kontrolerze zaraz po jego wywołaniu, na przykład w ten sposób:

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

A w kontrolerze:

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

Edycja: Możesz spróbować śledzić zmiany stanu, a następnie wykonać kod, gdy trasa zostanie zmieniona i zostanie odwiedzona określona trasa, na przykład:

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

Więcej szczegółów można znaleźć tutaj: Wydarzenia zmiany stanu .

Manish Kr. Shukla
źródło
6
Dzięki, ale właśnie to robię. Ten kod zostanie uruchomiony tylko raz, przy pierwszym otwarciu widoku. Próbowałem zarejestrować coś na mojej konsoli i uruchamia się to tylko za pierwszym razem.
Jorre
Kiedy mówisz, że działa w Twojej aplikacji, czy mówisz też o aplikacji jonowej? Próbuję sprawdzić, czy tak może być, że to nie działa dla mnie.
Jorre
2
Praca z stateChange załatwia sprawę, po prostu kliknięcie karty nadal działa tylko raz. Dzięki za edycję!
Jorre
Myślę, że ma to związek ze sposobem, w jaki Ionic buforuje określone części aplikacji. może ustawienie cache-viewna fałsz pomoże? ionicframework.com/docs/api/directive/ionView search for cache-view
Michael Trouw
Być może jest to problem związany z niedawnym wydaniem jonowego. Możesz jednak wyłączyć pamięć podręczną na poziomie tras. po prostu dodaj cache: false do każdej trasy w konfiguracji tras.
Manish Kr. Shukla
88

Domyślnie kontrolery były buforowane i dlatego kontroler został uruchomiony tylko raz. Aby wyłączyć buforowanie dla określonego kontrolera, musisz zmodyfikować swój .config(..).statei ustawić cacheopcję na false. np .:

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

dalsze czytanie można znaleźć pod adresem http://ionicframework.com/docs/api/directive/ionNavView/

Yakob Ubaidi
źródło
2
Bardzo przydatne dla kontrolera wylogowania
mrwaim
3
To naprawdę niefortunne, że buforowanie jest domyślnie włączone w trybie jonowym. Wygląda na to, że powinna to być funkcja opt-in zamiast dodawania jej domyślnie.
oalbrecht
Potrzebowałem tylko przeładować jeden stan, więc użyłem: $state.go('app.statename', {}, {reload:true});( więcej informacji , źródło ).
Sjoerd Pottuit,
1
Chociaż to działa, nie jest to do końca właściwy sposób. Spowolni to twoją aplikację - zakładając, że nie chcesz przechodzić przez całą procedurę inicjalizacji kontrolera za każdym razem, gdy użytkownik przełączy się do tego widoku, myślę, że odpowiedź jczaplew jest lepszym podejściem.
Chris Rae
Świetne rzeczy. Wyłączyłem buforowanie w całej aplikacji. Cieszę się, że trafiłem na tę odpowiedź
Robert Ngetich
50

Po odpowiedzi i linku od AlexMart działa coś takiego:

.controller('MyCtrl', function($scope) {
  $scope.$on('$ionicView.enter', function() {
     // Code you want executed every time view is opened
     console.log('Opened!')
  })
})
jczaplew
źródło
3
$ionicView.beforeEnterjest prawdopodobnie tym, czego chcesz. $ionicView.enteruruchamia się po „pełnym wejściu widoku” . Jeśli używasz animowanych przejść między widokami, użyj funkcji $ionicView.beforeEnterwykonywania przed rozpoczęciem przejścia. Oznacza to, że możesz uruchamiać swój kod podczas przejścia, co prawdopodobnie doprowadzi do „szybszego” działania aplikacji.
rinogo
Myślę, że to tylko najprostsza i najczystsza odpowiedź. Odnosząc się do komentarza @rinogo, myślę, że każdy programista może zdecydować, czy użyć „enter”, czy „beforeEnter”, w zależności od tego, co dzieje się w widoku / kontrolerze. Ważną rzeczą do zrozumienia jest to, że możesz obsługiwać zdarzenia cyklu życia, aby wywoływać funkcję za każdym razem, gdy wchodzisz do widoku.
jcarballo
12

Zmierzyłem się z tym samym problemem i tutaj powód tego zachowania pozostawiam wszystkim innym z tym samym problemem.

Wyświetl cykl życia

Aby poprawić wydajność, poprawiliśmy zdolność Ionic do buforowania widoku elementów i danych zakresu. Zainicjowany kontroler może trwać przez całe życie aplikacji; jest po prostu ukryty i usunięty z cyklu zegarka. Ponieważ nie przebudowujemy zakresu, dodaliśmy zdarzenia, których powinniśmy słuchać po ponownym wejściu w cykl obserwacyjny.

Aby zobaczyć pełny opis i zdarzenia $ ionicView, przejdź do: http://ionicframework.com/blog/navigating-the-changes/

AlexMart
źródło
9

Dlaczego nie wyłączysz pamięci podręcznej widoku za pomocą cache-view = "false" ?

Twoim zdaniem dodaj to do widoku ion-nav w ten sposób:

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

Lub w Twoim stanie Dostawca:

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

Każda z nich sprawi, że twój kontroler będzie zawsze wywoływany.

Diogo Medeiros
źródło
Czy nie będzie to miało skutków ubocznych związanych z wydajnością? Przypuszczam, że widok jest buforowany, więc cały widok nie jest ładowany ponownie za każdym razem. Wyłączenie tej funkcji nie spowodowałoby ponownego załadowania całej strony, podczas gdy chcemy, aby ponownie wykonano tylko fragment kodu?
Sindarus
Prawdopodobnie tak @Sindarus. Ale jest kilka przypadków, które są konieczne. Dla mnie mam wtyczkę rysującą widok i nie mogłem wymyślić, jak to wyczyścić.
Diogo Medeiros,
To było idealne rozwiązanie dla mojego przypadku, wylogowywałem użytkownika, a następnie ponownie odwiedzałem kontroler, nie chcę buforować i wszystko powinno zostać ponownie zainicjowane. Dziękuję Ci!
Firas Abd Alrahman
5

Na przykład dla @Michael Trouw,

wewnątrz kontrolera umieść ten kod. będzie działać za każdym razem, gdy ten stan zostanie wprowadzony lub aktywny, nie musisz się martwić o wyłączenie pamięci podręcznej i jest to lepsze podejście.

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

Możesz mieć więcej przykładów elastyczności, takich jak $ ionicView.beforeEnter ->, który jest uruchamiany przed wyświetleniem widoku. Jest w tym coś więcej.

Wang'l Pakhrin
źródło
2

Biorąc pod uwagę zdolność Ionic do buforowania elementów widoku i danych zakresu, o których mowa powyżej, może to być inny sposób, jeśli chcesz uruchamiać kontroler za każdym razem, gdy widok jest ładowany. Możesz globalnie wyłączyć mechanizm buforowania używany przez ionic, wykonując:

$ionicConfigProvider.views.maxCache(0);

W przeciwnym razie sposób, w jaki pracowałem dla mnie, działał

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

Ma to na celu wyczyszczenie pamięci podręcznej przed opuszczeniem widoku w celu ponownego uruchomienia kontrolera za każdym razem, gdy ponownie wejdziesz.

Rajush
źródło
1

To jest prawdopodobnie to, czego szukałeś:

Ionic domyślnie buforuje Twoje widoki, a tym samym kontrolery (maksymalnie 10) http://ionicframework.com/docs/api/directive/ionView/

Istnieją zdarzenia, do których można się podłączyć, aby umożliwić kontrolerowi wykonywanie pewnych czynności w oparciu o te zdarzenia jonowe. zobacz tutaj przykład: http://ionicframework.com/blog/navigating-the-changes/

Michael Trouw
źródło
1
Można to poprawić, pokazując przykładowy kod zamiast po prostu udostępniać link
Lawrence Weru
Czy jest coś takiego również w Angular Js?
Wang'l Pakhrin
@ Wang'lPakhrin domyślnie, każdy kod, IIFE lub funkcja, które zadeklarujesz i uruchomisz wewnątrz funkcji głównego kontrolera, będzie wykonywany za każdym razem, gdy widok (a tym samym kontroler) zostanie załadowany. Jeśli potrzebujesz zdarzeń, takich jak wykonanie funkcji raz w okresie życia aplikacji, sprawdź stany ViewContentLoadingi ViewContentLoadedzdarzenia
Michael Trouw
0

Podobny problem miałem z ionic, gdzie próbowałem załadować natywną kamerę zaraz po wybraniu zakładki camera. Rozwiązałem ten problem, ustawiając kontroler na komponent ion-view dla karty kamery (w tabs.html), a następnie wywołując metodę $ scope, która ładuje moją kamerę (addImage).

W 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>

Metoda addImage, zdefiniowana w AddMediaCtrl, ładuje natywną kamerę za każdym razem, gdy użytkownik kliknie kartę „Camera”. I nie , nie trzeba zmieniać niczego w kątowym cache dla tej pracy. Mam nadzieję, że to pomoże.

chukkwagon
źródło