【问题标题】:Angular 2: Immediate parent component not listening to events emitted by child componentAngular 2:直接父组件不监听子组件发出的事件
【发布时间】:2017-07-09 03:20:19
【问题描述】:

我有一个基本的 Angular 应用程序,包含以下 3 个组件:

  1. car-component 是主组件或父组件。
  2. carousel-component(car-component 的子组件,*使用 ng-content)
  3. 子组件(轮播组件的子组件)

子组件内的按钮在单击时使用 EventEmitter() 发出事件。从 plunker 中的代码可以看出,汽车组件(即主组件或主组件)能够监听并捕获其 child 的子组件(即 child -component.ts) 和 {{text}} 在汽车组件模板中更新。

但是,carousel-component 是子组件的直接父级未能捕获相同的事件,并且在 carousel-component 内没有更新任何文本。 p>

car-component.ts

import  {Component} from 'angular2/core';
import {CarouselComponent} from './carousel-component';
import {Child} from './child.component';

@Component({
    selector: 'my-app',
    template: `
              <div style="border:1px solid #CCC; padding: 5px; margin: 5px;">
                car-comp txt: {{text}}
                <carousel-component>
                    <child (changed)="onChange($event)"></child>
                </carousel-component>
              </div>
    `,
    directives : [Child, CarouselComponent]
})
export class CarComponent {

    text: string = '?';

    onChange(value) {
        console.log('car-component onChange fn..');
       this.text = value;
    }

}

carousel-component.ts

import  {Component, EventEmitter} from 'angular2/core';
import {Output} from 'angular2/core';

@Component({
    selector: 'carousel-component',
    template: `
                <div style="background: #CCC; padding: 10px;">
                <div>carousel-component txt: {{carouselTxt}}</div>
                <ng-content></ng-content>
                </div>
             `,
})
export class CarouselComponent {

    carouselTxt: string = '?';

    changed = new EventEmitter();

    onChange(value) {
        console.log('carousel-comp onChange called..');
        this.carouselTxt = value;
    }

}

child.component.ts

import  {Component, EventEmitter} from 'angular2/core';
import {Output} from 'angular2/core';

@Component({
    selector: 'child',
    template: `
                <div style="background: #FFF; padding: 10px;">
                child-comp txt: 
                <input type ="text" #textInput value="{{txt}}">
                <button (click)="onChange(textInput.value)">Emit</button>
                </div>
             `,
    outputs:['changed']
})
export class Child {

    txt: string = 'abc';

    changed = new EventEmitter();

    onChange(value) {
        this.txt = value;
        this.changed.emit(value);
    }

}

谁能告诉我我哪里出错了?

https://plnkr.co/edit/h9mjlo?p=preview

【问题讨论】:

  • 有人可以帮我解决这个问题吗?我现在正在使用主题(来自 rxjs)和服务类(@injectable)作为解决方法。无论如何,将不胜感激上述问题的任何建议或解决方案。谢谢。

标签: angular event-handling


【解决方案1】:

在 CarouselComponent 中使用 ContentChildren 和 ngAfterContentInit,无需添加服务“或”将模板移出汽车组件模板。

export class CarouselComponent {

    carouselTxt: string = '?';

    @ContentChildren(Child) childItems:QueryList<Child> = new QueryList<Child>();

    ngAfterContentInit () {
      this.childItems.toArray().forEach((item, n)=>{
        item.changed.subscribe(
          (val)=> { this.carouselTxt = val; },
          (e)=> { console.log('e::', e); },
          (c)=>{ console.log('c::', c); }
        );
      });
    }

}

解决方案:https://plnkr.co/edit/x2mO0r?p=preview

【讨论】:

    【解决方案2】:

    正如@Ricardo car-component 在最后一个答案中提到的那样,它有子组件的选择器。要监听 carousel-component 中的事件,请从 car-component 模板中删除子组件并将其添加到 carousel-component 模板中。并且您可以在轮播组件中再添加一个事件发射器,它将到达作为汽车组件的父级。您可以通过 onChange() 函数触发的那个事件

    【讨论】:

    • 我正在尝试使轮播组件可与任何类型的发出“已更改”EventEmitter() 的子组件重用,并且每个子组件都可以包含许多不同的其他方法。将特定子组件添加到轮播组件中将使轮播组件不可重用。 car-component 决定要添加的子组件的数量,carousel-component 应该只观察其所有子组件的变化并做出相应的反应,而不依赖于其父组件。希望这是有道理的。
    【解决方案3】:

    在您的汽车组件中,您正在监听孩子的事件发生变化并将其绑定到 onChange。由于这是在您的汽车组件模板中,因此它仅将其绑定到汽车组件的 onChange 方法,而不是轮播组件的。

    要使子组件的更改事件对其所有分层父级可见,请创建一个所有父级都订阅的服务。可以在此处找到有关如何执行此操作的指南:https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

    【讨论】:

    • 感谢您的建议,我想避免引入仅用于跟踪子事件到父事件(冒泡)的服务。反正我会调查的。
    猜你喜欢
    • 1970-01-01
    • 2021-11-02
    • 2016-10-07
    • 2017-06-03
    • 2022-10-27
    • 1970-01-01
    • 2020-04-28
    • 2018-09-30
    • 2019-04-11
    相关资源
    最近更新 更多