如何从 ViewContainerRef.get() 获取动态创建的组件的 Component 实例

Edw*_*ard 5 dynamic angular viewchildren

我正在努力完成的总结

  • 动态添加组件到一个ViewContainerRef(完成)
  • 使用属性初始化这些动态组件(完成)
  • 访问动态创建的 Component 实例,以便我可以根据实际情况做出决定。

问题

  • 动态添加组件时,它们被添加到 ViewContainerRef
  • ViewContainerRef提供方法,例如get(index)return ViewRef
  • ViewRef似乎与Component实例没有任何关系,这使得获取所需数据成为一项挑战

这是一个 Stackblitz 链接,其工作代码如下所示(用于动态创建组件)

appComponent通过创建使用一些部件开始了ComponentFactoryResolver,并且将它们添加到ViewChild在模板中所定义。每个DynamicComponent都使用id我们在创建后尝试引用的属性值进行初始化

@Component({
  selector: "my-app",
  template: `
    <h3>Retrieving Component Reference for Dyamic Compnents</h3>
    <button (click)="getCompRef()">Get References</button>
    <div>
      <ng-container #childCont></ng-container>
    </div>
    <div>
      <small>List out the Ids from the dynamic components</small> <br />
      {{ createdItemIds | json }}
    </div>
  `,
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements AfterViewInit {
  @ViewChild("childCont", { read: ViewContainerRef })
  childCont: ViewContainerRef;

  createdItemIds: string[] = [];

  itemLimit = 5;

  constructor(
    private fr: ComponentFactoryResolver,
    private cdr: ChangeDetectorRef
  ) {}

  ngAfterViewInit(): void {
    for (let i = 0; i < this.itemLimit; i++) {
      const factory = this.fr.resolveComponentFactory(DynamicComponent);
      const compRef = this.childCont.createComponent(factory, i);
      // Set the id of the instance so that we can use it later
      compRef.instance.id = i + 1;
      this.cdr.detectChanges();
    }
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

DynamicComponent添加之中是相当简单的。为简化起见,它只包含id我们试图获取的单个属性

@Component({
  selector: "dynamic-component",
  template: `
    <div>Dynamic Component: {{ id }}</div>
  `,
  styles: [``]
  ]
})
export class DynamicComponent {
  id: number;
} 
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都很好。

  • 组件是动态创建的
  • 组件实例用ID初始化,我们可以通过它在UI中显示的胖子看到

问题在于尝试从 DynamicallyCreated 组件中检索 ID 属性。

在 中AppComponent,当用户单击按钮时,该getCompRef()方法被调用并循环遍历childCont (ViewContainerRef)

getCompRef(): void {
  for (let i = 0; i < this.itemLimit; i++) {
    const viewRef = this.childCont.get(i);
    // How do I get at the instance of the view  in order to obtain id?
    // the view Ref doesn't provide access to the instance
    // console.log(viewRef);
  }
}
Run Code Online (Sandbox Code Playgroud)

但是ViewRef返回的 fromViewContainerRef.get()是 的子类,ChangeDetectoreRef并且不包含对相关实例的任何引用。

在对此问题进行研究时,它尝试沿着使用ViewChildren来获取正在创建的列表组件的路径走下去,但这并没有奏效,因为诸如

  • https://github.com/angular/angular/issues/8785
  • 或示例假设在ViewChildren selectoris 中使用的指令用于已在模板中预定义的组件
  • 我看到很多关于一些人希望在他们拥有 时获得 ViewRef 的问题Component.instance,但这在这种情况下没有帮助。

最后我的问题是,

  • 有没有一种简单的方法可以从ViewRef我缺少的 Component 实例中获取

任何帮助表示赞赏。

谢谢你。

Jon*_*ira 1

我只能通过跟踪不同数组中这些组件的实例来做到这一点。

@Component({
  selector: "my-app",
  template: `
    <h3>Retrieving Component Reference for Dyamic Compnents</h3>
    <button (click)="getCompRef()">Get References</button>
    <div>
      <ng-container #childCont></ng-container>
    </div>
    <div>
      <small>List out the Ids from the dynamic components</small> <br />
      {{ createdItemIds | json }}
    </div>
  `,
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements AfterViewInit {
  @ViewChild("childCont", { read: ViewContainerRef })
  childCont: ViewContainerRef;

  createdItemIds: string[] = [];

  itemLimit = 5;
  private dynamicComponentsArray: ComponentRef<DynamicComponent>[] = [];

  constructor(
    private fr: ComponentFactoryResolver,
    private cdr: ChangeDetectorRef
  ) {}

  ngAfterViewInit(): void {
    for (let i = 0; i < this.itemLimit; i++) {
      const factory = this.fr.resolveComponentFactory(DynamicComponent);
      const compRef = this.childCont.createComponent(factory, i);
      // Set the id of the instance so that we can use it later
      compRef.instance.id = i + 1;
      this.dynamicComponentsArray.push(compRef);
      this.cdr.detectChanges();
    }
  }
  
  getCompRef(): void {
      for (let i = 0; i < this.itemLimit; i++) {
        const viewRef = this.childCont.get(i);
        if (this.dynamicComponentsArray.length > 0) {
            for (let i = 0; i < this.dynamicComponentsArray.length; i++) {
                const componentRef = this.dynamicComponentsArray[i];
                const component = (componentRef) as ComponentRef<DynamicComponent>;
                let value = component.instance.id;
            }
        }
      }
    }
}
Run Code Online (Sandbox Code Playgroud)