3

I am trying to create a menu system in Angular that supports menus and submenus on both the left and right side, and looks good in mobile. I've been able to get the furthest with ngx-bootstrap, I've tried a few other libraries with little success.

The issue with the code I have is that when in mobile view, it's only partially working, the initial menus looks decent, but clicking on the menu is still creating a popup. If I take out some of the container="body" params it works ok in mobile, but not in desktop.

https://stackblitz.com/edit/angular-hmmqx1

menu.component.html

<nav class="navbar navbar-expand-sm">
<button class="navbar-toggler navbar-toggler-right nav-link" (click)="isCollapsed = !isCollapsed" aria-expanded="false" aria-label="Toggle navigation">
    <i class="fas fa-bars">Menu</i>
</button>
<div class="navbar-collapse collapse" container="body" [collapse]="isCollapsed" id="navbarNavDropdown">
    <ul class="navbar-nav col-md-12">
        <li *ngFor="let menu of leftItems" class="nav-item">
            <div *ngIf="!menu.items" container="body">
                <a *ngIf="!menu.items" class="nav-link" href="#">
                    <i *ngIf="menu.icon" class="{{ menu.icon }}"></i>{{ menu.label }}
                </a>
            </div>
            <div *ngIf="menu.items" class="navbar-collapse collapse" dropdown container="body" [collapse]="isCollapsed">
                <a class="nav-link dropdown-toggle" dropdownToggle (click)="false" href="#">
                    <i class="{{ menu.icon }}"></i>{{ menu.label }}
                </a>
                <ul *dropdownMenu class="dropdown-menu">
                    <ng-container  *ngFor="let item of menu.items">
                        <li *ngIf="!item.items" role="menuitem">
                            <a class="dropdown-item">
                                <i *ngIf="item.icon" class="{{ item.icon }}"></i>{{item.label}}
                            </a>
                        </li>
                        <li *ngIf="item.items" role="menuitem" dropdown triggers="mouseover" placement="top right" container="body">
                            <a class="dropdown-item" (click)="false">{{ item.label }}<i class="fas fa-caret-right dropdown-submenu"></i></a>
                            <ul *dropdownMenu class="dropdown-menu" role="menu">
                                <ng-container  *ngFor="let submenu of item.items">
                                    <li role="menuitem">
                                        <a class="dropdown-item" href="#">
                                            <i *ngIf="submenu.icon" class="{{ submenu.icon }}"></i>{{ submenu.label }}
                                        </a>
                                    </li>
                                    <li *ngIf="submenu.divider" class="divider dropdown-divider"></li>
                                </ng-container>
                            </ul>
                        </li>
                        <li *ngIf="item.divider" class="divider dropdown-divider"></li>
                    </ng-container>
                </ul>
            </div>
        </li>
        <li class="nav-item ml-auto"></li>
        <li *ngFor="let menu of rightItems" class="nav-item">
            <div *ngIf="!menu.items" container="body">
                <a *ngIf="!menu.items" class="nav-link" href="#">
                    <i *ngIf="menu.icon" class="{{ menu.icon }}"></i>{{ menu.label }}
                </a>
            </div>
            <div *ngIf="menu.items" dropdown container="body" placement="bottom right">
                <a class="nav-link dropdown-toggle" dropdownToggle (click)="false" href="#"><i class="{{ menu.icon }}"></i>{{ menu.label }}</a>
                <ul *dropdownMenu class="dropdown-menu dropdown-menu-right">
                    <ng-container  *ngFor="let item of menu.items">
                        <li *ngIf="!item.items" role="menuitem">
                            <a class="dropdown-item">
                                <i *ngIf="item.icon" class="{{ item.icon }}"></i>{{item.label}}
                            </a>
                        </li>
                        <li *ngIf="item.items" role="menuitem" dropdown triggers="mouseover" placement="top left" container="body">
                            <a class="dropdown-item" (click)="false"><i class="fas fa-caret-left dropdown-submenu-left"></i>{{ item.label }}</a>
                            <ul *dropdownMenu class="dropdown-menu dropdown-menu-right" role="menu">
                                <ng-container  *ngFor="let submenu of item.items">
                                    <li role="menuitem">
                                        <a class="dropdown-item" href="#">
                                            <i *ngIf="submenu.icon" class="{{ submenu.icon }}"></i>{{ submenu.label }}
                                        </a>
                                    </li>
                                    <li *ngIf="submenu.divider" class="divider dropdown-divider"></li>
                                </ng-container>
                            </ul>
                        </li>
                        <li *ngIf="item.divider" class="divider dropdown-divider"></li>
                    </ng-container>
                </ul>
            </div>
        </li>
    </ul>
</div>

menu.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-menu',
    templateUrl: './menu.component.html',
    styleUrls: ['./menu.component.scss'],
})
/**
 * Main Menu
 */

export class MenuComponent implements OnInit {
    leftItems: any[];
    rightItems: any[];
    isCollapsed = true;

    ngOnInit(): void {

        this.leftItems = [
        {
            label: 'Single Item',
            routerLink: '/single'
        },
        {
            label: 'Left Menu',
            icon: 'fas fa-puzzle-piece',
            items: [
                {label: 'Something', routerLink: '/something'
                },
                {label: 'Templates', routerLink: '/templates', divider: true},
                {label: 'Proposals', routerLink: '/props'},
                {label: 'Other Things', routerLink: '/other', divider: true},
                {label: 'Submneu', items: this.getDynamicMenu() },               
                {label: 'New Stuff', routerLink: '/new', icon: 'fas fa-plus'},                                                                                                          
                ]
            },
        ];

        this.rightItems = [
            {
                label: 'Help', icon: 'fas fa-life-ring',
                items: [
                    {label: 'Help Docs', items: [{label: 'Submenu Test'}]}
                ]
            }, {
                label: 'User', icon: 'fas fa-user',
                items: [
                    {label: 'Logout'}
                ]
            },]
    }

    getDynamicMenu() {
        const testNames = ['Test1', 'Test2', 'Test3'];
        const dynamicSubmenu = [];
        for(const menuName of testNames) {
            dynamicSubmenu.push({label: 'Submenu - ' + menuName, routerLink: '/submenus/' + menuName.toLowerCase()});
        }
        return dynamicSubmenu
    }
}
rtaft
  • 2,139
  • 1
  • 16
  • 32
  • I have just tried it in Chrome, with mobile and desktop view and they seemed perfectly fine. Can you please elaborate on the specific problem you encountering, maybe with screenshots, and specific platform descriptions? – ForestG Apr 29 '19 at 07:53
  • When in the mobile view, clicking a menu item shows a popup. The 'Help' one shows on the right side and looks funny. I would rather they expand vertically than be a popup menu when in mobile. – rtaft Apr 29 '19 at 11:47

1 Answers1

0

you have to change the placement direction of menu,you are not changing the placement direction on mobile view that why its show help on right side, try this when mobile placement="bottom" and on big screen this is fine placement="bottom right" its took time to figure out, for screen size you can view this thread Detect window size using Angular 4

this media query comes into play when screen size is small

@media (min-width: 576px)
{
}
Shahid Islam
  • 559
  • 3
  • 7