Ionic's sidemenu template and nested states

Update: You will often run into '< Back' button problems if you use 'href'. The Ionic framework uses the angular-ui-router module for handling routes and defining states (including nested states and nested views) so you need to use 'ui-sref' or '$state.go()'.

For example: http://plnkr.co/edit/pGwucVrTBDxSvw6z092h?p=preview

To learn more about how the Ionic framework uses the Angular UI router for handling routes, defining states and sharing data between views please refer to this post.

I ran into some issues when working with the Ionic framework's (v1.0.0-beta.14) sidemenu template and nested states.

The first problem I noticed was in menu.html:

<ion-side-menu-content>
    <ion-nav-bar class="bar-stable">
        <ion-nav-back-button>
        </ion-nav-back-button>

        <ion-nav-buttons side="left">
            <button class="button button-icon button-clear ion-navicon" 
                menu-toggle="left">
            </button>
        </ion-nav-buttons>

    </ion-nav-bar>
    <ion-nav-view name="menuContent"></ion-nav-view>
</ion-side-menu-content>

The ion-nav-buttons directive should be a direct descendant of the ion-nav-view directive. So, I moved it from menu.html into playlists.html:

<ion-view view-title="Playlists">

    <ion-nav-buttons side="left">
        <button class="button button-icon button-clear ion-navicon" 
            menu-toggle="left"></button>
    </ion-nav-buttons>

    <ion-content>
        <ion-list>
            <ion-item ng-repeat="playlist in playlists"
                ui-sref="app.playlists({playlistId: playlist.id})">
            {{playlist.title}}
            </ion-item>
        </ion-list>
    </ion-content>

</ion-view>

Now, if you take a look at the config function in app.js:

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider

    .state('app', {
              url: "/app",
         abstract: true,
      templateUrl: "templates/menu.html",
       controller: 'AppCtrl'
    })

    .state('app.playlists', {
      url: "/playlists",
        views: {
          'menuContent': {
            templateUrl: "templates/playlists.html",
             controller: 'PlaylistsCtrl'
        }
      }
    })

    .state('app.single', {
      url: "/playlists/:playlistId",
        views: {
         'menuContent': {
           templateUrl: "templates/playlist.html",
            controller: 'PlaylistCtrl'
        }
      }
    });

    ...

You'll notice that each of the view templates will be loaded into the ion-nav-view declared in menu.html:

<ion-nav-view name="menuContent"></ion-nav-view>

You will also notice that 'app' is the root state and that 'app.playlists' and 'app.single' are nested states.

The second problem I experienced was that if you navigate between nested states:

http://localhost:8100/#/app/playlists
http://localhost:8100/#/app/playlists/1
http://localhost:8100/#/app/playlists/2
http://localhost:8100/#/app/playlists

The ion-nav-bar is rendered with both the ion-nav-back-button's default icon and text, and the ion-nav-buttons icon.

My app has several levels of nested states:

  .state('app.main.choose-event', {
    url: "/choose-event",
    views: {
      'menuContent@app': {
        templateUrl: "templates/choose-event.html",
         controller: 'ChooseEventController'
      }
    }
  })

For example, the app.main.choose-event state, is a child state of the app.main state. And, the app.main state, is a child state of the app state.

In order to have the ion-nav-bar render correctly, I had to remove the ion-nav-back-buttons directive from menu.html:

<ion-side-menu-content>
    <ion-nav-bar class="bar-positive">
    </ion-nav-bar>
    <ion-nav-view name="menuContent"></ion-nav-view>
</ion-side-menu-content>

Add add ion-nav-buttons directives to each of my views, for example:

<ion-view view-title=".state('app.main'">

    <ion-nav-buttons side="left">
        <button class="button button-icon button-clear ion-navicon"
            menu-toggle="left">
        </button>
    </ion-nav-buttons>

    <ion-content class="has-header has-footer">
       ...
    </ion-content>

</ion-view>

And:

<ion-view view-title=".state('app.main.choose-event'">

    <ion-nav-buttons side="left">
        <button class="button button-icon button-clear"
            ui-sref="app.main">
            <i class="icon ion-ios7-arrow-back"></i>
        </button>
    </ion-nav-buttons>

    <ion-content class="has-header has-footer">
       ...
    </ion-content>

</ion-view>

Now, I can use $state.go() in my controllers to transition between (nested) states and the ion-nav-bar is rendered correctly:

Note: You can change the ion-nav-back-button's default icon and text:

$ionicConfigProvider.backButton.icon('ion-ios7-arrow-back');
$ionicConfigProvider.backButton.text('');
$ionicConfigProvider.backButton.previousTitleText(false);

References: