Why not create a tree component and bind inputs to it recursively?
The proposed solution is
- depth-agnostic - it will work for any number of levels in your data tree (even if it changes ad-hoc)
- quite efficient - it aggregates your data in
O(n)
.
First design the data model - it has to be a tree-node structure:
export interface GroupId { /* appropriate members... */ }
export interface ParentLocationGroup { /* other members... */ __text: string; }
export interface LgLevel { /* other members... */ __text: string; }
export interface DataModel {
Id: string,
Name: string,
GroupId: GroupId,
ParentLocationGroup: ParentLocationGroup,
LgLevel: LgLevel,
children: DataModel[]
}
Then aggregate your data in the top-level component (or even better - in your data service; you should be able to abstract that easily enough):
// dropdown.component.ts
@Component({
selector: 'app-dropdown',
template: `
<ul class="nav site-nav">
<li class=flyout>
<a href=#>Dropdown</a>
<app-dynamic-flyout [data]="data"></app-dynamic-flyout>
</li>
</ul>
`
})
export class DropdownComponent {
data: DataModel[];
constructor(dataService: YourDataService){
let data;
dataService.getYourData()
.pipe(map(d => d.ArrayOfLocationGroup.LocationGroup)))
// Make sure every item has the `children` array property initialized
// since it does not come with your data
.subscribe(d => data = d.map(i => ({...i, children: []})));
// Create a lookup map for building the data tree
let idMap = data.reduce((acc, curr) => ({...acc, [curr.Id]: curr}), {});
this.data = data.reduce(
(acc, curr) => curr.LgLevel.__text == 0 || !curr.ParentLocationGroup
// Either the level is 0 or there is no parent group
// (the logic is unclear here - even some of your lvl 0 nodes have a `ParentGroup`)
// -> we assume this is a top-level node and put it to the accumulator
? [...acc, curr]
// Otherwise push this node to an appropriate `children` array
// and return the current accumulator
: idMap[curr.ParentLocationGroup.__text].children.push(curr) && acc,
[]
);
}
}
And create the recurrent dynamic flyout component:
// dynamic-flyout.component.ts
@Component({
selector: 'app-dynamic-flyout',
template: `
<ul *ngIf="!!data.length" class="flyout-content nav stacked">
<li *ngFor="let item of data" [class.flyout-alt]="!!item.children.length">
<a href=#>{{item.Name}}</a>
<app-dynamic-flyout [data]="item.children"></app-dynamic-flyout>
</li>
</ul>
`
})
export class DynamicFlyoutComponent {
@Input() data: DataModel[];
}
The solution is not tested but it shall point you in a right direction...
Hope this helps a little :-)