I tried a number of things to get this working and I’ll share where I’ve arrived. I don’t claim to be an angular expert and I wrote this months ago so it’s entirely possible that I’m missing a piece and that this can be made better (if so please do share) - but for what it’s worth here’s how I solved this problem:
First in my index.html:
<ion-side-menus id="side-menus">
<!-- Center content -->
<ion-side-menu-content nav-router animation="slide-left-right">
<ion-nav-bar class="bar-dark"
animation="nav-title-slide-ios7"
back-button-type="button-icon button-clear"
back-button-icon="ion-ios7-arrow-back"></ion-nav-bar>
<ion-nav-view></ion-nav-view>
</ion-side-menu-content>
<!-- Left menu -->
<ion-side-menu id="side-menu-left-content" side="left">
<div ng-include src="leftSide.src"></div>
</ion-side-menu>
<!-- Right menu -->
<ion-side-menu id="side-menu-right-content" side="right">
<div ng-include src="rightSide.src"></div>
</ion-side-menu>
Next I created a new service that does nothing more than hold the current location of the left and right side content (leftSide.src and rightSide.src above) so they can be watched for changes:
.factory('SideMenuSwitcher', function ($rootScope) {
return {
leftSide: {src: ''},
rightSide: {src: ''}
};
})
Then I bind the services variables in the top level AppCtrl so that when leftSide.src and rightSide.src change the app can pick up those changes (see below).
.controller('AppCtrl', function ($scope, $rootScope, $location, SideMenuSwitcher, $ionicSideMenuDelegate) {
$scope.leftSide = SideMenuSwitcher.leftSide;
$scope.rightSide = SideMenuSwitcher.rightSide;
})
Now in each page where I want to swap menus out I include a scripted html template that includes an ng-init action. The ng-init action changes to leftSide and rightSide src variables to point to themselves (note the ‘id’ value has to be uniquely tied to the html element as always). This is the cool part - the ng-includes from above automatically see the change to their ‘src’ variable and re-render the contents of the side menus using the templates that you just included in the new page/view.
With all this in place you now separate your left and right menus using html script templates (though separate pages would probably work too) - so in my top level page I have something like this:
<script type="text/ng-template" id="app-left-menu.html" ng-init="leftSide.src='app-left-menu.html'">
<div>
<p>App 1</p>
<p>App 2</p>
<p>App 3</p>
</div>
</script>
And then in a child page/view - I replace menus by including new html templates in script tags like this:
<script type="text/ng-template" id="other-page-left-menu.html" ng-init="leftSide.src='other-page-left-menu.html'">
<div>
<p>Other Page 1</p>
<p>Other Page 2</p>
<p>Other Page 3</p>
</div>
</script>
What I liked about this approach is that:
- I didn’t have to write any custom code - just use existing ionic and angular directives.
- I separate the side menu content from the top level page layout.
- Unlike some other methods (e.g. pure string) the templates live in the html and I can leverage my IDEs html checking and formatting.
- It felt like about the right number of moving parts - the service to hold the current values of left and right side, binding to the app controller, the main page layout for left/right sidebar and then what to populate into the templates per view.
A couple other things I’ve thought about doing in the service:
- Build a directive rather than using the ng-include and scripted html template - but it felt too complicate for too little win… and would be even more magical.
- Add a method into the SideMenuSwitcher to explicitly change the src values - so you can do it from a button - I’ve not yet had need to do it - but your use case will require it - and you’ll probably also want to be able to turn the menus off altogether via an API at the service level.
- Add a method to detect a location change and null out the right and left side if there’s no definition for it on the page - effectively disable side menus on some views.
What I didn’t like and loved at the same time wrt this whole experience is that the ng-include ‘src’ was itself derived from a variable and changing that is picked up by angular and magically it re-renders the page. This feels both awesome and scary all at once…
It seems like it could be a general technique for dynamically changing pages - but I worry that I might be missing something important about efficiency here.
I’d love to hear someone tell me that this is all overly complicated and it can be done much more simply… if so please do tell… If not - I hope that helps you get a foothold on how to solve your problem!