Ionic 4 Tutorial: Angular 8 Multilevel Accordion Menu Example

by Didin J. on Sep 13, 2019 Ionic 4 Tutorial: Angular 8 Multilevel Accordion Menu Example

A comprehensive step by step Ionic 4 tutorial on building Angular 8 multilevel accordion or collapsible menu with the working example

Sometimes we have to build large mobile apps with a lot of menu and pages. In this Ionic 4 tutorial, we will show you how to handle the long list of the menu using an accordion or collapsible menu. So, the long menu can be grouped by category or subcategory and so on. There will be a nested list of menu that shows up by collapsed on it. Previously, we have to show you the same multilevel accordion or collapsible menu for Ionic 3 and Angular 4.

Table of Contents:

The following tools, frameworks, libraries, and modules are required for this tutorial:

Before going to the main steps, we assume that you have to install Node.js. Next, upgrade or install new Ionic 4 CLI by open the terminal or Node command line then type this command.

sudo npm install -g ionic

You will get the latest Ionic CLI version 5 in your terminal or command line. Check the version by type this command.

ionic -v
5.2.8

The latest version of Ionic CLI is 5 but Ionic core still 4

Right now, we are using the latest Ionic CLI version 5.2.8. Don't worry about the Angular version, we will use any version that generated with Ionic apps.


Create New Ionic Angular Side Menu App

The easier way to create Ionic Angular apps is using Ionic CLI. Just type this command to create a new Ionic Angular apps with side menu as a default template.

ionic start ionic-angular-accordion sidemenu --type=angular

Next, go to the newly created Ionic 4 project folder.

cd ./ionic-angular-accordion

Check the installed Angular and CLI version and other information by typing this command.

ionic info

