src/app/core/ui/navigation/menu-item/menu-item.component.ts

Metadata

Relationships

Depends on

Index

Properties
Methods
Inputs

Inputs

activeLink
Type : string

The menu item link that is currently displayed in the app in order to highlight the active menu.

item
Type : MenuItem
Required :  true

The menu item to be displayed.

Methods

hasSubMenu
hasSubMenu(item: MenuItem)
Parameters :
Name Type Optional
item MenuItem No
Returns : boolean
toggleSubMenu
toggleSubMenu()
Returns : void

Properties

isExpanded
Type : boolean
Default value : false
linkPath
Type : unknown
Default value : computed(() => this.item().link?.split("?")[0])

The path portion of item.link, without query parameters. e.g. "/user?type=X" → "/user"

linkQueryParams
Type : unknown
Default value : computed((): Record<string, string> | undefined => { const qs = this.item().link?.split("?")[1]; if (!qs) return undefined; const params: Record<string, string> = {}; new URLSearchParams(qs).forEach((value, key) => (params[key] = value)); return params; })

The query parameters parsed from item.link, if any. e.g. "/user?type=X" → { type: "X" }

import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
} from "@angular/core";
import { MatListModule } from "@angular/material/list";
import { FaIconComponent } from "@fortawesome/angular-fontawesome";
import { FaDynamicIconComponent } from "../../../common-components/fa-dynamic-icon/fa-dynamic-icon.component";
import { RouterLink } from "@angular/router";
import { Angulartics2Module } from "angulartics2";
import { MenuItem } from "../menu-item";
import { MatMenuModule } from "@angular/material/menu";

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-menu-item",
  templateUrl: "./menu-item.component.html",
  styleUrls: ["./menu-item.component.scss"],
  imports: [
    MatListModule,
    FaIconComponent,
    FaDynamicIconComponent,
    RouterLink,
    Angulartics2Module,
    MatMenuModule,
  ],
  standalone: true,
})
export class MenuItemComponent {
  /**
   * The menu item to be displayed.
   */
  item = input.required<MenuItem>();

  /**
   * The menu item link that is currently displayed in the app
   * in order to highlight the active menu.
   */
  activeLink = input<string>();

  /**
   * The path portion of item.link, without query parameters.
   * e.g. "/user?type=X" → "/user"
   */
  linkPath = computed(() => this.item().link?.split("?")[0]);

  /**
   * The query parameters parsed from item.link, if any.
   * e.g. "/user?type=X" → { type: "X" }
   */
  linkQueryParams = computed((): Record<string, string> | undefined => {
    const qs = this.item().link?.split("?")[1];
    if (!qs) return undefined;
    const params: Record<string, string> = {};
    new URLSearchParams(qs).forEach((value, key) => (params[key] = value));
    return params;
  });

  isExpanded: boolean = false;

  toggleSubMenu(): void {
    this.isExpanded = !this.isExpanded;
  }

  hasSubMenu(item: MenuItem): boolean {
    return !!item.subMenu && item.subMenu.length > 0;
  }
}
<mat-list-item
  angulartics2On="click"
  angularticsCategory="Navigation"
  angularticsAction="app_navigation_link_click"
  [angularticsLabel]="item().label"
  [routerLink]="item().link ? linkPath() : undefined"
  [queryParams]="linkQueryParams()"
  class="indent-item"
  [class.matched-background]="item().link === activeLink()"
  (click)="toggleSubMenu()"
>
  <a class="flex-row gap-small">
    <app-fa-dynamic-icon
      class="nav-icon"
      [icon]="item().icon"
    ></app-fa-dynamic-icon>
    <div class="menu-label" [title]="item().label">{{ item().label }}</div>

    @if (hasSubMenu(item())) {
      <fa-icon [icon]="isExpanded ? 'chevron-down' : 'chevron-right'"></fa-icon>
    }
  </a>
</mat-list-item>

<!-- Render submenus if they exist and are expanded -->
@if (isExpanded) {
  <div class="submenu">
    @for (subItem of item().subMenu; track subItem.label) {
      <!-- Pass activeLink to each submenu item to highlight the active submenu -->
      <app-menu-item
        [item]="subItem"
        [activeLink]="activeLink()"
      ></app-menu-item>
    }
  </div>
}

./menu-item.component.scss

@use "../../../../../styles/variables/sizes";
@use "../../../../../styles/variables/colors";

/* ensures that all icons have the same width */
.nav-icon {
  min-width: sizes.$max-icon-width;
}

.matched-background {
  background-color: colors.$background !important;
}

.submenu {
  padding-left: 20px;
}

.indent-item {
  margin-left: 8px;
  padding-left: 8px;
  width: auto;
  border-end-end-radius: 0;
  border-start-end-radius: 0;
}

.menu-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  min-width: 0;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""