Angular Material Stepper-如何动态创建要加载到步骤中的组件 [英] Angular Material Stepper - how to dynamically create components to load into steps

查看:274
本文介绍了Angular Material Stepper-如何动态创建要加载到步骤中的组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过许多类似的帖子,但没有一个对我有帮助.

I have seen a number of similar posts, but none help me.

我希望能够使用@ngFor创建组件,然后将其加载到材料步进器

I wish to be able to use @ngFor to create components to then load into steps of the Material Stepper

我一直在关注动态加载示例以及其他一些帖子(不完整),并提出以下建议.

I have been following an example of dynamic loading, and some other posts (which are incomplete), and come up with the following.

首先,我有许多要加载到步骤中的组件.它们除了字符串之外都是空的(例如,组件正在工作"

First I have a number of components I want to load into the steps. They are just empty apart from the string (eg "component is working"

例如

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
    ]
  }

标记:

<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.

So in markup above, I have the ngFor that I am having problems with.

包装器如下...

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);
  }
}

最后是它正在使用的指令.

and finally the directive it is using is..

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

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

  constructor(public viewContainerRef: ViewContainerRef) { }
}

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

So, I am trying to use the StepPageWrapperComponent to take each component as an input (item), and then use the componentFactoryResolver to create the conponent and then "attach" it to the directive in the template, ie pageDirective in <ng-template pageDirective></ng-template>

但是,当我运行它时,出现以下错误.

However, when I run this, I get the following error..

        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似乎只是一个字符串!

If I put a break point in StepPageWrapperComponent, this.item just seems to be a string!

因此,此字符串"step"是ngFor变量...

So, this string "step" is meant to be the ngFor variable...

但是它只是作为字符串而不是组件输入.

But it is just coming in as a string, rather than the component.

有人对我在这里做错的事情有任何想法吗,或者即使有更好的方法可以做到这一点?

Does anyone have any ideas on what I am doing wrong here, or even if there is a better way of doing this?

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

For any more details the source for this sample is can be cloned from https://github.com/pjc2007/wizard-stepper1.git

在此先感谢您的帮助!

[19年8月30日更新]

输入无效的原因是我将变量传递给输入时忘记了方括号.即我有

The reason the input was not working was I forgot the square brackets when passing the variable to the input.. ie I had

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

代替

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

现在我已经按预期将组件作为StepPageWrapperComponent的输入.

I now have the component as the input for StepPageWrapperComponent as expected.

所以,我的问题是执行行const componentFactory=this.componentFactoryResolver.resolveComponentFactory(this.item)

So, my problem now is the following error that is thrown when executing the line 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

这样做将此作为entryComponent

I do have this as an entryComponent

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

[UPDATE2 30 Aug 19]

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

Stepping into this.componentFactoryResolver.resolveComponentFactory, I see the following...

因此该组件似乎在地图中,但是map.get返回的是未定义的吗?

So the component seems to be in the map, but the map.get is returning undefined?

推荐答案

因此该组件似乎在地图中,但是map.get正在返回 未定义?

So the component seems to be in the map, but the map.get is returning undefined?

是的,这具有误导性.您正在传递类的实例,而不是类本身.

Yes, it's misleading. You're passing instance of class not class itself.

请考虑以下示例:

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

如您所见,输出非常相似,但是它们是两个不同的东西.

As you can see the output is quite similar but they are two different things.

因此解决方案是传递组件类型而不是组件实例:

So the solution is to pass component Type instead of component instance:

this.steps = [
  StepPage1Component,
  StepPage2Component,
  StepPage3Component
]

这篇关于Angular Material Stepper-如何动态创建要加载到步骤中的组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