【问题标题】:Angular 2: How do I emit an event up through multiple nested components?Angular 2:如何通过多个嵌套组件发出事件?
【发布时间】:2017-03-21 04:24:20
【问题描述】:

我有一个名为 ItemsComponent 的“智能”组件和两个嵌套的“哑”组件,ItemsListComponentItemComponent

ItemsComponent 的 html 模板包含 ItemsListComponent

// ItemsComponent
<div>
  // ItemsListComponent
  <app-items-list
    [items]="items"
    (doDelete)="deleteItem($event)"
  >
  </app-items-list>
<div>

它有一个名为deleteItem的函数:

deletItem(item) {
  // code to handle item deletion...
}

ItemsListComponent 包含 ItemComponent

// ItemsListComponent    
<ul *ngFor="let item of items">
  // ItemComponent
  <app-item
   [item]="item"
   (doDelete)="deleteItem($event)"
  >
  </app-item>
</ul>

所以html结构是这样的:

ItemsComponent (app-items)
    - ItemsListComponent (app-items-list)
        - ItemComponent (app-item)

ItemComponent有一个按钮

<button (click)="deleteItem(item)">

以及deleteItem的事件发射器:

@Output() doDelete = new EventEmitter();

deleteItem(item) {
  this.doDelete.emit(item);
}

当在 ItemComponent 中单击删除按钮时,事件只会冒泡到它的直接父级 ItemsListComponent,但不会到达 ItemsComponent 除非我将相同的事件发射器功能添加到 ItemsListComponent

臭臭ItemsListComponent

@Output() doDelete = new EventEmitter();

deleteItem(item) {
  this.doDelete.emit(item);
}

它以这种方式工作,但是 ItemsListComponent 现在与 ItemsComponent 共享代码气味,因为它们都具有相同的事件发射器内容,并且必须将事件从一个组件传递到另一个正在上升。

有没有更好的方法来做到这一点?

【问题讨论】:

标签: angular


【解决方案1】:

正如您所意识到的,自定义角度事件不会冒泡,因此如果您有一个深度嵌套的组件并且您想将事件传递给更高的组件,则中间的每个组件都必须向上委托事件。

另一种选择是将您的deleteItem 功能移动到注入到您的较低级别组件之一的服务中。这样一来,函数就可以在它发生的时候被调用,而不必将事件冒泡到你的视图层次结构中。

【讨论】:

    【解决方案2】:

    实际上,您可以使用CustomEvent 而不是EventEmitter 来实现。这只是一种解决方法,特别是因为 Angular 通信模式在 Angular documentation 和许多其他 places 中有很好的描述。

    基本上,您需要从内部子级触发CustomEvent,并在最外层组件(祖父母)上简单地监听它。

    最外层组件

    @Component({
     selector: 'outermost',
     template: `<child></child>`
    })
    export class OutermostComponent {
          @HostListener('FormSubmitCustomEvent', ['$event'])
          onCustomEventCaptured(event: any) {
            console.log('Event Received', event.detail);
          }
    }
    

    子组件

    @Component({
      selector: 'child',
      template: `<inner-child></inner-child>`
    })
    export class ChildComponent {
       
    }
    

    InnerChildComponent

    @Component({
      selector: 'inner-child',
      template: `<button (click)="onSubmit()"></button>`
    })
    export class InnerChildComponent {
    
    constructor(private elementRef: ElementRef) {}
    
    onSubmit(): void {
        const event: CustomEvent = new CustomEvent('FormSubmitCustomEvent', {
          bubbles: true,
          detail: { data: 'Hello from Inner Child' }
        });
    
        this.elementRef.nativeElement.dispatchEvent(event);
      }
    }
    

    这是一个有效的闪电战:https://stackblitz.com/edit/angular-5wv8p5

    【讨论】:

      猜你喜欢
      • 2016-08-04
      • 2018-10-18
      • 2020-09-17
      • 2015-12-10
      • 1970-01-01
      • 2018-02-13
      • 2018-04-16
      • 2018-06-01
      • 1970-01-01
      相关资源
      最近更新 更多