2016-01-15 4 views
5

親ディレクティブ内に子ディレクティブを持つ一般的な角1.xパターンを角2で実装したいと思います。角2の子コンポーネントイベントが親にブロードキャストされる

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

これらBarコンポーネントはFooコンポーネントに放出されますクリックイベントを持っているため、私はしたいと思います。

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

そして、ここにある私のBar

はここで、これまでの私の Foo

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

私はそのBarsの1がクリックされるたびにFooを知らせる行くにはどうすればよいですか?

+2

。 「@Output()」または[この例のような]サービスを介して(http://stackoverflow.com/a/34576997/1876949) – Sasxa

+0

@Sasxaあなたは明確にすることができますか? @Output()を子から親に使う方法を知っていますが、実際に子コンポーネントに属性を置くことができる場合のみです。私はそれをユーザー定義の子で動的に行う方法を知らない。 – Harangue

+1

tbh、私は '@Output()'をあまり使っていませんでした...私はサービスを好む、私は両方のクラスでインポートし、エミッタの同じインスタンスを要求し、emit/subscribeを登録します。分の例を作成するには... – Sasxa

答えて

5

他の答えは解決するのが非常に貧弱な仕事をしていません問題。 EventEmittersは@Outputsと組み合わせて使用​​することのみを目的としていますが、この問題はAngular 2またはRxJSの機能に組み込まれた依存性注入を利用しません。

具体的には、DIを使用しないことで、静的クラスに依存するコンポーネントを再利用すると、同じイベントがすべて受信されるというシナリオに陥ります。

DIを利用することにより、以下の例を見てみてください、より柔軟な使用を可能、など面白い命名スキームの必要性を回避、同じクラスを複数回提供することは容易です。複数のイベントが必要な場合は、不透明トークンを使用してこの単純クラスの複数のバージョンを提供できます。

実施例:あなたはFooのコンポーネントで、 `()`)バー、および `.subscribe(中.emit`に持つEventEmitterの方法を使用することができます http://plnkr.co/edit/RBfa1GKeUdHtmzjFRBLm?p=preview

// The service 
import 'rxjs/Rx'; 
import {Subject,Subscription} from 'rxjs/Rx'; 

export class EmitterService { 
    private events = new Subject(); 
    subscribe (next,error,complete): Subscriber { 
    return this.events.subscribe(next,error,complete); 
    } 
    next (event) { 
    this.events.next(event); 
    } 
} 

@Component({ 
    selector: 'bar', 
    template: ` 
    <button (click)="clickity()">click me</button> 
    ` 
}) 
export class Bar { 
    constructor(private emitter: EmitterService) {} 
    clickity() { 
    this.emitter.next('Broadcast this to the parent please!'); 
    } 
} 

@Component({ 
    selector: 'foo', 
    template: ` 
    <div [ngStyle]="styl"> 
     <ng-content></ng-content> 
    </div> 
    `, 
    providers: [EmitterService], 
    directives: [Bar] 
}) 
export class Foo { 
    styl = {}; 
    private subscription; 
    constructor(private emitter: EmitterService) { 
    this.subscription = this.emitter.subscribe(msg => { 
     this.styl = (this.styl.background == 'green') ? {'background': 'orange'} : {'background': 'green'}; 
    }); 
    } 
    // Makes sure we don't have a memory leak by destroying the 
    // Subscription when our component is destroyed 
    ngOnDestroy() { 
    this.subscription.unsubscribe(); 
    } 
} 
+1

https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service –

+0

これまで私はAngular 2で多くの時間を費やしてきましたが、これは正しい答えです。 – Harangue

13

@Output()デコレータを使用してサービスを使用できない場合は、サービスを使用してコンポーネント間でデータを送信できます。ここでは例です:

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]; 
    } 
} 

あなたが発するやイベントをサブスクライブする必要がどこにあなたがそれをインポートします。

// 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!'); 
    } 
} 

別の例:plunker

+0

これは、子 - >親通信に適しています。しかし、兄弟コンポーネントについてはどうですか? fooがbarの親ではなく、代わりに兄弟コンポーネントであるとしましょう。 fooの要素をクリックすると、barを更新する必要があります。一種のマスターディテールのシナリオですが、両方が同時にページに表示されます(iPadの分割ビューと考える)。 おそらくこれは独自の質問であるべきですが、私はAngular 2の兄弟コンポーネントの通信に関する情報の隣に見つかりました。 –

+0

このパターンはすばらしいです!私を助けるためにthx: – jebbie

+0

'unsubscribe()'を忘れないでください。 –

関連する問題