Saturday 22 July 2017

IONIC 3 AND ANGULAR 4 MULTI LEVEL ACCORDION MENU EXAMPLE

This is an example of a multi-level accordion menu with dynamic data using latest Ionic 3 and Angular 4.

1. Create New Ionic 3 and Angular 4 Side Menu App

We will start this tutorial by creating new Ionic 3 and Angular 4 app. This time we will use generated side menu app. Open and edit the terminal or Node.js command line then type this command.
ionic start ionic3-accordion-menu sidemenu --v2
That command will create new Ionic 3 app with the name 'ionic3-accordion-menu' using default template 'sidemenu'. Go to the newly created app folder.
cd ionic3-accordion-menu
Run the Ionic 3 app on the browser.
ionic serve -l
You should see this side menu.
Ionic 3 and Angular 4 Multi Level Accordion Menu Example - Side Menu
Right now, we will skip lazy loading pages configuration because we will focus only on the multilevel accordion menu. You can find more about lazy loading and Ionic 3 getting started here.


2. Create Nested Array of Objects

We have to create nested Array of objects which it's contains multilevel arrays. Create a new folder and JSON file in asset folder.
mkdir src/assets/data
touch src/assets/data/menus.json
Open and edit 'menus.json' then add this lines of data.
[
  {
    "category":"PC",
    "subs": [
      {
        "subcategory":"Processor",
        "manufactures": [
          {
            "manufacture":"Intel"
          },
          {
            "manufacture":"AMD"
          }
        ]
      },
      {
        "subcategory":"Motherboard",
        "manufactures": [
          {
            "manufacture":"Asus"
          },
          {
            "manufacture":"AMD"
          },
          {
            "manufacture":"GigaByte"
          },
          {
            "manufacture":"Intel"
          }
        ]
      },
      {
        "subcategory":"Memory",
        "manufactures": [
          {
            "manufacture":"Visipro"
          },
          {
            "manufacture":"Crucial"
          },
          {
            "manufacture":"VenomRX"
          }
        ]
      }
    ]
  },
  {
    "category":"Laptop",
    "subs": [
      {
        "subcategory":"Notebook",
        "manufactures": [
          {
            "manufacture":"Lenovo"
          },
          {
            "manufacture":"Dell"
          }
        ]
      },
      {
        "subcategory":"Netbook",
        "manufactures": [
          {
            "manufacture":"Lenovo"
          },
          {
            "manufacture":"Dell"
          },
          {
            "manufacture":"Acer"
          },
          {
            "manufacture":"HP"
          }
        ]
      }
    ]
  },
  {
    "category":"Printer",
    "subs": [
      {
        "subcategory":"Laserjet",
        "manufactures": [
          {
            "manufacture":"HP"
          },
          {
            "manufacture":"Brother"
          },
          {
            "manufacture":"Canon"
          },
          {
            "manufacture":"Samsung"
          }
        ]
      },
      {
        "subcategory":"Deskjet",
        "manufactures": [
          {
            "manufacture":"HP"
          },
          {
            "manufacture":"Canon"
          },
          {
            "manufacture":"Epson"
          }
        ]
      }
    ]
  }
]

3. Create and Call Service/Provider for Accessing Data
To access JSON data we have to create new service or provider to keep app modular. Type this command to create it.
ionic g provider DataService
Open and edit 'src/providers/data-service.ts' add 'Response' to 'Http' import.
import { Http, Response } from "@angular/http";
Create this function for call JSON data.
getMenus(){
  return this.http.get('assets/data/menus.json')
   .map((response:Response)=>response.json());
}
Register this service in 'app.module.ts' by open and edit 'src/app/app.module.ts' then add this import.
import { HttpModule } from '@angular/http';
import { DataService } from '../providers/data-service';
Add 'HttpModule' in '@NgModule' imports.
...
imports: [
  BrowserModule,
  IonicModule.forRoot(MyApp),
],
...
Add 'DataService' in '@NgModule' providers.
...
providers: [
  StatusBar,
  SplashScreen,
  {provide: ErrorHandler, useClass: IonicErrorHandler},
  DataService
]
...
Because menu holds by component, we have to edit it to call data for the menu from service/provider. Open and edit 'src/app/app.component.ts' then add this import.
import { DataService } from '../providers/data-service';
Replace this line.
pages: Array<{title: string, component: any}>;
With this.
pages: any;
Now, inject 'DataService' in constructor parameter and add this function for calling JSON data inside of constructor.
constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen, public dataService: DataService) {
  this.initializeApp();

  this.dataService.getMenus()
    .subscribe((response)=> {
        this.pages = response;
        console.log(this.pages);
    });

}


