Reputation: 13367
I assume this is simple but for some reason I can't figure it out. I am building a simple submenu. I have created the component:
export class SubMenuComponent implements OnInit {
@Input() links: MenuItem[];
constructor() {}
ngOnInit(): void {}
}
The MenuItem looks like this:
export class MenuItem {
label: string;
path: string;
open: boolean;
children?: MenuItem[];
}
And the Html looks like this:
<ul class="app-sub-menu list-unstyled">
<li *ngFor="let link of links" routerLinkActive="active"><a class="btn-link" [routerLink]="link.path"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: link.path === '/'}">{{ link.label }}</a>
<span class="toggle" *ngIf="link.children?.length" (click)="link.open = !link.open">
<mat-icon *ngIf="link.isActive || link.open">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="!link.isActive && !link.open">keyboard_arrow_up</mat-icon>
</span>
<ul class="list-unstyled" [class.open]="link.open" *ngIf="link.children?.length">
<li *ngFor="let link of link.children" routerLinkActive="active"><a class="btn-link"
routerLinkActive="active" [routerLink]="link.path" #link>{{ link.label }}</a>
<span class="toggle" *ngIf="link.children?.length" (click)="link.open = !link.open">
<mat-icon *ngIf="link.isActive || link.open">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="!link.isActive && !link.open">keyboard_arrow_up</mat-icon>
</span>
<ul class="list-unstyled" [class.open]="link.open" *ngIf="link.children?.length">
<li *ngFor="let link of link.children" routerLinkActive="active"><a class="btn-link"
routerLinkActive="active" [routerLink]="link.path">{{ link.label }}</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
As you can see, this current sub-menu only goes down 3 levels. I would like it to be infinitely nested. So I decided to use ng-template, but I can't get it to work. I thought it would be as simple as:
<ul class="app-sub-menu list-unstyled">
<ng-template *ngTemplateOutlet="link" *ngFor="let link of links"></ng-template>
</ul>
<ng-template #link>
<li *ngFor="let link of links" routerLinkActive="active"><a class="btn-link" [routerLink]="link.path"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: link.path === '/'}">{{ link.label }}</a>
<span class="toggle" *ngIf="link.children?.length" (click)="link.open = !link.open">
<mat-icon *ngIf="link.isActive || link.open">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="!link.isActive && !link.open">keyboard_arrow_up</mat-icon>
</span>
<ul class="list-unstyled" [class.open]="link.open" *ngIf="link.children?.length">
<ng-template *ngTemplateOutlet="link" *ngFor="let link of link.children"></ng-template>
</ul>
</li>
</ng-template>
But when I try to use that, I get an error:
Can't have multiple template bindings on one element. Use only one attribute prefixed with *
So I changed it to this:
And now I get a new error:
templateRef.createEmbeddedView is not a function
Does anyone know what I can do to get this to work?
Reading this:
It looks like I was using my template incorrectly, so I changed it to this:
<ul class="app-sub-menu list-unstyled">
<ng-container *ngTemplateOutlet="link; context: { $implicit: links }"></ng-container>
</ul>
<ng-template #link let-links>
<li *ngFor="let link of links" routerLinkActive="active"><a class="btn-link" [routerLink]="link.path"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: link.path === '/'}">{{ link.label }}</a>
<span class="toggle" *ngIf="link.children?.length" (click)="link.open = !link.open">
<mat-icon *ngIf="link.isActive || link.open">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="!link.isActive && !link.open">keyboard_arrow_up</mat-icon>
</span>
<ul class="list-unstyled" [class.open]="link.open" *ngIf="link.children?.length">
<ng-container *ngTemplateOutlet="link; context: { $implicit: link.children }"></ng-container>
</ul>
</li>
</ng-template>
But I am still getting the error :(
templateRef.createEmbeddedView is not a function
Upvotes: 0
Views: 526
Reputation: 13367
I figured it out, it was because my template id was the same as the actual model. So I changed it to this:
<ul class="app-sub-menu list-unstyled">
<ng-template #nestedList let-links>
<li *ngFor="let link of links" routerLinkActive="active"><a class="btn-link" [routerLink]="link.path"
routerLinkActive="active" [routerLinkActiveOptions]="{exact: link.path === '/'}">{{ link.label }}</a>
<span class="toggle" *ngIf="link.children?.length" (click)="link.open = !link.open">
<mat-icon *ngIf="link.isActive || link.open">keyboard_arrow_down</mat-icon>
<mat-icon *ngIf="!link.isActive && !link.open">keyboard_arrow_up</mat-icon>
</span>
<ul class="list-unstyled" [class.open]="link.open" *ngIf="link.children?.length">
<ng-container *ngTemplateOutlet="nestedList; context: { $implicit: link.children }"></ng-container>
</ul>
</li>
</ng-template>
<ng-container *ngTemplateOutlet="nestedList; context: { $implicit: links }"></ng-container>
</ul>
Upvotes: 2