Angular Material mat-stepper,如何将以编程方式创建的 componentRefs 正确传递给 mat-step?

问题描述 投票:0回答:1

我有一个问题请教, 我以编程方式创建了一些仅声明的组件,因此这些选择器根本不在任何模板中使用。我使用

ViewContainerRef.createComponent
来创建组件,每个创建结果都是一个
ComponentRef
。我把它们放入一个数组中。 我将
ComponentRef
数组传递到了包裹
mat-stepper
的组件中。我用数组做了一个
*ngFor
还可以,但是 如何将模板部分设置在
mat-step
下方? 在我看来,无论如何我都可以使用
ngTemplateOutlet
来做,只需要一个模板参考,如果我用
componentRef.instance
在我想要展示的页面下方捕获它,则可以来自
ViewChild
。 我不知道如何在
mat-step
下面设置来自
componentRef
的模板。

如果有人有任何想法可以与我分享吗?

提前谢谢您。

angular forms dynamic angular-material mat-stepper
1个回答
0
投票

这个想法是使用 *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>

© www.soinside.com 2019 - 2024. All rights reserved.