Run a controller function whenever a view is opened/shown

AngularjsIonic Framework

Angularjs Problem Overview


I'm building an app with angular+ionic that uses a classic three-button menu at the bottom with three ion-tabs in it. When a user clicks a tab, that template opens through ui-router.

I have states like this:

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

In the template I do something like:

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

I'm aware that I can write the doSomething() function in my controller and just call it manually there. That gives me the same problem though. I can't seem to figure out how to call the doSomething() function more than once, whenever somebody opens that view.

Right now, the doSomething() function gets called just fine, but only the first time that view/tab gets opened by the user. I'd like to call a function (to update geolocation) whenever a user opens that view or tab.

What would be a correct way to implement that?

Angularjs Solutions


Solution 1 - Angularjs

By default, your controllers were cache and that is why your controller only fired once. To turn off caching for a certain controller you have to modify your .config(..).state and set the cache option to false. eg :

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

for further reading please visit http://ionicframework.com/docs/api/directive/ionNavView/

Solution 2 - Angularjs

Following up on the answer and link from AlexMart, something like this works:

.controller('MyCtrl', function($scope) {
  $scope.$on('$ionicView.enter', function() {
     // Code you want executed every time view is opened
     console.log('Opened!')
  })
})

Solution 3 - Angularjs

If you have assigned a certain controller to your view, then your controller will be invoked every time your view loads. In that case, you can execute some code in your controller as soon as it is invoked, for example this way:

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

And in your 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;
});

Edit: You might try to track state changes and then execute some code when the route is changed and a certain route is visited, for example:

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

You can find more details here: State Change Events.

Solution 4 - Angularjs

I faced at the same problem, and here i leave the reason of this behavior for everyone else with the same issue.

> View LifeCycle > >In order to improve performance, we've improved Ionic's ability to cache view elements and scope data. Once a controller is initialized, it may persist throughout the app’s life; it’s just hidden and removed from the watch cycle. Since we aren’t rebuilding scope, we’ve added events for which we should listen when entering the watch cycle again.

To see full description and $ionicView events go to: http://ionicframework.com/blog/navigating-the-changes/

Solution 5 - Angularjs

Why don't you disable the view cache with cache-view="false"?

In your view add this to the ion-nav-view like that:

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

Or in your stateProvider:

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

Either one will make your controller being called always.

Solution 6 - Angularjs

For example to @Michael Trouw,

inside your controller put this code. this will run everytime when this state is entered or active, you do not need to worry about disabling cache and it's a better approach.

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

You can have more examples of flexibility like $ionicView.beforeEnter -> which runs before a view is shown. And there are some more to it.

Solution 7 - Angularjs

Considering Ionic's ability to cache view elements and scope data mentioned above, this might be another way of doing, if you want to run the controller every time the view gets loaded. You can globally disable the caching mechanism used by ionic by doing:

$ionicConfigProvider.views.maxCache(0);

Else, the way I had it working for me was doing

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

This is to clear the cache before leaving the view to re-run controller every time you enter back again.

Solution 8 - Angularjs

This is probably what you were looking for:

Ionic caches your views and thus your controllers by default (max of 10) http://ionicframework.com/docs/api/directive/ionView/

There are events you can hook onto to let your controller do certain things based on those ionic events. see here for an example: http://ionicframework.com/blog/navigating-the-changes/

Solution 9 - Angularjs

I had a similar problem with ionic where I was trying to load the native camera as soon as I select the camera tab. I resolved the issue by setting the controller to the ion-view component for the camera tab (in tabs.html) and then calling the $scope method that loads my camera (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>

The addImage method, defined in AddMediaCtrl loads the native camera every time the user clicks the "Camera" tab. I did not have to change anything in the angular cache for this to work. I hope this helps.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJorreView Question on Stackoverflow
Solution 1 - AngularjsYakob UbaidiView Answer on Stackoverflow
Solution 2 - AngularjsjczaplewView Answer on Stackoverflow
Solution 3 - AngularjsManish Kr. ShuklaView Answer on Stackoverflow
Solution 4 - AngularjsAlexMartView Answer on Stackoverflow
Solution 5 - AngularjsDiogo MedeirosView Answer on Stackoverflow
Solution 6 - AngularjsWang'l PakhrinView Answer on Stackoverflow
Solution 7 - AngularjsRajushView Answer on Stackoverflow
Solution 8 - AngularjsMichael TrouwView Answer on Stackoverflow
Solution 9 - AngularjschukkwagonView Answer on Stackoverflow