Let's assume I have the following tree structure:
Item1 Item2 Item3 Item4 Itemn
/ | \ / | \ / | \ / | \ / | \
/ | \ / | \ / | \ / | \ / | \
a b c d e f g h i j k l n-2 n-1 n
Each node from a,b,...,n
has values.
What's a more efficient way to structure this navigation?
My approach is he following:
Create an array toggleStatus
that contains boolean values.
Assign a number to each tab which is respectively equal to the index of toggleStatus
.
A method toggle(index)
will toggle the value of toggleStatus
at index index
.
Please have a look at my Stackblitz for a working example.
You don't need to add all the data directly into your HTML. You can just create an array of objects which will make it perfect for a nested ngFor
case.
Your data will look something like this
menus: any[] = [{
item: 'Item 1', submenus: [
{ item: 'a', info: 'Info of a' },
{ item: 'b', info: 'Info of b' },
{ item: 'c', info: 'Info of c' }
]
}, {
item: 'Item 2', submenus: [
{ item: 'd', info: 'Info of d' },
{ item: 'e', info: 'Info of e' },
{ item: 'f', info: 'Info of f' }
]
}, {
item: 'Item 3', submenus: [
{ item: 'g', info: 'Info of g' },
{ item: 'h', info: 'Info of h' },
{ item: 'i', info: 'Info of i' }
]
}, {
item: 'Item 4', submenus: [
{ item: 'j', info: 'Info of j' },
{ item: 'k', info: 'Info of k' },
{ item: 'l', info: 'Info of l' }
]
}];
Then in your HTML, we will loop over the menus
using ngFor
<div *ngFor="let menu of menus; let i = index">
<!-- Menu -->
<div (click)="toggleMenu(i)" class="text-white cursor-pointer text-center">
<div class="py-4 bg-blue-600 hover:bg-blue-400">
{{menu.item}}
</div>
<div class="container" *ngIf="showSubmenu[i]">
<!-- Submenus -->
<ng-container *ngFor="let submenu of menu.submenus; let j = index">
<div (click)="toggleSubmenu($event, submenu.item)" class="py-3 w-1/3 inline-block"
[ngClass]="{'bg-blue-200': j === 0, 'bg-blue-300': j === 1, 'bg-blue-400': j === 2}">
{{submenu.item}}
</div>
</ng-container>
<!-- Information -->
<div *ngFor="let submenu of menu.submenus; let j = index">
<div *ngIf="showInfo[submenu.item]" (click)="$event.stopPropagation()" class="py-3 bg-green-400">
{{submenu.info}}
</div>
</div>
</div>
</div>
</div>
In your component, we shall define the flags and the toggle
functions. I have used an array for flags. We will dynamically insert the toggle flag into this array based on the index. $event.stopPropagation
is used to prevent the click
event from bubbling up into the parent element's click
event. Here's how the component will look
showSubmenu: any[] = [];
showInfo: any[] = [];
toggleMenu(index: number) {
this.showSubmenu[index] = !this.showSubmenu[index];
}
toggleSubmenu(event: MouseEvent, item: string) {
event.stopPropagation();
this.showInfo[item] = !this.showInfo[item];
}
Note: The
item
passed to thetoggleSubmenu
should be a unique value. If you have anid
, it would be preferred to use that here instead ofitem
.
Here is a working StackBlitz of the same.