从动态创建的子组件向父组件发出事件

Posted

技术标签:

【中文标题】从动态创建的子组件向父组件发出事件【英文标题】:Emit event from dynamically created child component to parent component 【发布时间】:2019-08-10 13:46:13 【问题描述】:

我有一个滑块,其中是动态创建的项目 - 这些是子组件。

滑块的 ng-container 所在的父模板:

<div id="slider-wrapper">
    <ng-container appSliderForm *ngFor="let question of questionsInSlider"
                          [questionTest]="question" (onRemove)="removeQuestion($event)">
    </ng-container>
</div>

这些子组件由 appSliderForm 指令创建:

@Directive(
  selector: '[appSliderForm]'
)
export class FormSliderDirective implements OnInit 

  @Input()
  questionTest: QuestionInSlider;

  constructor(private resolver: ComponentFactoryResolver, private container: ViewContainerRef) 

  ngOnInit(): void 
    const factory = this.resolver.resolveComponentFactory<TestQuestionInSliderComponent>(TestQuestionInSliderComponent);
    const component = this.container.createComponent(factory);
    component.instance.questionTest = this.questionTest;
    component.instance.ref = component;
  


在我的子组件中,我有一个 remove 函数,用于将自身从滑块中移除。

@Component(
  selector: 'app-test-question-in-slider',
  templateUrl: './test-question-in-slider.component.html',
  styleUrls: ['./test-question-in-slider.component.less']
)
export class TestQuestionInSliderComponent 

  questionTest: QuestionInSlider;

  ref: any;

  @Output() public onRemove = new EventEmitter<QuestionInSlider>();

  constructor(private builderService: FormBuilderService) 

  /**
   * Chosen question from slider will be displayed.
   */
  choose(): void 
    this.questionTest.chosen = true;
    this.builderService.handlerQuestionFromSlider(this.questionTest);
  

  remove(): void 
    this.onRemove.emit(this.questionTest);
    this.ref.destroy();
  

  isChosen() 
    return 'chosen': this.questionTest.chosen;
  

  getBorderTopStyle() 
     return 'border-top': `4px solid $this.questionTest.color`;
  


当通过单击子组件模板中的删除图标调用此删除函数时,我想发出事件以告知父组件以进行其他操作,但函数 removeQuestion 在父组件中没有被调用。

你能告诉我为什么不调用这个 removeQuestion 函数吗?

removeQuestion(question: QuestionInSlider) 
    console.log(question);
  

更新

我在 chrome 浏览器中对其进行了调试,当 emit 函数运行时,我发现我的 onRemove EventEmitter 对象的观察者数组属性中没有任何值在 onRemove 对象上调用。

this.onRemove.emit(this.questionTest);

【问题讨论】:

【参考方案1】:

问题是FormSliderDirective 没有onRemove 事件。要使您的代码正常工作,您需要将事件添加到指令中并将其订阅到内部组件的事件。因此,每当内部事件触发时,它都会传播到外部。

这是一个如何将其添加到指令中的示例:

@Directive(
  selector: '[appSliderForm]'
)
export class FormSliderDirective implements OnInit 

  @Input() questionTest: QuestionInSlider;
  @Output() public onRemove = new EventEmitter<QuestionInSlider>();

  constructor(private resolver: ComponentFactoryResolver, private container: ViewContainerRef) 

  ngOnInit(): void 
    const factory = this.resolver.resolveComponentFactory<TestQuestionInSliderComponent>(TestQuestionInSliderComponent);
    const component = this.container.createComponent(factory);
    component.instance.questionTest = this.questionTest;
    component.instance.onRemove.subscribe(this.onRemove); // this connects the component event to the directive event
    component.instance.ref = component;
  


【讨论】:

很抱歉回复晚了。对于您的解决方案,这对我不起作用。我已经对其进行了调试,发现我在 TestQuestionInSliderComponent 中初始化的 onRemove EventEmitter 对象的属性 observers 是空数组。它不应该包含任何值? 好的,谢谢你推我。感谢您,我找到了解决方案。只需要扭转您的解决方案。 抱歉我的回复晚了。很高兴你想出来了。我犯了一个错误,当您发现您需要切换订阅时。我已经更新了我的答案。您可以直接订阅,因为 EventEmitters 是主题。【参考方案2】:

在应用@AlesD 的解决方案后发生同样的错误时,也许它会对您有所帮助:

ERROR TypeError: Cannot read property 'subscribe' of undefined

解决方法对我有用:

component.instance.onRemove = this.onRemove;

【讨论】:

以上是关于从动态创建的子组件向父组件发出事件的主要内容,如果未能解决你的问题,请参考以下文章

Vue3 监听来自动态创建的子组件的事件,$on 替换

Vue.js - 如何在数据对象更改时向父组件发出?

从结构指令向父组件发出事件不起作用

从动态创建的子组件更改状态 - React

Vuejs 3 从子组件向父组件发出事件

子组件向父组件发出,父组件更新所有子组件