Angular Material Stepper - 如何动态创建组件以加载到步骤中

2024-03-23

我看过很多类似的帖子。我希望能够使用@ngFor创建组件然后加载到步骤中材料步进机 https://material.angular.io/components/stepper/overview

我一直在关注一个动态加载示例 https://stackblitz.com/edit/angular-1o5zma?file=src/app/hero-job-ad.component.ts,以及其他一些帖子(不完整),并提出以下内容。

首先,我有一些想要加载到步骤中的组件。除了字符串之外,它们只是空的(例如“组件正在工作”

eg

export class StepPage1Component implements OnInit, StepPage {
      constructor() { }
      ngOnInit() {
      }
}

所以我有 3 个。

“根”组件如下。

export class WizardStepperComponent implements OnInit {
  @ViewChild('stepper') private myStepper: MatStepper;
  totalStepsCount: number;

  public steps: StepPage[];

  constructor(private stepsService: StepPagesService) { 
    this.steps = [
      new StepPage1Component,
      new StepPage2Component,
      new StepPage3Component
    ]
  }

Markup:

<mat-horizontal-stepper #stepper>
  <mat-step *ngFor='let step of steps'>
    <app-step-page-wrapper item='step'></app-step-page-wrapper>
  </mat-step>     
</mat-horizontal-stepper>

<!-- second option -->
<div>
  <button (click)="goBack(stepper)" type="button" [disabled]="stepper.selectedIndex === 0">Back</button>
  <button (click)="goForward(stepper)" type="button"
    [disabled]="stepper.selectedIndex === stepper._steps.length-1">Next</button>

  <!-- using totalStepsCount -->
  <!-- <button (click)="goForward(stepper)" type="button" [disabled]="stepper.selectedIndex === totalStepsCount-1">Next</button> -->
</div>

所以在上面的标记中,我有ngFor我遇到了问题。

包装如下...

import { Component, OnInit, Input, ViewChild, ComponentFactoryResolver } from '@angular/core';
import { directiveDef } from '@angular/core/src/view';
import { PageDirective } from '../page.directive';

@Component({
  selector: 'app-step-page-wrapper',
  template: '<ng-template pageDirective></ng-template>',
})
export class StepPageWrapperComponent implements OnInit {
  @Input() item?: any;
  @ViewChild(PageDirective) pageHost: PageDirective;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngOnInit() {
    if (this.item == undefined) {
      console.error('Item undefined');
      return 
    }

    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.item);
    const viewContainerRef = this.pageHost.viewContainerRef;
    viewContainerRef.clear();
    const componentRef = viewContainerRef.createComponent(componentFactory);
  }
}

最后它使用的指令是..

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[pageDirective]'
})
export class PageDirective {

  constructor(public viewContainerRef: ViewContainerRef) { }
}

所以,我正在尝试使用StepPageWrapperComponent将每个组件作为输入(item),然后使用componentFactoryResolver创建组件,然后将其“附加”到模板中的指令,即pageDirective in <ng-template pageDirective></ng-template>

但是,当我运行这个时,我收到以下错误。

        ERROR Error: No component factory found for step. Did you add it to @NgModule.entryComponents?
        at noComponentFactoryError (core.js:9877)
        at CodegenComponentFactoryResolver.push../node_modules/@angular/core/fesm5/core.js.CodegenComponentFactoryResolver.resolveComponentFactory (core.js:9915)
        at StepPageWrapperComponent.push../src/app/step-page-wrapper/step-page-wrapper.component.ts.StepPageWrapperComponent.ngOnInit (step-page-wrapper.component.ts:21)
        at checkAndUpdateDirectiveInline (core.js:22099)
        at checkAndUpdateNodeInline (core.js:23363)
        at checkAndUpdateNode (core.js:23325)
        at debugCheckAndUpdateNode (core.js:23959)
        at debugCheckDirectivesFn (core.js:23919)
        at Object.eval [as updateDirectives] (WizardStepperComponent.html:3)
        at Object.debugUpdateDirectives [as updateDirectives] (core.js:23911)

如果我在其中放置一个断点StepPageWrapperComponent, this.item似乎只是一个字符串!

所以,这个字符串“step”应该是 ngFor 变量......

但它只是作为字符串而不是组件出现。

有谁对我在这里做错了什么有任何想法,或者即使有更好的方法来做到这一点?

有关更多详细信息,可以从以下位置克隆此示例的源https://github.com/pjc2007/wizard-stepper1.git https://github.com/pjc2007/wizard-stepper1.git

2019 年 8 月 30 日更新

输入不起作用的原因是我在将变量传递给输入时忘记了方括号。即我有

<app-step-page-wrapper item='step'></app-step-page-wrapper>

代替

    <app-step-page-wrapper [item]='step'></app-step-page-wrapper>

我现在将该组件作为输入StepPageWrapperComponent正如预期的那样。

所以,我现在的问题是执行该行时抛出以下错误const componentFactory=this.componentFactoryResolver.resolveComponentFactory(this.item)

ngComponent: StepPage1Component {}
message: "No component factory found for [object Object]. Did you add it to @NgModule.entryComponents?"
stack: "Error: No component factory found for [object Object]. Did you add it to @NgModule.entryComponents?↵    at noComponentFactoryError (http://localhost:4200/vendor.js:71338:17)↵    at CodegenComponentFactoryResolver.push../node_modules/@angular/core/fesm5/core.js.CodegenComponentFactoryResolver.resolveComponentFactory (http://localhost:4200/vendor.js:71376:19)↵    at StepPageWrapperComponent.push../src/app/step-page-wrapper/step-page-wrapper.component.ts.StepPageWrapperComponent.ngOnInit (http://localhost:4200/main.js:244:66)↵    at checkAndUpdateDirectiveInline (http://localhost:4200/vendor.js:83560:19)↵    at checkAndUpdateNodeInline (http://localhost:4200/vendor.js:84824:20)↵    at checkAndUpdateNode (http://localhost:4200/vendor.js:84786:16)↵    at debugCheckAndUpdateNode (http://localhost:4200/vendor.js:85420:38)↵    at debugCheckDirectivesFn (http://localhost:4200/vendor.js:85380:13)↵    at Object.eval [as updateDirectives] (ng:///AppModule/WizardStepperComponent.ngfactory.js:16:5)↵    at Object.debugUpdateDirectives [as updateDirectives] (http://localhost:4200/vendor.js:85372:21)"
__proto__: Object

I do将其作为 EntryComponent

ie

@NgModule({
  declarations: [
    AppComponent,
    WizardStepperComponent,
    StepPage1Component,
    StepPage2Component,
    StepPage3Component,
    PageDirective,
    StepPageWrapperComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatStepperModule,
    MatInputModule,
    MatButtonModule,
    MatAutocompleteModule
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [
    StepPage1Component,
    StepPage2Component,
    StepPage3Component,
    StepPageWrapperComponent
  ]

2019 年 8 月 30 日更新

步入this.componentFactoryResolver.resolveComponentFactory,我看到以下内容...

所以组件似乎在地图中,但 map.get 返回未定义?


所以该组件似乎在地图中,但 map.get 正在返回 不明确的?

是的,这是误导。您传递的是类的实例而不是类本身。

考虑以下示例:

class Test {}
console.log(Test);       // class Test {}
console.log(new Test()); // Test {}

正如您所看到的,输出非常相似,但它们是两个不同的东西。

所以解决方案是通过元件类型而不是组件实例:

this.steps = [
  StepPage1Component,
  StepPage2Component,
  StepPage3Component
]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular Material Stepper - 如何动态创建组件以加载到步骤中 的相关文章

随机推荐