Bug in TabBar with nested states?

Hello guys, I think I’ve found a little but annoying bug when using nested states in tab subviews…

If I use a nested state in the first tab, it works perfectly, reloads well and if it’s the default route it runs well. But if I try to use a nested state in the second tab, it doesn’t load if it’s the initial url or if I reload it (it’s the same), it only works if I navigate to another tab and then back to it.

In my app I have a main abstract state for the tabs, as in the starter project:

.state('tab', {
  url: "/tab",
  abstract: true,
  templateUrl: "templates/tabs.html"
})

And then two abstract states to nest more states to them:

.state('tab.user', {
  url: '/user',
  abstract: true
})

.state('tab.search', {
  url: '/search',
  abstract: true
})

Then I have some other states nested to the abstract ones:

.state('tab.search.form', {
  url: '/list',
  views: {
    'search-tab@tab': {
      templateUrl: 'templates/search.html'
    }
  }
})

.state('tab.user.profile', {
  url: '/profile',
  views: {
    'user-tab@tab': {
      templateUrl: 'templates/profile.html'
    }
  }
})

The /tab/search/form is the first tab and works ok, and loads ok if it’s the default or first url the app loads (it refreshes ok). The /tab/user/profile is the second tab and works ok if you enter to it after loading the app in another tab, if you try to load this url directly it doesn’t works well. It loads the tab bar but with the first tab selected instead of the second, and no view or title bar appears.

If I switch the order of the tabs in the tabs.html the problem switches from one view to another, the profile one works perfectly and the search begins to fail.

I’ve tried to figure why, debugging the Ionic code, but I’m totally lost for this one. Some help will be appreciated.

Thanks!

2 Likes

Hmm, to be honest I am not completely sure. @adam is the resident navigation guru and tab expert.

It could be simply that the tab bar has only one abstract state, where the children of that state are the tabs. Since you have two abstract states, when you switch to the next abstract state everything becomes lost.

Is there a reason for using two abstract states? It seems like you could simply have tab.form and tab.profile.

Yes, I need to use nested states because I have a lot substates in each tab and I need also to use ui-sref relative urls because I reuse some views from one tab to another.

For example, I have a view for routes (is an app about routes, places, …) and a view for places that need to work navigating from your profile tab (your routes, your places) and from the search tab (results > route / place), and there are a lot like that (it’s a huge app).

Would you be able to create a plunker? It might be easier to see exactly what you mean. Thanks.

@adam - I am quite sure I am having the same issue. I have the following code which works in my ng-app with ui-router but trying to use the same logic / code in the Ionic apps never parses the view. I have tried a million different ways to do this with no luck:

      .state('products', {
    url: '/products',
    templateUrl: 'views/products/products.html',
    controller: 'ProductsCtrl',
    resolve: {
      isAuthenticated: isAuthenticated,
      products: products,
      categories: categories,
      tags: tags,
      goals: goals
    }
  })
  .state('products.list', {
    url: '/list',
    templateUrl: 'views/products/products.list.html'
  })
  .state('products.detail', {
    url: '/detail/:productId',
    templateUrl: 'views/products/products.detail.html',
    controller: 'ProductsDetailCtrl',
    resolve: {
      isAuthenticated: isAuthenticated,
    }
  })

Note the code I am using in ionic is the following:

    .state('tab.purchases', {
  url: '/purchases',
  views: {
    'tab-purchases' :{
      templateUrl: 'js/purchases/purchases-list.html',
      controller: 'PurchasesCtrl'
    }
  },
  resolve: {
    isAuthenticated: isAuthenticated,
    purchases: purchases
  }
})
.state('tab.purchases.detail', {
  url: '/detail/:purchaseId',
  views: {
    'tab-purchases' : {
      templateUrl: 'js/purchases/purchases-detail.html',
      controller: 'PurchasesDetailCtrl'
    }
  },
    resolve: {
      isAuthenticated: isAuthenticated
    }
})

The following illustrates the closes I have been able to get to something that works:

.state('tab.purchases', {
  url: '/purchases',
  views: {
    'tab-purchases' :{
      templateUrl: 'js/purchases/purchases-list.html',
      controller: 'PurchasesCtrl'
    }
  },
  resolve: {
    isAuthenticated: isAuthenticated,
    purchases: purchases
  }
})
.state('tab.purchases-detail', {
  // Issues with nesting views in Ionic.  Possible bug??
  url: '/purchases/detail/:purchaseId',
  views: {
    'tab-purchases' : {
      templateUrl: 'js/purchases/purchases-detail.html',
      controller: 'PurchasesDetailCtrl'
    }
  },
    resolve: {
      isAuthenticated: isAuthenticated
    }
})

