I'm building a stepper and am using "transclusion" with ng-content
to dynamically grab section
elements within the stepper tag. The stepper.component view works like this:
<ng-content select=".one"></ng-content>
<ng-content select=".two"></ng-content>
<ng-content select=".three"></ng-content>
Component usage looks like this:
<stepper>
<section class="one">content here<section>
<section class="two">content here<section>
<section class="three">content here<section>
</stepper>
However, I'd like to make it dynamic by recognizing the section elements automatically:
<ng-content *ngFor="let section of sections; index as i;" select="['section:nth-child(' + i + ')']"></ng-content>
How can I:
select
to target them incrementally?I would create a directive like:
@Directive({
selector: '[stepper-section]'
})
export class StepperSectionDirective {}
then add stepper-section
attribute to each of sections:
<stepper>
<section stepper-section>content here<section>
<section stepper-section>content here<section>
<section stepper-section>content here<section>
</stepper>
and finally make use of @ContentChildren
decorator to query all the sections:
@ContentChildren(StepperSectionDirective) sections: QueryList<StepperSectionDirective>;
If you want to loop through content and render it dynamically you can wrap your children with ng-template
and use ngTemplateOutlet
directive to render them in StepperComponent:
html
<app-stepper>
<ng-template stepper-section>Content 1</ng-template>
<ng-template stepper-section>Content 2</ng-template>
<ng-template stepper-section>Content 3</ng-template>
</app-stepper>
stepper-section.directive.ts
@Directive({
selector: '[stepper-section]'
})
export class StepperSectionDirective {
hidden = false;
constructor(public templateRef: TemplateRef<any>) {}
}
stepper.component.ts
@ContentChildren(StepperSectionDirective) sectionDirs: QueryList<StepperSectionDirective>;
stepper.component.html
<button *ngFor="let section of sections; index as i;"
[class.enabled]="activeSection === i" (click)="goTo(i)">
Step {{ i + 1 }}
</button>
<div class="content">
<ng-container *ngFor="let section of sections">
<ng-template *ngIf="!section.hidden"
[ngTemplateOutlet]="section.templateRef"></ng-template>
</ng-container>
</div>
The difference between these two approaches is that in the first case all child content gets rendered and we only manipulate display: none
to those steps we want to hide.
In the second approach we have more control on what we want to render and we render only one step at specific time.