Search code examples
angularmenuionic5

Add ionic-menu in distinct component


I'm updating an existing ionic/angular app and would like to have as little impact on the code as possible. My goal is to add a burger menu, as exists in a ton of other applications. My difficulty comes from the project architecture.

The header is created in a distinct component, nav-bar. It manages different states and context. Each page, modal, etc... sets up his own ion-header tag, but then its content (and mainly the ion-toolbar) is managed in the dedicated navbar component.

Here is a lightened working version of the code :

app.component.html

<ion-app>
    <ion-menu content-id="main-content">
        <ion-header>
            <ion-toolbar>
                <ion-title>Menu Content</ion-title>
            </ion-toolbar>
        </ion-header>
        <ion-content class="ion-padding">This is the menu content.</ion-content>
    </ion-menu>

    <ion-router-outlet *ngIf="isLoggedIn" id="main-content"></ion-router-outlet>
</ion-app>

about.page.html

<ion-header>
    <nav-bar [title]="'title.about'"></nav-bar>
</ion-header>

<ion-content padding>
    <!-- custom page content -->
</ion-content>

navbar.html

<ion-toolbar>
    <ion-buttons slot="start">
        <ion-button *ngIf="!isModal" (click)="goToPrevious()">
            <ion-icon name="chevron-back"></ion-icon>
        </ion-button>
        <ion-menu-button></ion-menu-button>
    </ion-buttons>

    <ion-title class="title-wrapper" slot="primary">{{ title }}</ion-title>
</ion-toolbar>

The navbar works (as in the title is displayed correctly as the back-button), except the burger button: it is not showing on a the page. In the developer console, I can see the element being added to the page, but not visually. It "magically" appears if I add a "display: block" on it, which clearly doesn't feel right.

What did I miss, why is the button not showing by itself?


Solution

  • The solution was heavily inspired from a post by Alon Laniado Bundayy Olayinka on this thread

    • First of all, I disregarded using a ion-menu, I finally preferred to make my own.
    • Secondly, the balise had to be moved alongside the rest in my new component. There was no logic to have the balise on each page, then the content outside
    • Finally, it was easier, cleaner and sturdier to make this new component in a module to facilitate the injection anywhere else.

    Here are my different files for anyone stumbling upon here.

    app/modules/shared/shared.module.ts

        import { CommonModule } from '@angular/common';
        import { NgModule } from '@angular/core';
        import { IonicModule } from "@ionic/angular";
        
        import { NavBar } from "./nav/nav";
        
        @NgModule({
            declarations: [NavBar],
            imports: [
                CommonModule,
                IonicModule,
            ],
            exports: [NavBar],
        })
        export class SharedModule { }
    

    app/modules/shared/navbar/nav.ts

        import { Location } from '@angular/common';
        import { Component, Input, OnInit } from '@angular/core';
        import { NavController } from '@ionic/angular';
        
        @Component({
            selector: 'navbar',
            templateUrl: 'navbar.html',
            styleUrls: ['nav.scss'],
        })
        export class NavBar implements OnInit {
            @Input() public title = '';
        
            constructor(
                public location: Location,
                public navCtrl: NavController
            ) { }
        }
    

    app/modules/shared/nav/nav.html

    <header>
        <nav>
            <div class="navbar__container">
                <div class="navbar__left">
                    <!-- Navigation button -->
                    <button aria-label="navigation-button">
                        <img src="assets/imgs/menu/menu-back.svg">
                    </button>
                    <!-- Burger menu -->
                    <button aria-label="menu-button">
                      <img [src]="toggleBurgerMenu? 'assets/imgs/menu/burger-close.svg' : 'assets/imgs/menu/burger-open.svg'">
                    </button>
                </div>
                <div class="navbar__right">
                    <!-- Page title-->
                    <span class="text text__size--regular text--primary">{{ title }}</span>
                </div>
            </div>
        </nav>
    </header>
    

    Then, this SharedModule is added in the imports array of the app.module.ts, and added as such on the specific component supposed to use it:

    <navbar [title]="custom-title"></navbar>
    

    Note that this import and usage is to be duplicated for each subsequent module or page.