Jeet Raythatha
Jeet Raythatha

Reputation: 11

Why do sidebar dropdown menus close when clicking on another dropdown after selecting one initially? angular material menulist drop down issue

Side-nav.component.html

<mat-sidenav-container class="sidenav-container">
  <mat-sidenav
    #drawer
    [ngClass]="sidenavToggle ? 'sidenav' : 'sidenavToggle'"
    fixedInViewport
    mode="side"
    [opened]="true"
    disableClose="true"
  >
    <mat-toolbar class="app-logo secondaryblue">
      <div class="app-header__logo">
        <div class="app-logo__wrapper">
          <img
            src="assets/images/Rishabh-Software-logo.png"
            alt=""
            class="desktop-logo sidenavToggle-logo"
          />
          <img
            src="assets/images/r-logo.svg"
            alt=""
            class="desktop-logo sidenav-logo"
          />
          <img
            src="assets/images/Rishabh-Software-logo.png"
            alt=""
            class="mobile-logo"
          />
        </div>
      </div>
    </mat-toolbar>
    <mat-nav-list>
      <ng-container *ngFor="let item of sidebarItems">
        <!-- <ng-template [ngIf]="shouldDisplayMenuItem(item)"> -->
        <ng-template
          [ngIf]="item.role.includes(this.role) && item?.viewPermission"
        >
          <app-menu-list-item
            [sidenavToggle]="sidenavToggle"
            [item]="item"
          ></app-menu-list-item>
        </ng-template>
      </ng-container>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content
    class="app-content_wrapper"
    [ngClass]="sidenavToggle ? 'marginChange' : ''"
  >
    <mat-toolbar class="app-header" color="primary">
      <button
        mat-icon-button
        class="menu-icon"
        aria-label="Example icon-button with menu icon"
        (click)="toggleSidenav()"
      >
        <mat-icon>menu</mat-icon>
      </button>

      <app-header-title
        [title]="breadcumbsTitle"
        home="Home"
        [subTitle]="breadcumbsSubTitle"
      ></app-header-title>

      <button mat-button class="display-name" disabled="true">
       {{ fullName }}  <span><img class="me-2" src="assets/images/user.svg" alt="" />
       </span> <span style="color: rgb(192, 189, 189);">|</span>
      </button>
      <button
        mat-raised-button
        color="primary"
        role="listitem"
        (click)="signOut()"
        class="app-nav__item"
      >
        <mat-icon class="logout-icon">power_settings_new</mat-icon>Logout
      </button>
    </mat-toolbar>

    <div class="container-fluid">
      <div class="row">
        <div class="col-12 mt-5 mb-5 pb-3 pt-5">
          <router-outlet></router-outlet>
        </div>
      </div>
    </div>

    <app-footer></app-footer>
  </mat-sidenav-content>
</mat-sidenav-container>

side-nav.component.ts


@Component({
  selector: 'app-side-nav',
  templateUrl: './side-nav.component.html',
  styleUrls: ['./side-nav.component.scss'],
})
export class SideNavComponent implements OnInit {
  sidenavToggle = false;
  sidebarItems: any = [];
  loggedInUserData: any;
  sub!: Subscription;
  role: any;
  @Input() title: string | undefined = undefined;
  @Input() home: string | undefined = undefined;

  breadcumbsSubTitle = '';
  private breakpointObserver = inject(BreakpointObserver);
  fullName!: string;
  testSideNav!: string;
  sideNavTestArray: any = [];
  componentName: any;
  constructor(private router: Router, private loginService: LoginService, private activatedRoute: ActivatedRoute,
    private common: CommonService) {
    this.router.events.pipe(
      filter(event => event instanceof ActivationEnd),
      map(event => (<ActivationEnd>event).snapshot),
      map(snapshot => (<ActivatedRouteSnapshot>snapshot).data)).subscribe(data => {
        if (data && data['breadcumbs']) {
          this.breadcumbsTitle = data['breadcumbs'].title;
          this.breadcumbsSubTitle = data['breadcumbs'].subTitle;
        }
      });
  }
  ngOnInit(): void {
    this.role = localStorage.getItem('Role');

    let userDataId = JSON.parse(localStorage.getItem('userData')!).id;
    this.componentName = localStorage.getItem('componentName');
    let userPermissions = JSON.parse(localStorage.getItem('Permissions')!);
    if (userDataId && userPermissions == undefined) {
      this.getUserPermissions(userDataId);
    }
    else {
      this.loadMenuItems(SidePanel_Item);
    }
    this.fullName = JSON.parse(localStorage.getItem('userData')!)?.firstName;
    const userData: any = localStorage.getItem('Role');
    this.loggedInUserData = userData;
  }

  getUserPermissions(id: any) {

    this.common.getPermissionsOfUser(id).subscribe((res: any) => {
      localStorage.setItem('Permissions', JSON.stringify(res.items));

      this.sub = this.loginService.roleOBS.subscribe((x) => {
        this.role = localStorage.getItem('Role');
        this.sidebarItems = [];
        this.loadMenuItems(SidePanel_Item);
      });
    })
  }

  loadMenuItems(menuItems: any[]) {

    menuItems.forEach((obj: { children: any[]; role: any[]; title: string; viewPermission?: boolean }) => {
      if (
        obj.role &&
        obj.children &&
        obj.children.length === 0 &&
        obj.role.length > 0 &&
        obj.role.some((item: any) => item === this.role) &&
        (obj.viewPermission || (obj.viewPermission && this.hasViewPermission(obj.title))
        )
      ) {
        this.sidebarItems.push(obj);
      }
      if (obj.children && obj.children.length > 0 && (obj.title == this.componentName || obj.title == 'Settings' || obj.title == 'Important Links')) {
        obj.viewPermission = this.hasViewPermission(obj.title)

        obj.children = this.filterMenuItems(obj.children);
        if (obj.children.length > 0) {
          this.sidebarItems.push(obj);
        }
      }

    });
  }

