typescript - Barnkomponenthendelser sendes til forelder


Jeg ønsker å implementere det vanlige Angular 1.x-mønsteret med å ha barndirektiver innenfor et foreldredirektiv i Angular 2. Her er min ønskede struktur.

<foo>
  <bar>A</bar>
  <bar>B</bar>
  <bar>C</bar>
</foo>

Jeg ønsker at disse Bar-komponentene skal ha click-hendelser som blir sendt videre til Foo-komponenten.

Her er min Foo så langt:

@Component({
  selector: 'foo',
  template: `
    <div>
      <ng-content></ng-content>
    </div>
  `
})
export class Foo {
   @ContentChildren(Bar) items: QueryList<Bar>;
}

Og her er min Bar:

@Component({
  selector: 'Bar',
  template: `
    <div (click)="clickity()">
      <ng-content></ng-content>
    </div>
  `
})
export class Bar {
  clickity() {
    console.log('Broadcast this to the parent please!');
  }
}

Hvordan går jeg frem for å varsle Foo hver gang en av dens Bars blir klikket?

Svar #1

Du kan bruke en tjeneste for å sende data mellom komponenter hvis du ikke kan gjøre det ved å bruke @Output() dekoratøren. Her er et eksempel:

import {EventEmitter} from 'angular2/core';

export class EmitterService {
  private static _emitters: { [channel: string]: EventEmitter<any> } = {};
  static get(channel: string): EventEmitter<any> {
    if (!this._emitters[channel]) 
      this._emitters[channel] = new EventEmitter();
    return this._emitters[channel];
  }
}

Du importerer det der du trenger å sende ut eller abonnere på en hendelse:

// foo.component.ts
import {EmitterService} from '../path/to/emitter.service'

class Foo {
  EmitterService.get("some_id").subscribe(data => console.log("some_id channel: ", data));
  EmitterService.get("other_id").subscribe(data => console.log("other_id channel: ", data));
}

// bar.component.ts
import {EmitterService} from '../path/to/emitter.service'

class Bar {

  onClick() {
    EmitterService.get("some_id").emit('you clicked!');
  }
  onScroll() {
    EmitterService.get("other_id").emit('you scrolled!');
  }
}

et annet eksempel: plunker

Svar #2

Hvorfor ikke bruke @ContentChildren?

i bar.component.ts eksponerer vi clicked-hendelsen

@Output() clicked = new EventEmitter<BarComponent>();
onClick(){
    this.clicked.emit(this);
}

i foo.component.ts abonnerer vi på click-hendelsen for hver

 @ContentChildren(BarComponent) accordionComponents: QueryList<BarComponent>;

 ngAfterViewInit() {
 this.accordionComponents.forEach((barComponent: BarComponent) => {
        barComponent.clicked.subscribe((bar: BarComponent) => doActionsOnBar(bar));           
    });
}

Relaterte artikler