Maybe I am using this wrong but after reviewing the ui-router docs and the ionic docs I think I am dealing with the same issue as reported above and in some other issues regarding this.

I will do my best to open a plunker on this tomorrow.

Hi all,

Any update on this topic?. I think I’m experiencing the same problem on v1.0.0-beta.9.

I made an example (http://codepen.io/anon/pen/GwpIc?editors=101) and wonder the following:

  • Why does the “Tab2” selection button not work when the app is first loaded?.
  • Why does it work after using the “Link to tabs.tab2” link?.
  • Why do the “Link to tabs.tab2.home1” and “Link to tabs.tab2.home1” links in the first tab not work at all?.

EDIT: I found the three points above are solved by declaring explicitly the destiation state of each tab using ui-sref. The following example based on the previous one shows it: http://codepen.io/anon/pen/szhLu?editors=101

Using href would also work.

Nevertheless I still don’t understand the reason. Is using ui-sref or href mandatory?. According to the current documentation they aren’t.

EDIT2: opened a related question in Stack Overflow: http://stackoverflow.com/q/24664986/2050333

Thanks in advance.
Cheers,
Rafa.

Hi,
I have tried nesting tabs using the default tabs templates created using $ ionic start myApp tabs… and it works just adding some styling to the nested tabs tag to avoid overlapping…

<ion-tabs class="tabs-icon-top has-header has-footer" style="background:#ff0000; border:1px solid red; top:44px; bottom:49px; height:auto;" delegate-handle="subtabs-handler">

(top, bottom and height are the ones to care, any other styling is for better spotting).

The only thing you have left to do is using $ionicTabsDelegate to make sure you are calling the right tabs…

.controller(‘SubTabCtrl’, function($scope, $state, $ionicTabsDelegate) {

//this call forces the loading of the subtab content so the panes are removed
$state.go(‘tab.account.subtab1’);

//the function to be called from the subtabs links
$scope.selectTabWithIndex = function(index) {
$ionicTabsDelegate.$getByHandle(‘subtabs-handler’).select(index);

	switch (index){
		case 0:
		$state.go('tab.account.subtab1');
		break;
		case 1:
		$state.go('tab.account.subtab2');
		break;
		case 2:
		$state.go('tab.account.subtab3');
		break;
	}
}

});

Being tab-account the tab is holding the subtabs… And having almost the same kind of abstract template as the tabs.html template. Just changing the href for the ng-click…

> <ion-tab title="sub tab 1" icon="icon ion-home" ng-click="selectTabWithIndex(0)"> 
>     <ion-nav-view name="account-subtab1"></ion-nav-view>
>   </ion-tab>

This should do the thing.

Cheers.

I have ran into the same issue where using nested tabs does not load views. I think i know what causes it.
When you declare your states as the OP uniring posted, you have different names of the ion-nav-views in your tabs, in this case you’ll have user-tab and search-tab.
Now i noticed that the tab implementation only keeps one active ion-nav-view in the DOM per tab.

1)So if you load the tab.user.profile state, it will load the user-tab ion-nav-view in the DOM. Navigating to any sub state at this point is going to work fine because ui-router can view the ‘user-tab’ view.
2) Problem now is, if you try to load a different state in a different tab, which requires a differently name ion-nav-view, for example you want to load the ‘tab.search-.form’ state, guess what? there is no ‘search-tab’ ion-nav-view element in the DOM, so ui-router gets confused as to where to load the content, it’s able to retrieve the template to load and all but it just does not know where to load it.
3)How to solve it? First, i think ui-router should definitely throw an error if it can’t find a named view. Second maybe the ion-tabs directive should keep the other ion-nav-view declarations in the DOM instead of loading them based on the active tab, if that is really the error.
Still looking on a good way of solving it.

My take on it, hope it helps you guys out there.

On further update, i think ion-tabs just does not play well with abstract states. On making my previous abstract states just regular states everything worked fine.

See my comment on this issue, it appears to be an issue with $scope inheritance and nested tabs.