'How can We create dynamic route navigation Link in angular with multi level children and which will recreate whole navigation on reload
I wanted to create a navigation list based on some configuration. like an Array of
export interface LeftNavModel {
name: string,
route: string,
iconName?: string,
data?: any }
so navigation data will look something like
[
{
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"
}
]
}
]
}
]
This data will create nav link like

And in a component create routerLink using the routes from the config JSON. I was able to create the same and is working fine. The issue is I wanted to share the navigated URL so other users can open the same page with navigation created dynamically.
Page Refresh can be handled by keeping config as state in router. Or using any storage mechanism like localStorage. But how can we share the link along with config data. Passing config as queryParam will create huge url. Any other option for the same?
Solution 1:[1]
I had to do this in a project I am working on a while back.
I am using bootstrap accordions for my sidebar, and as such needed to give each menu item an id. You could accomplish the same thing with anything though doesn't have to be bootstrap.
Create a class to represent the menu/nav items (Mine is something like this)
export class MenuItem {
id: number;
text: string;
icon: string;
url?: string;
children?: MenuItem[];
}
Create a menu items array which will store the list of items. This is a shortened version of what mine looks like:
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',
},
],
},
]
Initialize the menu items from the component that contains the nav items
import { menuItems } from '../menuItems';
public ngOnInit() {
this.renderMenu();
}
private renderMenu(): void {
this.renderedMenuItems = JSON.parse(JSON.stringify(menuItems));
}
Add HTML similar to below in order to iterate over the menu items
<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>
With the above code, I end up with the following (after styling obviously)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Hedgybeats |

