Запускать функцию контроллера всякий раз, когда открывается / отображается представление

81

Я создаю приложение с angular + ionic, которое использует классическое трехкнопочное меню внизу с тремя ионными вкладками в нем. Когда пользователь щелкает вкладку, этот шаблон открывается через ui-router.

У меня есть такие состояния:

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

В шаблоне я делаю что-то вроде:

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

Я знаю, что могу написать функцию doSomething () в своем контроллере и просто вызвать ее вручную. Однако это вызывает у меня ту же проблему. Я не могу понять, как вызывать функцию doSomething () более одного раза, когда кто-то открывает это представление.

Прямо сейчас функция doSomething () вызывается нормально, но только в первый раз, когда это представление / вкладка открывается пользователем. Я хотел бы вызывать функцию (для обновления геолокации) всякий раз, когда пользователь открывает это представление или вкладку.

Как правильно это реализовать?

Спасибо за помощь!

Хорре
источник
попробовать {{doSomething ()}}?
Asik
1
проблема не в doSomething (), поскольку он запускается нормально, просто он не запускается дважды. В первый раз, когда представление открывается, оно работает нормально, во второй раз кажется, что оно просто загружает кешированное представление или что-то в этом роде?
Jorre
ng-init вызывает функцию только один раз. вы можете вызвать ng-controller = "doSomething ()" или {{doSomething ()}} в ваших частичных представлениях, и функция запускается всякий раз, когда вызывается router / partial.
Asik
3
в состоянии конфигурации установите для кеша значение false. Ознакомьтесь с моим ответом.
Якоб Убайди

Ответы:

46

Если вы назначили определенный контроллер вашему представлению, то ваш контроллер будет вызываться каждый раз, когда ваше представление загружается. В этом случае вы можете выполнить некоторый код в своем контроллере, как только он будет вызван, например, таким образом:

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

И в вашем контроллере:

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

Изменить: вы можете попытаться отслеживать изменения состояния, а затем выполнить некоторый код, когда маршрут изменяется и определенный маршрут посещается, например:

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

Вы можете найти более подробную информацию здесь: События изменения состояния .

Маниш Кр. Шукла
источник
6
Спасибо, но это именно то, что я делаю. Этот код будет запускаться только один раз, когда представление было открыто в первый раз. Я пытался записать что-то на свою консоль, но она срабатывает только в первый раз.
Jorre
Когда вы говорите, что это работает в вашем приложении, вы также говорите об ионном приложении? Я пытаюсь понять, может ли это быть так, у меня это не работает.
Jorre
2
Работа с stateChange помогает, просто щелчок по вкладке выполняется только один раз. Спасибо за редактирование!
Jorre
Я думаю, это связано с тем, как Ionic кэширует определенные части вашего приложения. может быть, установка cache-viewfalse поможет? ionicframework.com/docs/api/directive/ionView search for cache-view
Майкл Труу,
Возможно, это проблема недавнего выпуска ionic. Однако вы также можете отключить кеш на уровне маршрутов. просто добавьте cache: false для каждого маршрута в вашей конфигурации маршрутов.
Маниш Кр. Shukla
88

По умолчанию ваши контроллеры были кешированы, поэтому ваш контроллер запускается только один раз. Чтобы отключить кеширование для определенного контроллера, вам нужно изменить свой .config(..).stateи установить cacheопцию false. например:

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

для дальнейшего чтения посетите http://ionicframework.com/docs/api/directive/ionNavView/

Якоб Убайди
источник
2
Очень полезно для контроллера выхода из системы
mrwaim 08
3
Очень жаль, что в ionic по умолчанию включено кеширование. Похоже, это должна быть функция согласия, а не добавление по умолчанию.
oalbrecht
Мне нужно было перезагрузить только одно состояние, поэтому я использовал: $state.go('app.statename', {}, {reload:true});( подробнее , источник ).
Sjoerd Pottuit
1
Хотя это работает, это не совсем правильный способ. Это замедлит ваше приложение - если вы не хотите проходить всю процедуру инициализации контроллера каждый раз, когда пользователь переключается на это представление, я думаю, что ответ jczaplew - более приятный подход.
Крис Рэй,
Качественный товар. Я отключил кеширование во всем приложении. Рад, что наткнулся на этот ответ
Роберт Нгетич
50

Следуя ответу и ссылке от AlexMart , работает что-то вроде этого:

