我有一个问题请教, 我以编程方式创建了一些仅声明的组件,因此这些选择器根本不在任何模板中使用。我使用
ViewContainerRef.createComponent
来创建组件,每个创建结果都是一个ComponentRef
。我把它们放入一个数组中。
我将 ComponentRef
数组传递到了包裹 mat-stepper
的组件中。我用数组做了一个 *ngFor
还可以,但是
如何将模板部分设置在mat-step
下方?
在我看来,无论如何我都可以使用 ngTemplateOutlet
来做,只需要一个模板参考,如果我用 componentRef.instance
在我想要展示的页面下方捕获它,则可以来自 ViewChild
。
我不知道如何在 mat-step
下面设置来自 componentRef
的模板。
如果有人有任何想法可以与我分享吗?
提前谢谢您。
这个想法是使用 *ngComponentOutlet 指令并传递输入,以便动态创建每个步骤。
这里附上我为您创建的完整示例:
import { Type, Component, input, output } from '@angular/core';
import { FormsModule, ReactiveFormsModule, FormGroup } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatStepper, MatStepperModule } from '@angular/material/stepper';
import { STEPPER_GLOBAL_OPTIONS, StepperSelectionEvent } from '@angular/cdk/stepper';
import { NgComponentOutlet } from '@angular/common';
export type StepperStepAction = {
label?: string;
action?: () => void;
}
export type StepperStep = {
title: string;
actions?: {
previous?: StepperStepAction;
next?: StepperStepAction;
}
component: Type<any>;
inputs?: {
[x: string]: any;
}
}
export type StepperStateEvent = number[];
@Component({
selector: 'app-step-a',
standalone: true,
template: '{{title()}}'
})
export class StepAComponent {
title = input.required<string>();
}
@Component({
selector: 'app-stepper',
standalone: true,
imports: [
MatStepperModule,
NgComponentOutlet,
FormsModule,
ReactiveFormsModule,
FormGroup,
MatButtonModule
],
providers: [{
provide: STEPPER_GLOBAL_OPTIONS, useValue: { displayDefaultIndicatorType: false }
},
{
provide: STEPPER_GLOBAL_OPTIONS,
useValue: { showError: true }
}],
templateUrl: './stepper.component.html'
})
export class StepperComponent {
steps = input([
title: 'title',
component: StepAComponent,
inputs: {
title: 'step 1 title'
}
]);
selectionChange = output<StepperStateEvent>();
defaultFormGroup!: FormGroup;
nextLabel: string = `Next`;
previousLabel: string = `Back`;
onSelectionChange(event: StepperSelectionEvent) {
const stepperState = [event.previouslySelectedIndex, event.selectedIndex];
this.selectionChange.emit(stepperState);
}
previous(stepper: MatStepper, step:StepperStep){
if(!step.actions?.previous?.action){
stepper.previous();
}
else {
step.actions?.previous?.action();
}
}
next(stepper: MatStepper, step:StepperStep){
if(!step.actions?.next?.action){
stepper.next();
}
else {
step.actions?.next?.action();
}
}
}
<mat-stepper labelPosition="bottom"
#stepper
[disableRipple]="true"
linear
(selectionChange)="onSelectionChange($event)">
@for(step of steps(); track $index){
<mat-step [stepControl]="step.inputs?.form || defaultFormGroup">
<ng-template matStepContent>
<ng-container *ngComponentOutlet="step.component;inputs: step.inputs;"/>
<div class="text-align--center">
<button (click)="next(stepper, step)"
mat-flat-button
class="primary"
color="primary">
<span>{{step.actions?.next?.label || nextLabel}}</span>
</button>
</div>
<div>
<button mat-button
color="primary"
(click)="previous(stepper, step)">
<mat-icon>arrow_right_alt</mat-icon>
<span>{{step.actions?.previous?.label || previousLabel}}</span>
</button>
</div>
</ng-template>
<ng-template matStepLabel>{{step.title}}</ng-template>
</mat-step>
}
@for(template of ['edit','error','number','done']; track $index){
<ng-template [matStepperIcon]="template"
let-i="index"
let-active="active">{{i+1}}</ng-template>
}
</mat-stepper>