我想根据某些配置创建一个导航列表。 就像一个数组
export interface LeftNavModel {
name: string,
route: string,
iconName?: string,
data?: any }
所以导航数据看起来像这样
[
{
name: "First Route",
route:"first",
sectionName: "First Section",
iconName: "home",
children: [
{
name: "First Child Route",
route:`first/firstChild`,
iconName: "folder"
children: [
{
name: "First Sub Child Route",
route:"first/firstChild/firstSubChild",
iconName: "image"
}
]
}
]
}
]
并在组件中使用配置 JSON 中的路由创建 routerLink。 我能够创建相同的并且工作正常。问题是我想共享导航 URL,以便其他用户可以打开动态创建导航的同一页面。
页面刷新可以通过将配置保留为路由器中的状态来处理。或者使用任何存储机制,例如 localStorage。但是我们如何共享链接和配置数据。 将配置作为 queryParam 传递将创建巨大的 url。还有其他选择吗?
我必须在我不久前正在进行的一个项目中执行此操作。
我在侧边栏使用引导手风琴,因此需要为每个菜单项提供一个 id。你可以用任何东西完成同样的事情,尽管不一定是引导程序。
创建一个类来表示菜单/导航项(我的是这样的)
export class MenuItem {
id: number;
text: string;
icon: string;
url?: string;
children?: MenuItem[];
}
创建一个菜单项数组,用于存储项目列表。这是我的简化版本:
export const menuItems = [
{
id: 1,
text: 'Dashboard',
icon: 'dashboard',
url: 'dashboard',
},
{
id: 2,
text: 'Organizational Documents',
icon: 'library_books',
children: [
{
id: 3,
text: 'View',
icon: 'search',
url: 'organizational-documents/view',
},
],
},
{
id: 4,
text: 'Qualifications',
icon: 'school',
children: [
{
id: 5,
text: 'Create',
icon: 'create',
url: 'qualifications/create',
},
{
id: 6,
text: 'View',
icon: 'search',
url: 'qualifications/view',
},
],
},
{
id: 7,
text: 'Programmes',
icon: 'library_books',
children: [
{
id: 8,
text: 'Create',
icon: 'create',
children: [
{
id: 9,
text: 'Learnership',
icon: 'add',
url: 'programmes/create/learnership',
},
{
id: 10,
text: 'Internship',
icon: 'add',
url: 'programmes/create/internship',
},
],
},
{
id: 11,
text: 'View',
icon: 'search',
children: [
{
id: 12,
text: 'Learnerships',
icon: 'search',
url: 'programmes/view/learnerships',
},
{
id: 13,
text: 'Internships',
icon: 'search',
url: 'programmes/view/internships',
},
],
},
]
从包含导航项的组件初始化菜单项
import { menuItems } from '../menuItems';
public ngOnInit() {
this.renderMenu();
}
private renderMenu(): void {
this.renderedMenuItems = JSON.parse(JSON.stringify(menuItems));
}
添加类似于下面的 HTML 以便迭代菜单项
<nav id="sidebar" class="sidebar-open overflow-auto shadow">
<div class="accordion accordion-flush mb-2" id="sidebarAccordion">
<div *ngFor="let item of renderedMenuItems">
<div *ngIf="!item.children">
<a
id="flush-{{ item.id }}"
class="
fs-6
d-flex
align-items-center
p-2
pt-3
pb-3
cursor-pointer
non-dropdown
"
routerLink="{{ item.url }}"
routerLinkActive="active-route-dash"
>
<mat-icon class="ms-1 me-3">{{ item.icon }}</mat-icon>
{{ item.text }}
</a>
</div>
<div *ngIf="item.children" class="accordion-item">
<h2 class="accordion-header m-0" id="flush-{{ item.id }}">
<div
id="menu-button-{{ item.id }}"
class="accordion-button collapsed cursor-pointer p-2"
data-bs-toggle="collapse"
attr.data-bs-target="#flush-collapse-{{ item.id }}"
aria-expanded="false"
attr.aria-controls="flush-collapse-{{ item.id }}"
>
<mat-icon class="ms-1 me-3">{{ item.icon }}</mat-icon>
{{ item.text }}
</div>
</h2>
<div
id="flush-collapse-{{ item.id }}"
class="accordion-collapse collapse"
attr.aria-labelledby="flush-{{ item.id }}"
data-bs-parent="#sidebarAccordion"
>
<ul class="list-unstyled mb-0">
<li *ngFor="let child of item.children">
<div
*ngIf="child.children"
class="accordion accordion-flush"
id="accordion-{{ child.id }}"
>
<div class="accordion-item">
<h2 class="accordion-header m-0" id="flush-{{ child.id }}">
<div
id="menu-button-{{ child.id }}"
class="accordion-button collapsed cursor-pointer p-2"
data-bs-toggle="collapse"
attr.data-bs-target="#flush-collapse-{{ child.id }}"
aria-expanded="false"
attr.aria-controls="flush-collapse-{{ child.id }}"
>
<div class="ps-2 fw-normal d-flex align-items-center">
<mat-icon class="ms-1 me-3">{{
child.icon
}}</mat-icon>
{{ child.text }}
</div>
</div>
</h2>
<div
id="flush-collapse-{{ child.id }}"
class="accordion-collapse collapse"
attr.aria-labelledby="flush-{{ child.id }}"
attr.data-bs-parent="#accordion-{{ child.id }}"
>
<ul class="list-unstyled mb-0">
<li *ngFor="let subChild of child.children">
<a
class="
cursor-pointer
nav-item
ps-4
d-flex
align-items-center
non-dropdown
"
routerLink="{{ subChild.url }}"
routerLinkActive="active-route-3rd"
>
<mat-icon class="ms-1 me-3">{{
subChild.icon
}}</mat-icon>
{{ subChild.text }}
</a>
</li>
</ul>
</div>
</div>
</div>
<div *ngIf="!child.children">
<a
class="
cursor-pointer
nav-item
ps-3
d-flex
align-items-center
non-dropdown
"
routerLink="{{ child.url }}"
routerLinkActive="active-route-2nd"
>
<mat-icon class="ms-1 me-3">{{ child.icon }}</mat-icon>
{{ child.text }}
</a>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</nav>
使用上面的代码,我最终得到以下结果(显然在样式之后)
我已经针对此问题实施了解决方案,因为没有其他可用答案。我现在将分享我为满足要求而实施的内容。
我已经创建了一个配置,其中包含我的应用程序所需的所有导航。加载特定视图时,导航组件会加载所需的配置部分
配置示例
export const navConfig = [{
sectionName:"Search",
i18nKey: "search",
sectionTopDivider: true,
menuList:[
{
menuName: "Company1",
i18nKey: "company1",
route: "app/company1",
prependIconName: "search",
customClass:"text-success",
appendIconName: "image",
},
{
menuName: "Company2",
i18nKey: "company2",
route: "app/company2",
prependIconName: "search",
appendIconName: "image"
}
]},{
sectionName:"OverView",
i18nKey:"OverView",
sectionTopDivider: true,
menuList:[
{
menuName: "Company 1 Overview",
i18nKey: "company1 overview",
route: "app/company1-overview",
prependIconName: "home",
appendIconName: "image",
menuList: [
{
menuName: "Company1 Child Route",
i18nKey: "",
route: "company1/[departmentId]",
prependIconName: "",
appendSVGIconName: "",
}
]
},
{
menuName: "Company 2 Overview",
i18nKey: "company2 overview",
route: "app/company2-overview",
prependIconName: "home",
appendIconName: "image",
menuList: [
{
menuName: "Company2 Child Route",
i18nKey: "",
route: "company2/[departmentId]",
prependIconName: "",
appendSVGIconName: "",
}
]
}
]}]
所有与应用程序相关的文件都附加到该代码片段中。 您可以将此导航组件插入到您的应用程序中,如下所示
<app-left-navbar></app-left-navbar>
要加载导航配置,请将导航服务注入构造函数并加载所需的导航配置 例如:
private navService: LeftNavbarService,
this.navService.setNavConfigList(navConfig);
其中 navConfig 是根据模型 left-nav.model.ts 所需的导航配置
如果您想从配置中加载特定部分,您可以像下面这样做
this.route.url.subscribe(url=>{
let headerModel: HeaderModel = {
mainLabel: "New Header",
mainIconName: "menu",
subLabel: "Back to dashboard",
subIconName: "arrow_back",
subRoute: "./"
}
this.navService.setNavHeader(headerModel); // new header model if required
let defaultNavConfig = this.navService.getNavConfigList(); // featch loaded config from nav service
let section = this.navService.getConfig(defaultNavConfig, 'sectionName', 'OverView'); //fetch required section from config using section name
section.hidden = false; //edit section visibility if required
this.navService.setNavList(defaultNavConfig); // set nav with updated config. You can edit already existing config or can add new config if required
})
请通过服务了解工作情况。
//left-navbar.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, take } from 'rxjs';
import { HeaderModel, LeftMenuConfig, MenuItemConfig } from '../models/left-nav.model';
import * as _ from 'lodash';
@Injectable({
providedIn: 'root'
})
export class LeftNavbarService {
navConfigList!: LeftMenuConfig[];//new BehaviorSubject<LeftMenuConfig[]>([]);
navList = new BehaviorSubject<LeftMenuConfig[]>([]);
headerModel = new BehaviorSubject<HeaderModel>(<HeaderModel>{});
// footerModel = new BehaviorSubject<HeaderModel>(<HeaderModel>{});
activeNavModel!: MenuItemConfig;
constructor() { }
getNavList(): Observable<LeftMenuConfig[]> {
return this.navList.asObservable();
}
getNavConfigList(): LeftMenuConfig[] {
return _.cloneDeep(this.navConfigList);
}
setNavList(navList: LeftMenuConfig[]) {
this.navList.next(navList)
}
setNavConfigList(navList: LeftMenuConfig[]) {
this.navConfigList = navList;
}
getNavHeader(): Observable<HeaderModel> {
return this.headerModel.asObservable();
}
setNavHeader(headerModel: HeaderModel) {
this.headerModel.next(headerModel);
}
// getNavFooter(): Observable<HeaderModel> {
// return this.footerModel.asObservable();
// }
// setNavFooter(footerModel: HeaderModel) {
// this.footerModel.next(footerModel);
// }
getNavListPromise() {
return this.navList.pipe(take(1)).toPromise();
}
setActiveNavModel(navModel: MenuItemConfig) {
this.activeNavModel = navModel;
}
getActiveNavModel() {
return this.activeNavModel;
}
getConfig(listToMatch: Array<any>, key: string, value: string): any {
let matched;
for (let i = 0; i < listToMatch.length; i++) {
let item = listToMatch[i];
if (item[key] === value) {
matched = item;
break;
}
if (item.menuList && item.menuList.length) {
matched = this.getConfig(item.menuList, 'menuName', value);
if (matched) break;
}
}
return matched;
}
}
//left-nav.model.ts
export interface LeftMenuConfig {
sectionName: string,
i18nKey: string,
sectionTopDivider?: boolean,
sectionBottomDivider?: boolean,
hidden?:boolean,
menuList: MenuItemConfig[]
}
export interface MenuItemConfig {
menuName: string,
i18nKey: string,
route: string,
prependIconName?: ((item: MenuItemConfig) => string) | string,
prependSVGIconName?: ((item: MenuItemConfig) => string) | string,
appendIconName?: ((item: MenuItemConfig) => string) | string,
appendSVGIconName?: ((item: MenuItemConfig) => string) | string,
data?: any,
rawHtml?: ((item: MenuItemConfig) => string) | string,
customClass?: ((item: MenuItemConfig) => string) | string,
formatterComponent?: any,
hidden?: boolean,
disabled?:boolean,
privilege?:string,
selected?: boolean,
menuList?: MenuItemConfig[]
}
export interface HeaderModel {
mainLabel: string,
mainRoute?: string,
mainIconName?: string,
mainSvgIconName?: string,
subLabel?: string,
subRoute?: string,
subIconName?: string,
subSvgIconName?: string,
}
//left-navbar.component.ts
import { Component, ElementRef, Input, OnInit } from '@angular/core';
import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
import { filter, Observable } from 'rxjs';
import { HeaderModel, LeftMenuConfig, MenuItemConfig } from '../models/left-nav.model';
import { LeftNavbarService } from '../services/left-navbar.service';
import { animateText, onSideNavChange } from './left-nav-animations';
@Component({
selector: 'app-left-navbar',
templateUrl: './left-navbar.component.html',
styleUrls: ['./left-navbar.component.scss'],
animations: [onSideNavChange, animateText]
})
export class LeftNavbarComponent implements OnInit {
constructor(
private navbarService: LeftNavbarService,
private route: ActivatedRoute,
private router: Router
) {
this.router.events
.pipe(
filter(event => event instanceof NavigationStart)
)
.subscribe(
(event) => {
let url = this.route.url;
console.log(url);
}
);
}
navList!: Observable<LeftMenuConfig[]>;
headerModel!: Observable<HeaderModel>;
footerModel!: any;
expanded = true;
navState = true;
@Input() leftPadding: number = 0; // Initial left padding of list item
@Input() listNodePadding: number = 20 // Left padding of children list items for each level
ngOnInit() {
this.navList = this.navbarService.getNavList();
this.headerModel = this.navbarService.getNavHeader();
this.footerModel = {
mainLabel: 'Help & Support',
mainRoute: '',
mainIconName: 'help_outline',
subLabel: 'Help Sub Label',
subRoute: '',
subIconName: 'copyright',
};
}
getCustomIcon(item: any, key: string) {
if (item[key] && typeof (item[key]) === 'function') {
return item[key](item);
} else return item[key];
}
toggleLeftNav() {
this.navState = !this.navState;
setTimeout(() => {
this.expanded = this.navState;
}, 200)
}
onActivateRoute(isActive: boolean, item: MenuItemConfig) {
if (isActive) {
this.navbarService.setActiveNavModel(item);
};
}
}
//left-navbar.component.scss
.left-nav-container {
::ng-deep {
.mat-list-item {
height: 40px !important;
align-items: center;
// border-left: 4px solid transparent;
// &.active {
// // border-left: 4px solid #303030;
// }
.mat-list-item-content {
overflow: hidden;
padding: 0 0 0 4px !important;
width: 100%;
}
&:disabled {
cursor: not-allowed;
pointer-events: none;
opacity: 0.6;
}
}
.mat-subheader {
padding: 0 !important;
}
.mat-nav-list.footer-section {
margin-top: auto !important;
}
.mat-list-text {
padding-left: 0 !important;
}
}
&.expanded {
// min-width: 220px;
}
&.collapsed {
::ng-deep {
.mat-list-item {
// width: 40px !important;
justify-content: center;
}
}
}
.menu-group-container {
padding: 0 4px;
&.active-container {
border-radius: 4px;
background-color: #e8ecef80;
padding: 4px;
}
}
.active-container {
border-radius: 4px;
background-color: #e8ecef80;
padding: 4px;
}
}
.expandCollapseBtn {
width: 24px;
height: 24px;
background-color: #8b9daf;
border-radius: 50%;
display: inline-block;
right: -12px;
top: 10px;
z-index: 4;
cursor: pointer;
span.material-icons {
color: white;
}
}
.child-indicator-elm {
position: absolute;
width: 8px;
height: 30px;
z-index: 1;
&::before {
content: "";
float: left;
width: 8px;
height: inherit;
background: transparent;
border: 2px solid #A3B1BF;
border-bottom-left-radius: 6px;
border-top: 0;
border-right: 0;
position: absolute;
top: 0px;
left: 0px;
}
&::after {
content: "";
float: right;
width: 4px;
height: 4px;
border-radius: 50%;
position: absolute;
right: -3px;
bottom: -1px;
background-color: #A3B1BF;
}
}
.display-none {
display: none !important;
}
//left-navbar.component.html
<div [@onSideNavChange]="navState ? 'open' : 'close'" class="left-nav-container p-2 h-100 position-relative"
[ngClass]="{'expanded':expanded, 'collapsed':!expanded}">
<span class="expandCollapseBtn position-absolute" (click)="toggleLeftNav()">
<span *ngIf="expanded" class="material-icons">arrow_left</span>
<span *ngIf="!expanded" class="material-icons">arrow_right</span>
</span>
<div class="w-100 h-100 d-flex flex-column align-items-stretched justify-content-start">
<ng-container *ngIf="headerModel | async">
<ng-container *ngTemplateOutlet="headerTmpl; context:{item: headerModel | async, class: 'header-section'}">
</ng-container>
</ng-container>
<mat-nav-list dense>
<ng-container *ngFor="let item of navList | async">
<ng-container *ngIf="!item?.hidden">
<mat-divider *ngIf="item?.sectionTopDivider"></mat-divider>
<span *ngIf="item?.sectionName && expanded" mat-subheader>{{item?.sectionName}}</span>
<ng-container *ngFor="let menuItem of item?.menuList">
<div [appUserPrivilege]="menuItem?.privilege" class="menu-group-container"
[ngClass]="{'p-0':!expanded, 'active-container': menuItem?.selected}">
<ng-container *ngIf="menuItem?.formatterComponent">
<app-formatter-navlink [navModel]="menuItem"></app-formatter-navlink>
</ng-container>
<ng-container *ngIf="menuItem?.rawHtml">
<a mat-list-item class="d-flex rounded" [routerLink]="menuItem?.route"
routerLinkActive="active"
[innerHTML]="menuItem | navCustomHandler : 'rawHtml' | safeHtml">
</a>
</ng-container>
<ng-container
*ngIf="!menuItem?.formatterComponent && !menuItem?.rawHtml && !menuItem?.hidden">
<div appCustomClassHandler [menuItem]="menuItem">
<a [disabled]="menuItem?.disabled" mat-list-item
(isActiveChange)="onActivateRoute($event,menuItem)"
[routerLink]="menuItem?.route" class="d-flex rounded"
[style.padding-left.px]="expanded ? leftPadding: 0"
[routerLinkActiveOptions]="{exact: true}" [state]="{config: menuItem}"
routerLinkActive="active">
<mat-icon *ngIf="menuItem?.prependIconName" matListIcon
[innerText]="menuItem | navCustomHandler: 'prependIconName'"></mat-icon>
<mat-icon *ngIf="menuItem?.prependSVGIconName" mat-list-icon
svgIcon="{{ getCustomIcon(menuItem, 'prependSVGIconName') }}"></mat-icon>
<div class="ps-1" [@animateText]="expanded ? 'show' : 'hide'" matLine>
{{menuItem?.i18nKey}}
</div>
<mat-icon *ngIf="menuItem?.appendIconName"
[@animateText]="expanded ? 'show' : 'hide'"
[innerText]="menuItem | navCustomHandler: 'appendIconName'"></mat-icon>
<mat-icon class="d-flex" *ngIf="menuItem?.appendSVGIconName"
[@animateText]="expanded ? 'show' : 'hide'"
svgIcon="{{ getCustomIcon(menuItem, 'appendSVGIconName') }}"></mat-icon>
</a>
</div>
</ng-container>
<ng-container *ngIf="!menuItem.hidden && menuItem?.menuList">
<ng-container
*ngTemplateOutlet="navTmpl; context:{menuItem: menuItem, leftPadding: leftPadding + listNodePadding }">
</ng-container>
</ng-container>
</div>
</ng-container>
<mat-divider *ngIf="item?.sectionBottomDivider"></mat-divider>
</ng-container>
</ng-container>
</mat-nav-list>
<ng-container *ngIf="footerModel">
<ng-container
*ngTemplateOutlet="footerTmpl; context:{item: footerModel, class: 'footer-section', footer: true}">
</ng-container>
</ng-container>
</div>
</div>
<ng-template #navTmpl let-parentConfig="menuItem" let-menuItem="menuItem" let-leftPadding="leftPadding">
<mat-nav-list dense>
<ng-container *ngFor="let menuItem of menuItem?.menuList; let i=index;">
<ng-container *ngIf="menuItem && !menuItem?.hidden">
<div [ngClass]="{'active-container':menuItem?.selected}" [appUserPrivilege]="menuItem?.privilege">
<ng-container *ngIf="menuItem?.formatterComponent">
<app-formatter-navlink [navModel]="menuItem"></app-formatter-navlink>
</ng-container>
<ng-container *ngIf="menuItem?.rawHtml">
<a mat-list-item class="d-flex rounded" [routerLink]="menuItem?.route" routerLinkActive="active"
[innerHTML]="menuItem.rawHtml(menuItem) | safeHtml">
</a>
</ng-container>
<ng-container *ngIf="!menuItem?.formatterComponent && !menuItem?.rawHtml">
<div class="position-relative" appCustomClassHandler [menuItem]="menuItem">
<span *ngIf="expanded" appFluidHeight [refElement]="linkRef" [parentConfig]="parentConfig"
[index]="i" [style.bottom.px]="linkRef['_element']?.nativeElement?.offsetHeight/2"
[style.left.px]="leftPadding" class="child-indicator-elm"></span>
<a #linkRef [disabled]="menuItem?.disabled" mat-list-item
[style.padding-left.px]="expanded ? leftPadding: 0" class="d-flex rounded"
(isActiveChange)="onActivateRoute($event,menuItem)" [routerLink]="menuItem?.route"
[state]="{config: menuItem}" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: true}">
<mat-icon *ngIf="menuItem?.prependIconName" matListIcon
[innerText]="menuItem | navCustomHandler: 'prependIconName'"></mat-icon>
<mat-icon *ngIf="menuItem?.prependSVGIconName" mat-list-icon
svgIcon="{{ getCustomIcon(menuItem, 'prependSVGIconName') }}"></mat-icon>
<div class="ps-1" [@animateText]="expanded ? 'show' : 'hide'" matLine>
{{menuItem?.i18nKey}}
</div>
<mat-icon *ngIf="menuItem?.appendIconName" [@animateText]="expanded ? 'show' : 'hide'"
[innerText]="menuItem | navCustomHandler: 'appendIconName'"></mat-icon>
<mat-icon class="d-flex" *ngIf="menuItem?.appendSVGIconName"
[@animateText]="expanded ? 'show' : 'hide'"
svgIcon="{{ getCustomIcon(menuItem, 'appendSVGIconName') }}"></mat-icon>
</a>
</div>
</ng-container>
<ng-container *ngIf="menuItem?.menuList">
<ng-container
*ngTemplateOutlet="navTmpl; context:{menuItem: menuItem, leftPadding: leftPadding + listNodePadding}">
</ng-container>
</ng-container>
</div>
</ng-container>
</ng-container>
</mat-nav-list>
</ng-template>
<ng-template #headerTmpl let-item="item" let-class="class" let-isFooter="footer">
<mat-nav-list [ngClass]="class" dense>
<mat-divider *ngIf="isFooter"></mat-divider>
<ng-container *ngIf="item?.mainLabel">
<a mat-list-item [@animateText]="expanded ? 'show' : 'hide'" [ngClass]="{'d-flex mainLabel rounded': true}"
[routerLink]="item?.mainRoute" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<mat-icon *ngIf="item.mainIconName" matListIcon>{{item?.mainIconName}}</mat-icon>
<mat-icon *ngIf="item.mainSvgIcon" mat-list-icon svgIcon="{{ item.mainSvgIcon }}"></mat-icon>
<div [@animateText]="expanded ? 'show' : 'hide'" matLine class="ms-2 ml-2">{{item?.mainLabel}}</div>
</a>
</ng-container>
<ng-container *ngIf="item?.subLabel">
<a mat-list-item [ngClass]="{'d-flex subLabel rounded': true}" [routerLink]="item?.subRoute"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<mat-icon *ngIf="item.subIconName" matListIcon>{{item?.subIconName}}</mat-icon>
<mat-icon *ngIf="item.subSvgIcon" mat-list-icon svgIcon="{{ item.subSvgIcon }}"></mat-icon>
<div [@animateText]="expanded ? 'show' : 'hide'" matLine class="ms-2 ml-2">{{item?.subLabel}}</div>
</a>
</ng-container>
</mat-nav-list>
</ng-template>
<ng-template #footerTmpl let-item="item" let-class="class">
<mat-nav-list [ngClass]="class" dense>
<mat-divider *ngIf="class"></mat-divider>
<ng-container *ngIf="item?.mainLabel">
<a mat-list-item [ngClass]="{'d-flex mainLabel rounded': true}" [routerLink]="item?.mainRoute"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<mat-icon *ngIf="item.mainIconName" matListIcon>{{item?.mainIconName}}</mat-icon>
<mat-icon *ngIf="item.mainSvgIcon" mat-list-icon svgIcon="{{ item.mainSvgIcon }}"></mat-icon>
<div [@animateText]="expanded ? 'show' : 'hide'" matLine class="ms-2 ml-2">{{item?.mainLabel}}</div>
</a>
</ng-container>
<ng-container *ngIf="item?.subLabel">
<a mat-list-item [ngClass]="{'d-flex subLabel rounded': true}" [routerLink]="item?.subRoute"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<mat-icon *ngIf="item.subIconName" matListIcon>{{item?.subIconName}}</mat-icon>
<mat-icon *ngIf="item.subSvgIcon" mat-list-icon svgIcon="{{ item.subSvgIcon }}"></mat-icon>
<div [@animateText]="expanded ? 'show' : 'hide'" matLine class="ms-2 ml-2">{{item?.subLabel}}</div>
</a>
</ng-container>
</mat-nav-list>
</ng-template>