.controller('MyCtrl', function($scope) {
  $scope.$on('$ionicView.enter', function() {
     // Code you want executed every time view is opened
     console.log('Opened!')
  })
})
Jczaplew
источник
3
$ionicView.beforeEnterэто, вероятно, то, что вы хотите. $ionicView.enterсрабатывает после того, как "вид полностью открыт" . Если вы используете анимированные переходы между видами, то using $ionicView.beforeEnterвыполняется до начала перехода. Это означает, что вы можете запускать свой код во время перехода, что, скорее всего, приведет к тому, что ваше приложение станет более «быстрым».
rinogo
Думаю, это самый простой и ясный ответ. Что касается комментария @rinogo, я думаю, что каждый программист может решить, использовать ли "enter" или "beforeEnter", в зависимости от того, что происходит в представлении / контроллере. Здесь важно понимать, что вы можете обрабатывать события жизненного цикла для вызова функции каждый раз, когда вы входите в свое представление.
jcarballo
12

Я столкнулся с той же проблемой, и здесь я оставляю причину такого поведения для всех остальных с той же проблемой.

Посмотреть LifeCycle

Чтобы повысить производительность, мы улучшили способность Ionic кэшировать элементы представления и данные области видимости. После инициализации контроллера он может сохраняться на протяжении всей жизни приложения; он просто скрыт и удален из цикла просмотра. Поскольку мы не перестраиваем область видимости, мы добавили события, которые мы должны слушать при повторном входе в цикл просмотра.

Чтобы увидеть полное описание и события $ ionicView, перейдите по адресу : http://ionicframework.com/blog/navigating-the-changes/

AlexMart
источник
9

Почему бы вам не отключить кеш просмотра с помощью cache-view = "false" ?

На ваш взгляд, добавьте это в ion-nav-view следующим образом:

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

Или в вашем stateProvider:

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

Любой из них сделает ваш контроллер вызываемым всегда.

Диого Медейрос
источник
Не будет ли у этого побочных эффектов производительности? Я предполагал, что представление кэшируется, поэтому все представление не перезагружается каждый раз. Отключение этой функции не приведет к повторной загрузке всей страницы, в то время как мы хотим, чтобы снова выполнялся только фрагмент кода?
Sindarus 05
Наверное, да @Sindarus. Но есть несколько необходимых случаев. Для меня у меня есть чертеж плагина на представлении, и я не мог понять, как его очистить.
Диого Медейрос
Это было идеальное решение для моего случая, я выходил из системы, а затем снова посещал контроллер, я не хочу кэшировать, и все должно быть повторно инициализировано. благодарю вас!
Firas Abd Alrahman
5

Например, @Michael Trouw,

внутри вашего контроллера поместите этот код. это будет запускаться каждый раз, когда это состояние вводится или активно, вам не нужно беспокоиться об отключении кеша, и это лучший подход.

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

У вас может быть больше примеров гибкости, например $ ionicView.beforeEnter ->, который запускается перед отображением представления. И это еще не все.

Ван'л Пахрин
источник
2

Учитывая способность Ionic кэшировать элементы представления и данные области, упомянутые выше, это может быть другим способом сделать, если вы хотите запускать контроллер каждый раз при загрузке представления. Вы можете глобально отключить механизм кеширования, используемый ionic, выполнив:

$ionicConfigProvider.views.maxCache(0);

Иначе то, как у меня это работало для меня, делало

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

Это необходимо для очистки кеша перед выходом из представления для повторного запуска контроллера каждый раз, когда вы снова входите.

Раджуш
источник
1

Вероятно, это то, что вы искали:

Ionic кэширует ваши представления и, следовательно, ваши контроллеры по умолчанию (максимум 10) http://ionicframework.com/docs/api/directive/ionView/

Есть события, к которым вы можете подключиться, чтобы позволить вашему контроллеру делать определенные вещи на основе этих ионных событий. см. здесь пример: http://ionicframework.com/blog/navigating-the-changes/

Майкл Троу
источник
1
Можно улучшить, показывая пример кода вместо простого обмена ссылкой
Лоуренс Веру
Есть ли что-нибудь подобное и на Angular Js?
Wang'l Pakhrin
@ Wang'lPakhrin по умолчанию любой код, IIFE или функция, которую вы объявляете и запускаете внутри функции вашего основного контроллера, будет выполняться каждый раз при загрузке представления (и, следовательно, контроллера). Если вам нужно такие события , как выполнить функцию один раз в жизни вашего приложения, проверить угловатые-Ui-маршрутизатор липких состояний и ViewContentLoadingи ViewContentLoadedсобытие :)
Michael Trouw
0

У меня была аналогичная проблема с ionic, когда я пытался загрузить родную камеру, как только я выбираю вкладку камеры. Я решил проблему, установив в контроллере компонент ion-view для вкладки камеры (в tabs.html), а затем вызвав метод $ scope, который загружает мою камеру (addImage).

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

Метод addImage, определенный в AddMediaCtrl, загружает собственную камеру каждый раз, когда пользователь щелкает вкладку «Камера». Мне не нужно было ничего менять в кеше angular, чтобы это работало. Надеюсь, это поможет.

чуккугон
источник