Ionic:

   Ionic CLI                     : 5.2.8 (/usr/local/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.9.0
   @angular-devkit/build-angular : 0.801.3
   @angular-devkit/schematics    : 8.1.3
   @angular/cli                  : 8.1.3
   @ionic/angular-toolkit        : 2.0.0

Utility:

   cordova-res : not installed
   native-run  : 0.2.5 (update available: 0.2.8)

System:

   NodeJS : v10.15.1 (/usr/local/bin/node)
   npm    : 6.11.3
   OS     : macOS Mojave

Next, run the Ionic 4 application for the first time using this command.

ionic serve -l

If there's a question like below, just type `Y`.

Looks like @ionic/lab isn't installed in this project.

       This package is required for this command to work properly. The package provides a
       CLI utility, but the ionic-lab binary was not found in your PATH.

? Install @ionic/lab? (Y/n)

The Ionic application will open automatically in your default web browser.

Ionic 4 Angular 8 Multilevel Accordion Collapsible Menu - Ionic home


Add the Nested Arrays of Objects

This Ionic Angular accordion or collapsible menu will contain the nested arrays of menu items. So, there just a few of top menu which has its derivatives. We will put this Array data to the JSON file. Create the new folder under the assets folder and a new file inside it.

mkdir src/assets/data
touch src/assets/data/menus.json

Next, open and edit `src/assets/data/menus.json` then add these lines of JSON data.

[
    {
        "name": "top-menu-1",
        "item": [
            {
                "name": "item-1-1",
                "item": [
                    {
                        "name": "item-1-1-1",
                        "item": [
                            {
                                "name": "item-1-1-1-1",
                                "url": "/item1111"
                            },
                            {
                                "name": "item-1-1-1-2",
                                "url": "/item1112"
                            }
                        ]
                    },
                    {
                        "name": "item-1-1-2",
                        "item": [
                            {
                                "name": "item-1-1-2-1",
                                "url": "/item1121"
                            },
                            {
                                "name": "item-1-1-2-2",
                                "url": "/item1122"
                            }
                        ]
                    }
                ]
            },
            {
                "name": "item-1-2",
                "item": [
                    {
                        "name": "item-1-2-1",
                        "item": [
                            {
                                "name": "item-1-2-1-1",
                                "url": "/item1211"
                            },
                            {
                                "name": "item-1-2-1-2",
                                "url": "/item1212"
                            }
                        ]
                    },
                    {
                        "name": "item-1-2-2",
                        "item": [
                            {
                                "name": "item-1-2-2-1",
                                "url": "/item1221"
                            },
                            {
                                "name": "item-1-2-2-2",
                                "url": "/item1222"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "name": "top-menu-2",
        "item": [
            {
                "name": "item-2-1",
                "item": [
                    {
                        "name": "item-2-1-1",
                        "item": [
                            {
                                "name": "item-2-1-1-1",
                                "url": "/item2111"
                            },
                            {
                                "name": "item-2-1-1-2",
                                "url": "/item2112"
                            }
                        ]
                    },
                    {
                        "name": "item-2-1-2",
                        "item": [
                            {
                                "name": "item-2-1-2-1",
                                "url": "/item2121"
                            },
                            {
                                "name": "item-2-1-2-2",
                                "url": "/item2122"
                            }
                        ]
                    }
                ]
            },
            {
                "name": "item-2-2",
                "item": [
                    {
                        "name": "item-2-2-1",
                        "item": [
                            {
                                "name": "item-2-2-1-1",
                                "url": "/item2211"
                            },
                            {
                                "name": "item-2-2-1-2",
                                "url": "/item2212"
                            }
                        ]
                    },
                    {
                        "name": "item-2-2-2",
                        "item": [
                            {
                                "name": "item-2-2-2-1",
                                "url": "/item2221"
                            },
                            {
                                "name": "item-2-2-2-2",
                                "url": "/item2222"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

Now, we have 4 level menu based on the nested arrays of JSON objects. The bottom level of the data contains the URL to the page that navigates from the menu. For that, we must have 16 pages as the landing page from the last child of the menu items.


Create Ionic 4 Service or Provider

We will use an Ionic 4 service or provider to handle read or get JSON data. The JSON data read or get will be done by the Angular Http Client Module. The HttpClient in @angular/common/HTTP offers a simplified client HTTP API for Angular applications that rests on the XMLHttpRequest interface exposed by browsers. Additional benefits of HttpClient include testability features, typed request and response objects, request and response interception, Observable APIs, and streamlined error handling. Type this command to generate a new Ionic 4 provider.

ionic g service data

Before populating any data from the Ionic service, we have to set up the Angular HttpClient module first. Open and edit `src/app/app.module.ts` then add this import of HttpClientModule.

import { HttpClientModule } from '@angular/common/http';

Add the HttpClientModule to the @NgModule imports after the BrowserModule.

imports: [
  BrowserModule,
  HttpClientModule,
  IonicModule.forRoot(),
  AppRoutingModule
],

Next, open and edit `src/app/data.service.ts` then add this import of HttpClient.

import { HttpClient } from '@angular/common/http';

Inject that HttpClient module to the constructor.

constructor(private http: HttpClient) { }

Declare a variable that handle a connection to the JSON data.

dataUrl = 'assets/data/menus.json';

Add a function to get JSON data using HttpClient.

getData() {
  return this.http.get(this.dataUrl);
}


Create Multilevel Accordion or Collapsible Menu

As you see in the previous step that we need 16 pages to handle the last child of the menu items actions. For that, we have to create all of those pages.

ionic g page item1111
ionic g page item1112
ionic g page item1121
ionic g page item1122
ionic g page item1211
ionic g page item1212
ionic g page item1221
ionic g page item1222
ionic g page item2111
ionic g page item2112
ionic g page item2121
ionic g page item2122
ionic g page item2211
ionic g page item2212
ionic g page item2221
ionic g page item2222

That command will automatically create the route for each page. Next, we have to load the JSON data from the Angular component or main Ionic component. Open and edit `src/app/app.component.ts` then add this import of Data service.

import { DataService } from './data.service';

Inject DataService to the constructor.

constructor(
  private platform: Platform,
  private splashScreen: SplashScreen,
  private statusBar: StatusBar,
  private data: DataService
)

Replace the appPages variable with this.

public appPages: any;

Declare the new variables to handle menu level that collapsed.

showLevel1 = null;
showLevel2 = null;
showLevel3 = null;

Call DataService inside the constructor body that load JSON data for nested menu items.

this.data.getData().subscribe((resp) => {
  console.log(resp);
  this.appPages = resp;
});

Add a new function to clear all collapsed menu. This function will be used only for static Home menu.

clearLevel() {
  this.showLevel1 = null;
  this.showLevel2 = null;
  this.showLevel3 = null;
}

Add a function to expand the level 1 menu which checks the status of level 1 menu collapsed or not.

toggleLevel1(idx: string) {
  if (this.isLevel1Shown(idx)) {
    this.showLevel1 = null;
  } else {
    this.showLevel1 = idx;
  }
}

Add the above-called function to set collapsed level 1 menu status.

isLevel1Shown(idx: string) {
  return this.showLevel1 === idx;
}

Add a function to expand the level 2 menu which checks the status of the level 2 menu collapsed or not.

toggleLevel2(idx: string) {
  if (this.isLevel2Shown(idx)) {
    this.showLevel2 = null;
  } else {
    this.showLevel1 = idx;
    this.showLevel2 = idx;
  }
}

Add the above-called function to set collapsed level 2 menu status.

isLevel2Shown(idx: string) {
  return this.showLevel2 === idx;
}

Add a function to expand the level 3 menu which checks the status of level 3 menu collapsed or not.

toggleLevel3(idx: string) {
  if (this.isLevel3Shown(idx)) {
    this.showLevel3 = null;
  } else {
    this.showLevel2 = idx;
    this.showLevel3 = idx;
  }
}

Add the above-called function to set collapsed level 3 menu status.

isLevel3Shown(idx: string) {
  return this.showLevel3 === idx;
}

Next, we will implement that functions to the Ionic HTML page. Open and edit `src/app/app.component.html` then replace the <ion-content> content with this.

<ion-content>
  <ion-list lines="full">
    <ion-menu-toggle auto-hide="false" class="first-level">
      <ion-item [routerDirection]="'root'" [routerLink]="['/home']" (click)="clearLevel()">
        <ion-label><ion-icon name="home"></ion-icon>Home</ion-label>
      </ion-item>
    </ion-menu-toggle>
    <ion-item *ngFor="let p of appPages; let i=index;" [routerDirection]="'root'" (click)="toggleLevel1('idx'+i)" [ngClass]="{active: isLevel1Shown('idx'+i)}">
      <ion-label>
        <ion-icon [name]="isLevel1Shown('idx'+i) ? 'arrow-dropdown-circle' : 'arrow-dropright-circle'" slot="end"></ion-icon>
        {{p.name}}
        <ul *ngIf="isLevel1Shown('idx'+i)" class="level1">
          <li *ngFor="let i1 of p.item; let j=index;" (click)="toggleLevel2('idx'+i+'idx'+j)" [ngClass]="{active: isLevel2Shown('idx'+i+'idx'+j)}">
              <ion-icon [name]="isLevel2Shown('idx'+i+'idx'+j) ? 'arrow-dropdown-circle' : 'arrow-dropright-circle'" slot="end"></ion-icon>
            {{i1.name}}
            <ul *ngIf="isLevel2Shown('idx'+i+'idx'+j)" class="level2">
              <li *ngFor="let i2 of i1.item; let k=index;" (click)="toggleLevel3('idx'+i+'idx'+j+'idx'+k)" [ngClass]="{active: isLevel3Shown('idx'+i+'idx'+j+'idx'+k)}">
                <ion-icon [name]="isLevel3Shown('idx'+i+'idx'+j+'idx'+k) ? 'arrow-dropdown-circle' : 'arrow-dropright-circle'" slot="end"></ion-icon>
                {{i2.name}}
                <ul *ngIf="isLevel3Shown('idx'+i+'idx'+j+'idx'+k)" class="level3">
                  <li *ngFor="let i3 of i2.item; let l=index;" [routerLink]="[i3.url]">
                    <ion-menu-toggle auto-hide="false" class="first-level">{{i3.name}}</ion-menu-toggle>
                  </li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </ion-label>
    </ion-item>
  </ion-list>
</ion-content>

As you see, the level 1 menu is collapsible based on the Angular click event that calls the toggle function. The child of the level 1 menu is a list that show/hide based on `isLevel2Shown` function using the params of level 1 index. Level 2, 3 are the same using the Angular click event. For level 4 it uses Angular RouterLink to navigate to that chosen Ionic page. Finally, give a little style for the menu items by open and edit `src/app/app.component.scss` then add these lines of SCSS codes.

.level1, .level2, .level3 {
    padding: 0;
    margin: 8px 0;
    list-style: none;
    li {
        border-top: solid 1px #eee;
        padding: 8px 0 0 8px;
    }
}


Run and Test Ionic Angular Multilevel Accordion Menu

There's nothing required to run and test this Ionic Angular Multilevel Accordion or collapsible menu. Just run in the browser as an Ionic lab then it should be the same as running in the Android or iOS devices. Type this command again to run this app.

ionic serve -l

Here's the Ionic 4 Angular 8 Multilevel Accordion or collapsible menu look like.

That it's the complete Ionic 4 Angular 8 Multilevel Accordion or collapsible menu example. You can find the working source code from our GitHub.

We know that building beautifully designed Ionic apps from scratch can be frustrating and very time-consuming. Check Ionic 4 - Full Starter App and save development and design time. Android, iOS, and PWA, 100+ Screens and Components, the most complete and advance Ionic Template.

That just the basic. If you need more deep learning about Ionic, Angular, and Typescript, you can take the following cheap course:

Thanks!

Loading…