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:
- Strangemilk [dot] com: Building an iOS App with Ionic – Part 2 (Nested States)
- Andrew McGivery: Understanding Ionic’s Side Menu
- Gabe Scholz: Effectively maintaining state in AngularJS applications