4. Create Multilevel Accordion Menu

Now, is the point. Creating multilevel Accordion Menu with Ionic 3 and Angular 4. Open and edit 'src/app/app.html' the add this lines of codes inside '<ion-content>'.
<ion-content>
  <ion-list>
    <ion-item *ngFor="let p of pages" text-wrap>
      {{p.category}}
      <ion-list>
        <ion-item *ngFor="let s of p.subs" text-wrap>
          {{s.subcategory}}
          <ion-list>
            <ion-item *ngFor="let m of s.manufactures" text-wrap>
              {{m.manufacture}}
            </ion-item>
          </ion-list>
        </ion-item>
      </ion-list>
    </ion-item>
  </ion-list>
</ion-content>
After we re-run the Ionic 3 app, the menu should look like this.
Ionic 3 and Angular 4 Multi Level Accordion Menu Example - Multi Level Menu
As you can see, there is 3 level of the menu. For that, we have to make accordion to hide child menus. Open and edit 'src/app/app.component.ts' then declare this variable.
showLevel1 = null;
showLevel2 = null;
Create new functions for toggle show/hide level 2 and level 3 of the menu.
toggleLevel1(idx) {
  if (this.isLevel1Shown(idx)) {
    this.showLevel1 = null;
  } else {
    this.showLevel1 = idx;
  }
};

toggleLevel2(idx) {
  if (this.isLevel2Shown(idx)) {
    this.showLevel1 = null;
    this.showLevel2 = null;
  } else {
    this.showLevel1 = idx;
    this.showLevel2 = idx;
  }
};
Also, create the function for check if level 2 and 3 is shown or hidden.
isLevel1Shown(idx) {
  return this.showLevel1 === idx;
};

isLevel2Shown(idx) {
  return this.showLevel2 === idx;
};
Now, open and edit 'src/app/app.html' then replace all list with this list.
<ion-content>
  <ion-list>
    <ion-item *ngFor="let p of pages; let i=index" text-wrap (click)="toggleLevel1('idx'+i)" [ngClass]="{active: isLevel1Shown('idx'+i)}">
      <h4>
        {{p.category}}
        <ion-icon color="success" item-right [name]="isLevel1Shown('idx'+i) ? 'arrow-dropdown' : 'arrow-dropright'"></ion-icon>
      </h4>
      <ion-list *ngIf="isLevel1Shown('idx'+i)">
        <ion-item *ngFor="let s of p.subs; let i2=index" text-wrap (click)="toggleLevel2('idx'+i+'idx'+i2)" [ngClass]="{active: isLevel2Shown('idx'+i+'idx'+i2)}">
          <h4>
            {{s.subcategory}}
            <ion-icon color="success" item-right [name]="isLevel2Shown('idx'+i+'idx'+i2) ? 'arrow-dropdown' : 'arrow-dropright'"></ion-icon>
          </h4>
          <ion-list *ngIf="isLevel2Shown('idx'+i+'idx'+i2)">
            <ion-item *ngFor="let m of s.manufactures" text-wrap>
              {{m.manufacture}}
            </ion-item>
          </ion-list>
        </ion-item>
      </ion-list>
    </ion-item>
  </ion-list>
</ion-content>
Then re-run the Ionic 3 app and see the results in the browser.
Ionic 3 and Angular 4 Multi Level Accordion Menu Example - Multi Level Accordion Menu
That it's for now, we are leaving this tutorial without action for click on each menu item. We know this isn't a best and simple way for creating multiple accordions. For that, we need suggestions and best algorithm to make this tutorial better and useful for everyone.

1 comment:

  1. please make dynamic accordian in ionic 3. i have multi level json containing childs subchilds grandchild. in future it make have more too. how can i handle

    ReplyDelete