Ejecuta una función de controlador cada vez que se abre / muestra una vista

81

Estoy creando una aplicación con angular + iónico que usa un menú clásico de tres botones en la parte inferior con tres pestañas de iones. Cuando un usuario hace clic en una pestaña, esa plantilla se abre a través de ui-router.

Tengo estados como este:

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

En la plantilla hago algo como:

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

Soy consciente de que puedo escribir la función doSomething () en mi controlador y simplemente llamarla manualmente allí. Sin embargo, eso me da el mismo problema. Parece que no puedo averiguar cómo llamar a la función doSomething () más de una vez, cada vez que alguien abre esa vista.

En este momento, la función doSomething () se llama bien, pero solo la primera vez que el usuario abre esa vista / pestaña. Me gustaría llamar a una función (para actualizar la geolocalización) cada vez que un usuario abre esa vista o pestaña.

¿Cuál sería la forma correcta de implementar eso?

¡Gracias por ayudar!

Jorre
fuente
probar {{doSomething ()}}?
Asik
1
el problema no es con doSomething () ya que se está iniciando bien, es solo que no se activará dos veces. La primera vez que se abre la vista, funciona bien, la segunda vez parece que solo está cargando una vista en caché o algo así.
Jorre
ng-init llama a la función solo una vez. puede llamar ng-controller = "doSomething ()" o {{doSomething ()}} en sus vistas parciales y la función se activa cada vez que se llama al router / parcial.
Asik
3
en su estado de configuración, establezca su caché en falso. Mira mi respuesta.
Yakob Ubaidi

Respuestas:

46

Si ha asignado un cierto controlador a su vista, entonces se invocará su controlador cada vez que se cargue su vista. En ese caso, puede ejecutar algún código en su controlador tan pronto como se invoca, por ejemplo, de esta manera:

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

Y en tu controlador:

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

Editar: puede intentar rastrear los cambios de estado y luego ejecutar algún código cuando se cambia la ruta y se visita una determinada ruta, por ejemplo:

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

Puede encontrar más detalles aquí: Eventos de cambio de estado .

Manish Kr. Shukla
fuente
6
Gracias, pero eso es exactamente lo que estoy haciendo. Este código solo se ejecutará una vez, la primera vez que se abrió la vista. Intenté registrar algo en mi consola y solo se activa la primera vez.
Jorre
Cuando dices que funciona en tu aplicación, ¿estás hablando también de una aplicación iónica? Estoy tratando de ver si ese podría ser el caso, no funciona para mí.
Jorre
2
Trabajar con stateChange funciona, simplemente hacer clic en una pestaña solo se ejecuta una vez. ¡Gracias por editar!
Jorre
Creo que esto tiene que ver con la forma en que Ionic almacena en caché ciertas partes de su aplicación. tal vez establecer cache-viewen falso ayudará? ionicframework.com/docs/api/directive/ionView búsqueda de vista de caché
Michael Trouw
Este es quizás el problema con el reciente lanzamiento de iónico. Sin embargo, también puede deshabilitar la caché en el nivel de rutas. simplemente agregue un caché: falso a todas y cada una de las rutas en la configuración de sus rutas.
Manish Kr. Shukla
88

De forma predeterminada, sus controladores estaban en caché y es por eso que su controlador solo se disparó una vez. Para desactivar el almacenamiento en caché de un controlador determinado, debe modificar su .config(..).statey establecer la cacheopción en false. p.ej :

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

para obtener más información, visite http://ionicframework.com/docs/api/directive/ionNavView/

Yakob Ubaidi
fuente
2
Muy útil para un controlador de cierre de sesión
mrwaim
3
Es realmente lamentable que el almacenamiento en caché esté activado de forma predeterminada en ionic. Parece que esta debería ser una función opcional en lugar de agregarla de forma predeterminada.
oalbrecht
Solo necesitaba recargar un estado, así que usé: $state.go('app.statename', {}, {reload:true});( más información , fuente ).
Sjoerd Pottuit
1
Si bien esto funciona, no es exactamente la forma correcta de hacerlo. Va a ralentizar su aplicación, suponiendo que no quiera pasar por todo el procedimiento de inicio del controlador cada vez que el usuario cambia a esa vista, creo que la respuesta de jczaplew es un enfoque más agradable.
Chris Rae
Buena cosa. Había deshabilitado el almacenamiento en caché en toda la aplicación. Me alegro de haber encontrado esta respuesta
Robert Ngetich
50

Siguiendo la respuesta y el enlace de AlexMart , algo como esto funciona:

