Есть ли способ сохранить состояние расширенного узла sidenav без использования какого-либо управления состоянием? На данный момент расширенный узел sidenav будет сбрасываться каждый раз при изменении маршрута. Кажется, что компонент navbar разрушается снова и снова.
navbar.component. html
<mat-sidenav-container [hasBackdrop]="true" autosize>
<mat-sidenav fixedTopGap="60" fixedInViewport="true" #sidenav mode="over">
<mat-list-item>Modules</mat-list-item>
<mat-tree
[dataSource]="dataSource"
[treeControl]="treeControl"
class="tree"
>
<ng-container *matTreeNodeDef="let node">
<mat-tree-node routerLinkActive="active" matTreeNodeToggle>
<a class="full-content" [routerLink]="[node.link]" mat-icon-button>
<div style="text-align: left;">
<mat-icon mat-icon-button>{{ node.icon }}</mat-icon>
<mat-label>{{ node.name }}</mat-label>
</div>
</a>
</mat-tree-node>
</ng-container>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<li>
<div class="mat-tree-node">
<button
matTreeNodeToggle
class="full-content-button"
mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node)"
>
<mat-icon class="mat-icon-rt1-mirror">
{{
treeControl.isExpanded(node) ? 'expand_less' : 'expand_more'
}}
</mat-icon>
{{ node.name }}
</button>
</div>
<ul [class.tree-invisible]="!treeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
<hr />
</li>
</mat-nested-tree-node>
</mat-tree>
</mat-sidenav>
<mat-sidenav-content (scroll)="onScroll($event)">
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
navbar.component.ts
import * as CryptoJS from "crypto-js";
import cloneDeep from 'lodash.clonedeep';
import { ActivatedRoute, Data, Router, UrlSegment } from '@angular/router';
import {
AfterViewInit,
Component,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
import { excludedModule } from 'src/app/shared/type-casting/enum/navbar-exclude.enum';
import { INavBarMenu } from '../../../models/modules/general/navbar/NavBar.model';
import { LocalStorageService } from './../../../util/localStorage/local-storage.service';
import { MatSidenav } from '@angular/material';
import { NavBarService } from './../../../../core/services/general/navbar/navbar.service';
import { NestedTreeControl } from '@angular/cdk/tree';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('sidenav') _sidenav: MatSidenav;
/** @value Cater opacity value of '0' & '1' */
private isFooterShownSubject = new BehaviorSubject<number>(+false);
readonly isFooterShown$ = this.isFooterShownSubject.asObservable();
public dataSource: INavBarMenu[];
public treeControl = new NestedTreeControl<INavBarMenu>(
node => node.children
);
private enumExcludedModule = Object.values(excludedModule);
private subscriptions = new Subscription();
private route: Data;
constructor(
private _navBarService: NavBarService,
private _acRoute: ActivatedRoute,
private _router: Router,
private _localStorage: LocalStorageService
) {
this.route = _acRoute.snapshot.root.firstChild.children[0].children[0];
/** @execute multiple subscription in parallel, then take only latest subscription */
combineLatest(this.getMenuDetails(), _acRoute.url).subscribe(
([res]: [INavBarMenu[], UrlSegment[]]) => {
const clonedRes: INavBarMenu[] = cloneDeep(res);
const accessRights = CryptoJS.AES.encrypt(
JSON.stringify(clonedRes),
"Secret Passphrase"
);
localStorage.setItem('accessRights', accessRights);
/** @mutation - changed object reference of clonedRes, lastly this.dataSource assigned value of mutated clonedRes */
clonedRes.forEach(el =>
this.enumExcludedModule.forEach(
exclude =>
(el.children = Object.values(el.children).filter(
value => value.link !== exclude
))
)
);
this.dataSource = clonedRes;
}
);
}
onScroll(event: any) {
/** @logic visible height + pixel scrolled >= total height */
event.target.offsetHeight + event.target.scrollTop >=
event.target.scrollHeight
? this.isFooterShownSubject.next(+1)
: this.isFooterShownSubject.next(+0);
}
hasChild = (_: number, node: INavBarMenu) =>
!!node.children && node.children.length > 0;
ngOnInit() {}
goHome() {
this._router.navigate(['/homepage']);
}
logout() {
localStorage.clear();
this._router.navigate(['/login']);
}
ngAfterViewInit(): void {
}
changeState(node) {
console.log(node);
}
ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}
}
NavBar.model.ts
export class INavBarMenu {
constructor(
public id: number,
public name: string,
public pView: string,
public pAdd: string,
public pEdit: string,
public pDelete: string,
public link?: string,
public icon?: string,
public isExpanded?: boolean,
public children?: INavBarMenu []
) {}
}
Образец данных
{"id":12,"icon":null,"name":"Prod. Control","nameDesc":null,"pID":10,"link":null,"pView":"true","pAdd":"true","pEdit":"true","pDelete":"true","children":[{"id":33,"icon":null,"name":"PO Listing","nameDesc":null,"pID":12,"link":"/productionorder","pView":"true","pAdd":"true","pEdit":"true","pDelete":"true"},{"id":26,"icon":null,"name":"Design Layout","nameDesc":null,"pID":12,"link":"/designlayout","pView":"true","pAdd":"true","pEdit":"true","pDelete":"true"}]}