Skip to content
This repository was archived by the owner on Mar 3, 2023. It is now read-only.

Ionic_Menu

Miroslav Smukov edited this page May 2, 2016 · 9 revisions

Menu

In this post I'm going to write about implementing a "side menu" inside the Ionic app. My Native Android version already has this menu since it was created from a template, but for Ionic I have to implement it on my own - luckily, that's not too hard.

Menu Interface Template

Creating a menu involves creating an HTML template for that menu's interface. For this I created a new app.html file within the app folder and added the following code.

Source Code

<ion-menu [content]="content">
 <ion-toolbar>
   <ion-title>Menu</ion-title>
 </ion-toolbar>
 <ion-content>
   <ion-list>
     <button ion-item *ngFor="#p of pages" (click)="openPage(p)">
       {{p.title}}
     </button>
   </ion-list>
 </ion-content>
</ion-menu>

<ion-nav id="nav" #content [root]="rootPage"></ion-nav>

The last line (apart from the #content) was already set inside the app.js file as the app's template. Everything within <ion-menu> tags is the HTML code for the side menu that will be displayed. Let's explain this code a little bit by starting with the following piece:

<ion-nav id="nav" #content [root]="rootPage"></ion-nav>

In order to use Menu, you must specify a reference to the content element that Menu should listen on for drag events, using the content property. This is telling the menu which content the menu is attached to, so it knows which element to move over, and to respond to drag events. Note that a menu is a sibling to its content.

By adding the #content to <ion-nav> we are creating a local variable called content which references this component. We are then using this variable to set the <ion-nav> as the content property of the <ion-menu> through the following piece of code: [content]="content".

With the [root]="rootPage" we are setting the root property to the rootPage variable which we'll later define in the app.js file.

Next, let's move on to this piece of code:

 <ion-list>
   <button ion-item *ngFor="#p of pages" (click)="openPage(p)">
     {{p.title}}
   </button>
 </ion-list>

So, within the <ion-content>, which is obviously the content of our menu, we are declaring a list of buttons for each page within the pages variable that we'll define inside the app.js file as well.

ngFor will create a button for each page we defined in the constructor earlier (like ng-repeat in Angular 1), the * syntax means it will create an embedded template for each of the pages (it won’t render out the exact code we have above to the DOM, instead it will use the templates created), and by using #p we are able to keep a reference to a specific page, which we pass into the openPage function (defined in app.js file) when the button is clicked.

Next, let's move on to the app.js file.

Adding the Menu to the Main Component (App.js)

After I added the menu to app.js my code looks like this:

Source Code

import 'es6-shim';
import {App, Platform, IonicApp, MenuController} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {TabsPage} from './pages/tabs/tabs';
import {Page1} from './pages/page1/page1';
import {Page2} from './pages/page2/page2';
import {Page3} from './pages/page3/page3';


@App({
  //template: '<ion-nav [root]="rootPage"></ion-nav>',
  templateUrl: 'build/app.html',
  config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
export class MyApp {
  //this gets injected into constructor below, it's the order that matters
  static get parameters() {
    return [[IonicApp], [Platform], [MenuController]];
  }

  constructor(app, platform, menu) {
    this.app = app;
    this.platform = platform;
    this.menu = menu;
    this.initializeApp();

    // set our app's pages
    this.pages = [
        { title: 'Page 1', component: Page1 },
        { title: 'Page 2', component: Page2 },
        { title: 'Page 3', component: Page3 }
    ];

    this.rootPage = Page1;
  }

  initializeApp() {
    this.platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      StatusBar.styleDefault();
    });
  }

  openPage(page) {
    // close the menu when clicking a link from the menu
    this.menu.close();
    // navigate to the new page if it is not the current page
    let nav = this.app.getComponent('nav');
    nav.setRoot(page.component);
  }
}

Firstly, I needed to import some components from the ionic-angular library. The new components that I imported are:

  • IonicApp - provides some information about the app, and also keeps track of all the components within the application (as well as allowing us to select specific components)
  • Platform - provides information about the platform that the app is running on (e.g. width, height, landscape, portrait etc.), in this case we’re using it to detect when the app is ready
  • MenuController - allows us to create and manage a sliding menu

Next I changed the parameters() method to include these new services.

static get parameters() {
  return [[IonicApp], [Platform], [MenuController]];
}

This function is what injects the services into the MyApp's constructor, and the order of the services listed within this function is very important. This order directly corresponds to the order of parameters within the constructor below:

constructor(app, platform, menu) {
  //code omitted for brevity
}

This means that the app variable will be injected with IonicApp service, platform with Platform service, and menu with MenuController service. The names of the constructor parameters is not important in this context, only the order.

Next, within the @App decorator I changed the inline template to use the templateUrl pointing to the app.html file I previously created. Note that @App decorator marks the MyApp component as the root component of the entire app. You'll also notice later on that page component have the @Page decorator.

Finally, within the constructor I assigned the appropriate variables, set the rootPage which is the first page that gets shown when the app is run, and populated the pages array, which gets iterated over in the app.html template to build the buttons for our menu.

Lastly, I created the openPage(page) method which gets called from the Menu buttons to hide the menu and switch over to the selected page. Here we see a new function called getComponent, this is provided by the IonicApp service – it takes in an id and will return the component in the app with that id. In this case we are using it to grab the menu component and close it whenever a page is selected, and also to grab the nav component so that we can change the rootPage (by calling setRoot). We usually use NavController to manage navigation in the application, but this is not available in the root component, so we have to grab the nav component manually with IonicApp instead.

Adding the Menu button to Navigation Bar

You could run the code written so far and open the Menu by swiping from left to right. The menu is fully functional, however, there is no Menu icon anywhere on the screen, which is not good.

To add the menu button I added the following piece of code to all of the page templates (page1.html, page2.html, page3.html).

<button menuToggle>
   <ion-icon name="menu"></ion-icon>
</button>

Below you can see how the full HTML template for Tab 3 looks like when I added the above code to the page3.html file:

<ion-navbar *navbar>
  <button menuToggle>
    <ion-icon name="menu"></ion-icon>
  </button>
  <ion-title>
    Tab 3
  </ion-title>
</ion-navbar>

<ion-content class="page3">

</ion-content>

Conclusion

In the end it didn't took me a long time to add the similar menu I had in out-of-the-box template for Native Android to my Ionic app. The whole processes was pretty simple and straightforward, and I can already see how easy it will be to extend the menu's look and functionality. You can see the end result below.

Ionic Menu

References

I have to mention Josh Morony and his amazing blog post which helped me a lot with the implementation of this menu, and not only that, it helped me quickly understand some of the Ionic2 and Angular2 key implementation details.

Other references:

Clone this wiki locally