Replacing content on the left/right SideMenuController


#1

Thanks for creating an awesome framework!!

I have an app that uses the nav-bar within the center pane of the side views. I would like to replace the contents of the left and right sides when I move between routes… is there an easy way to do this or is this simply outside of the existing use case for this widget?

Can you recommend an approach that would allow me to do this? I’m thinking that I might need to create a separate page with nav-bar and side-menu structure for every page there’s a different side-menu.

Any suggestions?
Thanks!


Side menu with dynamic content, best approach?
#2

I’d suggest you use a service for this.

I’ve put a Plnkr together that demonstrates this:

NOTE : The ‘Servers’ and ‘Accounts’ pages don’t exist in the router, so they will just redirect to home.


#3

Thanks so much for the prompt reply and the Plnkr example! I can make this work. Unless I’m missing something what it will mean is that I need to come up with a common template that I can reuse across all nav-pages and then a data model within the service (as you suggested) that populates that template for the different nav-pages.

Honestly I was hoping for any easy means of dropping a completely new template into left and right - with rendering handled by the controller for the new ‘nav-page’.

I did manage to send html as string content via $emit, using a corresponding $on to update a controller variable. A custom directive was used within the html to compile that variable upon change. I don’t like this approach bc it encourages me to assemble html string in the controller.

I was thinking that a nice solution might be if I could put a hidden element in the new nav-page, have angular compile it for me (normally) and then just pass the element or elementId into the SideMenuController to replace the existing left or right menus…

LOL - I have a feeling that some of this is me still coming to terms with and angularizing my thinking… :wink:


#4

That was just one possible example. I don’t think that rending HTML on the fly is necessarily a good idea. Certainly doing so in the controller is frowned upon. That type of work should be done in a directive.

You could also build out all of the various side menus you have in mind all together in one side menu. Then, depending on whatever state you monitor, use ng-if`` orng-showor `ng-hide` or `ng-switch to present the information.


#5

Hello,

I’m starting to play with ionic, and i’m facing a little problem similar to this topic.
It’s a simple use case, I just want to show/hide menu items depending on context (user is logged or not, using ng-hide/ng-show).
My problem is that it seems that the side menu isn’t refreshing the data it’s based on after model changes.
So as a simple test i’m trying to output a variable, it’s working on a view, but not on the side menu (menu/view are using same controller/variables).

Thanks a lot.


#6

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:

  1. I didn’t have to write any custom code - just use existing ionic and angular directives.
  2. I separate the side menu content from the top level page layout.
  3. Unlike some other methods (e.g. pure string) the templates live in the html and I can leverage my IDEs html checking and formatting.
  4. 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:

  1. 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.
  2. 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.
  3. 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!


#7

Thank you, i’ll give that a try and report back my experience.


#8

darrin, thanks a lot for your post that helped me to start with dynamic side-menus.
In the end, I found another (easier?) way to do it and I wanted to share it here.

I started by doing the same 3 steps as you:
1 - index.html with <div ng-include src="leftSide.src"></div>
2- SideMenuSwitcher service
3- Add init to AppCtrl

Then, I did it another way:
4- I created my-left-menu.html with no <script> tag at all:

        <div>
            <p>App 1</p>
            <p>App 2</p>
            <p>App 3</p>
        </div>

5- When I want to switch to a new left side menu, I just add in the concerned controller:
$scope.leftSide.src = "templates/my_left_menu.html";

5bis- In another controller:
$scope.leftSide.src = "templates/another_left_menu.html";


#9

Walt,
I got similar requirement and I searched extensively however I didnt find any good solution for this till now.
Could you please elaborate it more how you solved this problem.

Regards,
Suhas


#10

Thank you so much Darrin & Walt. I got it worked :slight_smile:


#11

Very good, this solved me a lot of problems. But, one question: in the ‘templated’ menu (the one you have into the ng-template script), i’ve include some ion-list… but it seems not to understand the ng-click directive (the same directive, with the same function called, works into the ‘static’ right side menu):

<ion-list>
        <ion-item nav-clear href="#" ng-controller="PlannerCtrl" ng-click="getPlanner()">
          <i class="icon ion-loop"></i>&nbsp;&nbsp;Refresh
        </ion-item>

Can something be done for this ?

Thanks in advance


#12

Thanks so much! You can even use the specific page controllers by adding the ng-controller tag to the div but i guess you know that <3