.controller('MyCtrl', function($scope) {
  $scope.$on('$ionicView.enter', function() {
     // Code you want executed every time view is opened
     console.log('Opened!')
  })
})
jczaplew
fuente
3
$ionicView.beforeEnteres probablemente lo que quieres. $ionicView.enterse dispara después de que "la vista haya entrado completamente" . Si está utilizando transiciones de vista animadas, el uso se $ionicView.beforeEnterejecuta antes de que comience la transición. Esto significa que puede ejecutar su código durante la transición, lo que probablemente dará lugar a una sensación más "ágil" en su aplicación.
rinogo
Creo que esta es la respuesta más simple y limpia. En cuanto al comentario de @rinogo, creo que cada programador puede decidir si usar "enter" o "beforeEnter", según lo que suceda en la vista / controlador. Lo importante que debe comprender aquí es que puede manejar los eventos del ciclo de vida para llamar a una función cada vez que ingresa a su vista.
jcarballo
12

Me enfrenté al mismo problema, y ​​aquí dejo el motivo de este comportamiento para todos los demás con el mismo problema.

Ver ciclo de vida

Para mejorar el rendimiento, hemos mejorado la capacidad de Ionic de almacenar en caché los elementos de visualización y los datos del alcance. Una vez que se inicializa un controlador, puede persistir durante toda la vida de la aplicación; simplemente está oculto y eliminado del ciclo de reloj. Como no estamos reconstruyendo el alcance, hemos agregado eventos que debemos escuchar al ingresar nuevamente al ciclo de observación.

Para ver la descripción completa y los eventos de $ ionicView, visite: http://ionicframework.com/blog/navigating-the-changes/

AlexMart
fuente
9

¿Por qué no deshabilita la caché de vista con cache-view = "false" ?

En su vista, agregue esto a la vista de navegación de iones de esa manera:

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

O en su estado Proveedor:

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

Cualquiera de los dos hará que su controlador sea llamado siempre.

Diogo Medeiros
fuente
¿No tendrá esto efectos secundarios en el rendimiento? Supuse que la vista se almacena en caché para que no se recargue toda la vista cada vez. La desactivación de esta función no provocaría que toda la página se cargue de nuevo, mientras que solo queremos que se vuelva a ejecutar una parte del código.
Sindarus
Probablemente, sí @Sindarus. Pero hay algunos casos que son necesarios. Para mí, tengo un dibujo de complemento en la vista y no pude averiguar cómo limpiarlo.
Diogo Medeiros
Esta fue una solución perfecta para mi caso, estaba cerrando la sesión del usuario y luego volví a visitar el controlador, no quiero almacenar en caché y todo debería reiniciarse. ¡gracias!
Firas Abd Alrahman
5

Por ejemplo a @Michael Trouw,

dentro de su controlador ponga este código. esto se ejecutará cada vez que se ingrese o se active este estado, no necesita preocuparse por deshabilitar el caché y es un mejor enfoque.

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

Puede tener más ejemplos de flexibilidad como $ ionicView.beforeEnter -> que se ejecuta antes de que se muestre una vista. Y hay algunos más.

Wang'l Pakhrin
fuente
2

Teniendo en cuenta la capacidad de Ionic para almacenar en caché los elementos de vista y los datos de alcance mencionados anteriormente, esta podría ser otra forma de hacerlo, si desea ejecutar el controlador cada vez que se carga la vista. Puede deshabilitar globalmente el mecanismo de almacenamiento en caché utilizado por ionic haciendo:

$ionicConfigProvider.views.maxCache(0);

De lo contrario, la forma en que lo hice funcionar para mí fue

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

Esto es para borrar la caché antes de salir de la vista para volver a ejecutar el controlador cada vez que ingrese nuevamente.

Rajush
fuente
1

Probablemente esto es lo que estabas buscando:

Ionic almacena en caché sus vistas y, por lo tanto, sus controladores de forma predeterminada (máximo de 10) http://ionicframework.com/docs/api/directive/ionView/

Hay eventos a los que puede conectarse para permitir que su controlador haga ciertas cosas en función de esos eventos iónicos. vea aquí un ejemplo: http://ionicframework.com/blog/navigating-the-changes/

Michael Trouw
fuente
1
Se puede mejorar mostrando un código de ejemplo en lugar de simplemente compartir un enlace
Lawrence Weru
¿Hay algo como esto en Angular Js también?
Wang'l Pakhrin
@ Wang'lPakhrin por defecto, cualquier código, IIFE o función que declare y ejecute dentro de la función de su controlador principal se ejecutará cada vez que se cargue la vista (y por lo tanto el controlador). Si necesita eventos como ejecutar una función una vez en la vida útil de su aplicación, consulte los estados ViewContentLoadingy ViewContentLoadedeventos fijos de angular-ui-router :)
Michael Trouw
0

Tuve un problema similar con iónico en el que intentaba cargar la cámara nativa tan pronto como seleccionaba la pestaña de la cámara. Resolví el problema configurando el controlador en el componente ion-view para la pestaña de la cámara (en tabs.html) y luego llamando al método $ scope que carga mi cámara (addImage).

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

El método addImage, definido en AddMediaCtrl carga la cámara nativa cada vez que el usuario hace clic en la pestaña "Cámara". Yo no tengo que cambiar nada en la memoria caché angular para que esto funcione. Espero que esto ayude.

chukkwagon
fuente