  filterMenuItems(children: any[]): any[] {

    return children.filter((child: any) => {
      if (!child.viewPermission) {
        child.viewPermission = this.hasViewPermission(child.title);
      }

      if (
        (child.role &&
          Array.isArray(child.role) &&
          child.role.some((item: any) => item === this.role) &&
          child.viewPermission)
      ) {
        if (child.children && child.children.length > 0) {

          child.children = this.filterMenuItems(child.children);
        }
        return true;
      }
      child.viewPermission = false;
      return false;
    });
  }

  isHandset$: Observable<boolean> = this.breakpointObserver
    .observe(Breakpoints.Handset)
    .pipe(
      map((result) => result.matches),
      shareReplay()
    );

  toggleSidenav() {
    this.sidenavToggle = !this.sidenavToggle;
  }

  public signOut(): void {
    this.loginService.logOut();
    this.loadMenuItems([]);
    this.filterMenuItems([]);
    this.loggedInUserData = '';
    this.sidebarItems = [];
    this.loginService.currentUserSubject.next(null);
    localStorage.removeItem('Permissions');
    setTimeout(() => {
      window.location.reload();
    }, 1000);
  }

  hasViewPermission(title: any) {

    let permissions = JSON.parse(localStorage.getItem('Permissions')!);
    if (!permissions) {
      return false; // or handle as needed
    }
    let permission = permissions.find((p: { subProjectName: string; }) => p.subProjectName === title);
    if (!permission) {
      return false; // or handle as needed
    }
    return permission?.viewPermission ? permission?.viewPermission : false;

  };

}

menu-list-item.html

<ng-template [ngIf]="item?.viewPermission" >
<mat-list-item
  (click)="onItemSelected(item)"
  [ngStyle]="{ 'padding-left': !sidenavToggle ? depth * 12 + 'px' : '' }"
  [ngClass]="{
    active: item.routeLink ? isRouteActive(item.routeLink) : false,
    expanded: expanded
  }"
  class="app-menu__item"
>
  <mat-icon class="routeIcon">{{ item.icon }}</mat-icon>
  <span *ngIf="!sidenavToggle" class="app-menu__label">
  
    {{ item.title }}</span>
  <span
    class="treeview-indicator"
    fxFlex
    *ngIf="item.children && item.children.length"
  >
    <span fxFlex></span>
    <mat-icon
      *ngIf="!sidenavToggle"
      class="align-middle"
      [@indicatorRotate]="expanded ? 'expanded' : 'collapsed'"
    >
      expand_more
    </mat-icon>
  </span>
</mat-list-item>
</ng-template>
<div *ngIf="expanded">
  <app-menu-list-item
    *ngFor="let child of item.children"
    [item]="child"
    [depth]="depth + 1"
  >
  </app-menu-list-item>
</div>

menu-list-item.ts

import { Component, HostBinding, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import {
  animate,
  state,
  style,
  transition,
  trigger,
} from '@angular/animations';
import { NavService } from '../../service/nav.service';
import { SidePanel_Item } from '../../model/side-panel.model';
import { SideNavComponent } from '../side-nav/side-nav.component';
@Component({
  selector: 'app-menu-list-item',
  templateUrl: './menu-list-item.component.html',
  styleUrls: ['./menu-list-item.component.scss'],
  animations: [
    trigger('indicatorRotate', [
      state('collapsed', style({ transform: 'rotate(0deg)' })),
      state('expanded', style({ transform: 'rotate(180deg)' })),
      transition(
        'expanded <=> collapsed',
        animate('225ms cubic-bezier(0.4,0.0,0.2,1)')
      ),
    ]),
  ],
})
export class MenuListItemComponent implements OnInit {
  expanded!: boolean;
  @HostBinding('attr.aria-expanded') ariaExpanded = this.expanded;
  @Input() item: any;
  @Input() depth!: number;
  @Input() sidenavToggle: any;

  constructor(public navService: NavService, public router: Router) {
    if (this.depth === undefined) {
      this.depth = 0;
    }
  }

  ngOnInit() {
    SidePanel_Item;
    this.navService.currentUrl.subscribe((url: string) => {
      if (this.item.route && url) {
        this.expanded = url.indexOf(`/${this.item.route}`) === 0;
        this.ariaExpanded = this.expanded;
      }
    });
  }

  onItemSelected(item: any) {
    if (!item.children || !item.children.length) {
      this.router.navigate([item.routeLink]);
      this.navService?.closeNav();
    }
    if (item.children && item.children.length) {
      this.expanded = !this.expanded;
    }
  }

  isRouteActive(route: string): boolean {
    const currentRouteWithoutQueryParams = this.router.url.split('?')[0];
    return currentRouteWithoutQueryParams === route;
  }
}

The issue occurs is described as follows:

Drop Down 1 item-1 item-2 item-3

Drop Down 2 item-1 item-2 Drop down 3 item-1 item-2

first when I click on the drop down 1 it expands and then I click on the any item from the drop down 1 the page of that item opens successfully the I click on the drop down 2 it expands and then when I click on any item of another drop down all the dropdown gets collapsed.

the expected result should be the drop drop should only collapsed when clicked on the dropdown and should not get collapsed after clicking on the item from other drop down.

Upvotes: 0

Views: 58

Answers (0)

Related Questions