How to destroy controllers in ion-tab directive?

I have a weird issue with all of my controllers persisting across every state inside of an ion-tab.

My routes:

// setup an abstract state for the tabs directive
.state('tab', {
  url: '/tab',
  abstract: true,
  templateUrl: 'templates/tabs.html',

.state('', {
  url: '/one',
  views: {
    'main-tab': {
      templateUrl: 'templates/one.html',
      controller: 'oneCtrl'

.state('tab.two', {
  url: '/one/:id',
  views: {
    'main-tab': {
      templateUrl: 'templates/two.html',
      controller: 'twoCtrl'

.state('tab.three', {
  url: '/one/:id/two/:twoId',
  views: {
    'main-tab': {
      templateUrl: 'templates/three.html',
      controller: 'threeCtrl'

The Main template holds a tab and all of the other view are shown inside of it:

<ion-tab title="tab" icon="icon ion-home" href="#/tab/patients">
    <ion-nav-view name="main-tab"></ion-nav-view>

My problem is that when I change views a controller is created, but NEVER destroyed when I move to a new view. I can confirm this by adding a logger with timeout to each controller:

var onTimeout = function() {
        $scope.value += 1;
        $timeout(onTimeout, 1000);
    $timeout(onTimeout, 1000);
    $scope.value = 0;

This will continue logging from the previous view as a navigate to new views. WTH?

Am I using ion-tabs incorrectly? I want to be able to refresh data on certain views, but since the controller is never destroyed, it cannot update its scopes.

ie: if I am in tab.three and I call $state.go('', {}, {reload: true}) then my resolve property in the controller will be triggered, but the new data will never be assigned in the controller as the controller is still running.

Here is a jsbin example:

Notice that the console log is coming from the homeTabCtrl, but if you change tabs, the $timout keeps running. I want that controller to die when you change tabs. Is this possible?

solution is to set


Not sure if I agree with the default behavior to cache all views as it also caches the controller scopes. This basically means that data will not refresh on view changes.

Hey there

So cacheing views/scopes was done so we can have access to that data right away, this way we can do thing such as swipe to go back (coming soon).
Plus there’s a performance benefit.
Your app isn’t constantly rebuilding these scopes, but can just reconnect things on the fly.

To make sure you can stop functions that run in the background, we have created these view event (in our docs), which allow you to bind to certain events emitted on view change.

1 Like