Home > Software engineering >  Select Menu Open/Close
Select Menu Open/Close

Time:10-24

In the sidebar, I have two rubrics Category and Markets.

enter image description here

When I click on Category, the items display correctly.

enter image description here

My problem is that if I click on another rubric, for example, if I click on Markets. The Category rubric does not close automatically.

enter image description here

I created a method below... I do not know if it is correct?

selectMenu(parentMenu: { link_name: string }) : void {
    this.menuSidebar.forEach(menu => {
        if (menu.link_name !== parentMenu.link_name) {
            menu.active = false;
        } else {
            menu.active = !menu.active;
            }
        })
}

HTML

I'm not sure where I should call my method in the html?

<div  [class.sidebar-close]="!openSidebar" >
    <div >
        <img src="https://zupimages.net/up/22/42/refj.png" /> 
    </div>
    <ul  id="nav-links" >
      <li *ngFor="let item of menuSidebar" #itemEl >
        <div *ngIf="item.sub_menu.length > 0"  (click)="showSubmenu(itemEl)">
          <a (click)="selectMenu(item)">
            <i [class]="item.icon"></i>
            <span >{{item.link_name}}</span>
          </a>
          <i class='bx bxs-chevron-down arrow'></i>
        </div>
        <ul  [class.blank]="item.sub_menu.length == 0">
          <li><a >{{item.link_name}}</a></li>
          <li *ngFor="let item_sub of item.sub_menu" routerLinkActive="active">
            <a [routerLink]="[item_sub.link]">{{item_sub.link_name}}</a>
          </li>
        </ul>
      </li>
    </ul>
  </div>

dashboard.component.ts

import { Component, OnInit } from '@angular/core';
import { MenuSidebar } from './types/menuSidebar';


@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {

    openSidebar: boolean = true;

    menuSidebar: MenuSidebar[] = [
       {
        link_name: 'Category',
        link: null,
        icon: 'bx bx-collection',
        active: false,
        sub_menu: [
          {
            link_name: 'Portfolio',
            link: '/category/portfolio',
          }, 
          {
            link_name: 'Contact',
            link: '/category/contact',
          }, 
        ]
      },
      {
        link_name: 'Markets',
        link: null,
        icon: 'bx bx-collection',
        active: false,
        sub_menu: [
          {
            link_name: 'Indice',
            link: '/markets/indice',
          }, 
        ]
      },
    ]
  
    constructor() { }
  
    ngOnInit() {
  
    }
  
    showSubmenu(itemEl: HTMLElement) {
      itemEl.classList.toggle('showMenu');
    }

    selectMenu(parentMenu: { link_name: string }) : void {

      this.menuSidebar.forEach(menu => {
      if (menu.link_name !== parentMenu.link_name) {
      menu.active = false;
      } else {
      menu.active = !menu.active;
      }
      })
      
    }
    
  }

Here is a reproduction also via Stackblitz.

Thank you very much for your help.

CodePudding user response:

If you always have one expanded menu item, then it is easier to use a variable to store the active item and bind the expand class to that variable like this:

activeItem;

  toggleShowSubmenu(item: any) {
    if (item.link_name == this.activeItem) {
      this.activeItem = undefined;
    } else {
      this.activeItem = item.link_name;
    }
  }

In your template

<li *ngFor="let item of menuSidebar" [class.showMenu]="activeItem == item.link_name" #itemEl>

And then you pass the item object instead of the html element reference

(click)="toggleShowSubmenu(item)"

Here is a fork of your example with my suggested solution

  • Related