Reputation: 1007
I'm trying to use a nested *ngFor in my Angular project to render a dynamic menu. I'm trying something like this:
<li class="treeview" *ngFor="let pm of parentMenu">
<a href="#">
<i class="fa fa-edit"></i> <span>{{pm.MenuTitle}}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu" *ngFor="let cm of childMenu">
<li *ngIf="cm.ParentMenuId == pm.Id">{{cm.MenuTitle}}</li>
</ul>
</li>
I'm only getting the first element of childMenu, my understanding was *ngFor works similar to foreach in C#, but clearly, that's not the case. Could someone please help me fix the code and understand it?
Upvotes: 0
Views: 262
Reputation: 2213
I don't know the content of your .ts
file, but your code works fine for me here:
https://stackblitz.com/edit/angular-sduuwm
Notice that I have defined my arrays like this:
parentMenu = [
{
Id: 1,
MenuTitle: "One",
},
{
Id: 2,
MenuTitle: "Two",
},
{
Id: 3,
MenuTitle: "Three",
}
];
childMenu = [
{
ParentMenuId: 1,
MenuTitle: "One quarter"
},
{
ParentMenuId: 1,
MenuTitle: "One half"
},
{
ParentMenuId: 2,
MenuTitle: "Two half"
},
{
ParentMenuId: 3,
MenuTitle: "Three half"
}
];
However, that said, if I were you I would rather define my arrays like this:
parentMenu = [
{
Id: 1,
MenuTitle: "One",
childMenu: [
{ MenuTitle: "One quarter" },
{ MenuTitle: "One half" },
]
},
{
Id: 2,
MenuTitle: "Two",
childMenu: [
{ MenuTitle: "Two half" },
]
},
{
Id: 3,
MenuTitle: "Three",
childMenu: [
{ MenuTitle: "Three half" },
]
}
];
and do the HTML like this:
<a href="#">
<i class="fa fa-edit"></i> <span>{{pm.MenuTitle}}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu" *ngFor="let cm of pm.childMenu">
<li>{{cm.MenuTitle}}</li>
</ul>
And you won't need the *ngIf
test in your code.
Upvotes: 3
Reputation: 5131
You are correct that ngFor behaves like a foreach or for loop.
I suspect your problem is the object you are binding to.
using basically your code there should be a property on the component called parentItem that is an array with nested properties including childMenu
parentMenu = {
'Parent1':[{'menuTitle':'Menu 1', 'childItem':[
{'menuTitle':'sub item 1'}]
},
{'menuTitle':'A cool menu', 'childItem':[
{'menuTitle':'sub item 1'},
{'menuTitle': 'sub item 2'}]
}]
}
and then your HTML should work much like:
<li class="treeview" *ngFor="let pm of parentMenu.Parent1">
<a href="#">
<i class="fa fa-edit"></i> <span>{{pm.menuTitle}}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu" *ngFor="let cm of pm.childItem">
<li>{{cm.menuTitle}}</li>
</ul>
</li>
And for reference in action a working stackblitz from your code:
Upvotes: 0
Reputation: 1
<ul>
<ng-template #recursiveMenu let-parentMenu>
<li class="treeview" *ngFor="let pm of parentMenu">
<a href="#">
<i class="fa fa-edit"></i> <span>{{pm.MenuTitle}}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<ng-container *ngTemplateOutlet="recursiveMenu; context:{
$implicit: pm.childMenu}">
</ng-container>
</ul>
</li>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveMenu; context:{
$implicit: parentMenu}">
</ng-container>
</ul>
Upvotes: 0
Reputation: 44
You can achieve recursive menu by using template, containers or recursive calling of a component. There are different approaches that you can follow.
Angular2 Navigation Menu with Recursive Templates
Recursion in Angular Components
Angular *ngFor recursive list tree template
Upvotes: -1
Reputation: 507
try this code
<ul class="treeview-menu" *ngFor="let cm of pm.childMenu">
<li *ngIf="cm.ParentMenuId == pm.Id">{{cm.MenuTitle}}</li>
</ul>
Upvotes: 0