【问题标题】:How to catch a dynamic rendered component's output in Angular 8?如何在 Angular 8 中捕获动态渲染组件输出?
【发布时间】:2020-05-03 18:10:08
【问题描述】:

我想捕捉来自ViewChild 渲染组件的输出。在ngIf 触发后显示的 ViewChild 的内容。

这是我的模板代码:

<div *ngIf="isModalVisible" class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <!-- ... -->
      </div>
      <div class="modal-body">
        <ng-template #dialogHost (saveModel)="setModel($event)"></ng-template>
      </div>
    </div>
  </div>
</div>

这是 TypeScript 文件:

import { ChangeDetectorRef, Component, ComponentFactoryResolver, Input, ViewChild, ViewContainerRef } from '@angular/core';
import { DialogContentItem } from 'src/app/models/dialog/content/dialog-content-item';

@Component({
  selector: 'app-dialog-preparator',
  templateUrl: './dialog-preparator.component.html',
  styleUrls: ['./dialog-preparator.component.css']
})
export class DialogPreparatorComponent {
  isModalVisible = false;
  @Input() dialogContent: DialogContentItem;
  @ViewChild('dialogHost', {static: false, read: ViewContainerRef}) dialogHost: ViewContainerRef;

  showModal() {
    this.isModalVisible = true;
    this.changeDetector.detectChanges();
    this.renderComponent();
  }

  renderComponent() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.dialogContent.component);

    this.dialogHost.clear();

    const componentRef = this.dialogHost.createComponent(componentFactory);
    (componentRef.instance as DialogContentInterface).data = this.dialogContent.data;
  }

  setModel(model: any) {
    // I need to emit the model
  }
}

这里是 ProcutCreateEditComponent:

<app-dialog-preparator [dialogContent]="userDialogContent"></app-dialog-preparator>

该组件的 TypeScript 代码:

import { Component } from '@angular/core';
import { UserCreateEditComponent } from 'src/app/components/user/user-create-edit.component';

@Component({
  selector: 'app-product-create-edit',
  templateUrl: './product-create-edit.component.html',
  styleUrls: ['./product-create-edit.component.scss']
})
export class ProductCreateEditComponent {
  // this could be any other component in my software
  userDialogContent: DialogContentItem = new DialogContentItem(UserCreateEditComponent, {});

  constructor() {}

  // ...
}

这里是 UserCreateEditComponent 的 TypeScript 代码:

import { Component, Output } from '@angular/core';

@Component({
  selector: 'app-user-create-edit',
  templateUrl: './user-create-edit.component.html',
  styleUrls: ['./user-create-edit.component.scss']
})
export class UserCreateEditComponent {
  @Output() saveModel: EventEmitter<T> = new EventEmitter();
  user = new User();

  constructor() {}

  save() {
    this.saveModel.emit(this.user);
  }
}

所以在 ProcutCreateEditComponent 中我创建了一个 UserCreateEditComponent 的实例并将这个实例传递给 DialogPreparatorComponent。 DialogPreparatorComponent 在对话框中显示 UserCreateEditComponent,然后单击保存按钮(在 UserCreateEditComponent 中),saveModel() 发送到 DialogPreparatorComponent。我想......但不是这个,我收到了这个错误消息:

Event binding saveModel not emitted by any directive on an embedded template.
Make sure that the event name is spelled correctly and all directives are
listed in the "@NgModule.declarations". ("
      </div>
      <div class="modal-body">
        <ng-template #dialogHost [ERROR ->](saveModel)="setModel($event)"></ng-template>
      </div>
    </div>

其实很好,因为ng-template 没有saveModel() 输出。

但是我怎样才能捕捉到 UserCreateEditComponent 的输出呢?

【问题讨论】:

    标签: angular typescript angular-components eventemitter angular-event-emitter


    【解决方案1】:

    由于您在代码中创建组件,因此您无法在模板中添加事件处理程序,您必须在创建组件时也将其添加到组件代码中。

    例如,您可以更改渲染组件方法以添加订阅。

    renderComponent() {
      const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.dialogContent.component);
    
      this.dialogHost.clear();
    
      const componentRef = this.dialogHost.createComponent(componentFactory);
      (componentRef.instance as DialogContentInterface).data = this.dialogContent.data;
      (componentRef.instance as DialogContentInterface).saveModel.subscribe((model) => this.setModel(model));
    }
    

    我希望我正确理解了您的模型,并且您在此处创建的组件是具有输出属性的组件。

    确保在销毁动态组件时也取消订阅,这样您就不会因为剩余订阅而导致内存泄漏。

    【讨论】:

      猜你喜欢
      • 2018-12-29
      • 2020-01-31
      • 2018-02-06
      • 2015-09-07
      • 2021-04-15
      • 1970-01-01
      • 2020-11-23
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多