2016-08-02 14 views
11

से आरएक्सजेएस अवलोकन योग्य स्ट्रीम कैसे बनाएं मैं आरएक्सजेएस 5.0.0-बीटा 6 के साथ कोणीय 2.0.0-आरसी.4 का उपयोग कर रहा हूं।एंगुलर 2 घटक टेम्पलेट बाल तत्व घटना

मैं घटनाओं से देखने योग्य धाराओं के निर्माण के विभिन्न तरीकों के साथ प्रयोग कर रहा हूं, लेकिन विकल्पों से अभिभूत हूं और राय को कैनवास करना चाहता हूं। मुझे खुशी वहाँ कोई एक आकार फिट सभी समाधान है और वहाँ पाठ्यक्रमों के लिए घोड़े हैं। संभवतः अन्य तकनीकों के बारे में मैं नहीं जानता या नहीं पर विचार किया जा सकता है।

Angular 2 component interaction cookbook एक बच्चे घटक घटक के साथ बातचीत करने वाले मूल घटक के कई तरीकों को प्रदान करता है। हालांकि, केवल parent and children communicate via a service का उदाहरण observables उपयोग करता है और यह सबसे परिदृश्यों के लिए overkill की तरह लगता है।

परिदृश्य यह है कि एक टेम्पलेट का तत्व घटनाओं की एक बड़ी मात्रा को उत्सर्जित करता है और मैं जानना चाहता हूं, समय-समय पर, सबसे हाल का मूल्य क्या है।

मैं 1000ms की अवधि के साथ Observable के sampleTime विधि का उपयोग एक <p> HTML तत्व पर माउस स्थान पर नजर रखने के।

1) यह तकनीक ElementRef का उपयोग nativeElement संपत्ति तक पहुंचने के लिए घटक के कन्स्ट्रक्टर में इंजेक्शन और टैग नाम से बाल तत्वों से पूछताछ करती है।

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <p>Move over me!</p> 
    <div *ngFor="let message of messages">{{message}}</div> 
    ` 
}) 
export class WatchChildEventsComponent implements OnInit { 
    messages:string[] = []; 

    constructor(private el:ElementRef) {} 

    ngOnInit() { 
    let p = this.el.nativeElement.getElementsByTagName('p')[0]; 
    Observable 
     .fromEvent(p, 'mousemove') 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
     }); 
    } 
} 

आम सहमति राय इस तकनीक पर भ्रूभंग क्योंकि Angular2 ताकि आप शायद ही कभी, अगर कभी, इसके साथ सीधे बातचीत करने के लिए की जरूरत है डोम के ऊपर एक पर्याप्त अमूर्त प्रदान करता है लगता है। लेकिन उस Observable की fromEvent कारखाने विधि यह नहीं बल्कि आकर्षक उपयोग करने के लिए बनाता है और यह पहली तकनीक है कि दिमाग में आया था।

2) यह तकनीक EventEmitter का उपयोग करती है, जो Observable है।

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <p (mousemove)="handle($event)">Move over me!</p> 
    <div *ngFor="let message of messages">{{message}}</div> 
    ` 
}) 
export class WatchChildEventsComponent implements OnInit { 
    messages:string[] = []; 
    emitter:EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>(); 

    ngOnInit() { 
    this.emitter 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
     }); 
    } 

    handle(e:MouseEvent) { 
    this.emitter.emit(e); 
    } 
} 

यह समाधान डोम क्वेरी करने से बचा जाता है, लेकिन घटना उत्सर्जक माता-पिता के लिए बच्चे से संवाद करने के लिए उपयोग किया जाता है, और इस घटना उत्पादन के लिए नहीं है।

मैंने here पढ़ा है कि यह नहीं माना जाना चाहिए कि अंतिम उत्सव में ईवेंट उत्सर्जक अवलोकन योग्य होंगे, इसलिए यह भरोसा करने के लिए एक स्थिर सुविधा नहीं हो सकती है।

3) यह तकनीक एक अवलोकन योग्य Subject का उपयोग करती है।

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <p (mousemove)="handle($event)">Move over me!</p> 
    <div *ngFor="let message of messages">{{message}}</div> 
    ` 
}) 
export class WatchChildEventsComponent implements OnInit { 
    messages:string[] = []; 
    subject = new Subject<MouseEvent>(); 

    ngOnInit() { 
    this.subject 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
     }); 
    } 

    handle(e:MouseEvent) { 
    this.subject.next(e); 
    } 
} 

यह समाधान मेरी जटिलता में बिना किसी जटिलता को जोड़ने के सभी बक्से लगाता है। मैं एक ReplaySubject का उपयोग प्रकाशित मूल्यों के पूरे इतिहास में, अगर यह मौजूद है, subject = new ReplaySubject<MouseEvent>(1); बजाय साथ जब मैं यह करने के लिए अभी हाल ही में एक सदस्यता लेते हैं, या प्राप्त करने के लिए कर सकता है।

4) यह तकनीक @ViewChild सजावट के संयोजन के साथ टेम्पलेट संदर्भ का उपयोग करती है।

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <p #p">Move over me!</p> 
    <div *ngFor="let message of messages">{{message}}</div> 
    ` 
}) 
export class WatchChildEventsComponent implements AfterViewInit { 
    messages:string[] = []; 
    @ViewChild('p') p:ElementRef; 

    ngAfterViewInit() { 
    Observable 
     .fromEvent(this.p.nativeElement, 'mousemove') 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
     }); 
    } 
} 

यह काम करता है, यह मेरे लिए थोड़ा गंध करता है। खाका संदर्भ एक टेम्पलेट के भीतर घटक बातचीत के लिए मुख्य रूप से कर रहे हैं। यह nativeElement के माध्यम से डीओएम को भी छूता है, ईवेंट नाम और टेम्पलेट संदर्भ को संदर्भित करने के लिए स्ट्रिंग का उपयोग करता है, और AfterViewInit लाइफसाइकिल हुक का उपयोग करता है।

5) मैंने एक कस्टम घटक का उपयोग करने के लिए उदाहरण बढ़ाया जो Subject प्रबंधित करता है और समय-समय पर एक ईवेंट उत्सर्जित करता है।

@Component({ 
    selector: 'child-event-producer', 
    template: ` 
    <p (mousemove)="handle($event)"> 
     <ng-content></ng-content> 
    </p> 
    ` 
}) 
export class ChildEventProducerComponent { 
    @Output() event = new EventEmitter<MouseEvent>(); 
    subject = new Subject<MouseEvent>(); 

    constructor() { 
    this.subject 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.event.emit(e); 
     }); 
    } 

    handle(e:MouseEvent) { 
    this.subject.next(e); 
    } 
} 

यह इस तरह माता-पिता द्वारा किया जाता है:

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <child-event-producer (event)="handle($event)"> 
     Move over me! 
    </child-event-producer> 
    <div *ngFor="let message of messages">{{message}}</div> 
    `, 
    directives: [ChildEventProducerComponent] 
}) 
export class WatchChildEventsComponent { 
    messages:string[] = []; 

    handle(e:MouseEvent) { 
    this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
    } 
} 

मैं इस तकनीक की तरह; कस्टम घटक वांछित व्यवहार को समाहित करता है और माता-पिता के उपयोग के लिए यह आसान बनाता है, लेकिन यह केवल घटक पेड़ को संचारित करता है और भाई बहनों को सूचित नहीं कर सकता है।

6) इस तकनीक के साथ जो इस घटना के साथ बच्चे से माता-पिता को आसानी से आगे बढ़ाता है।

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <child-event-producer> 
     Move over me! 
    </child-event-producer> 
    <div *ngFor="let message of messages">{{message}}</div> 
    `, 
    directives: [ChildEventProducerComponent] 
}) 
export class WatchChildEventsComponent implements AfterViewInit { 
    messages:string[] = []; 
    @ViewChild(ChildEventProducerComponent) child:ChildEventProducerComponent; 

    ngAfterViewInit() { 
    Observable 
     .from(this.child.event) 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
     }); 
    } 
} 

7) या इस तरह::

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <child-event-producer (event)="handle($event)"> 
     Move over me! 
    </child-event-producer> 
    <div *ngFor="let message of messages">{{message}}</div> 
    `, 
    directives: [ChildEventProducerComponent] 
}) 
export class WatchChildEventsComponent implements OnInit { 
    messages:string[] = []; 
    subject = new Subject<MouseEvent>(); 

    ngOnInit() { 
    this.subject 
     .sampleTime(1000) 
     .subscribe((e:MouseEvent) => { 
     this.messages.push(`${e.type} (${e.x}, ${e.y})`); 
     }); 
    } 

    handle(e:MouseEvent) { 
    this.subject.next(e); 
    } 
} 

एक नमूदार Subject का उपयोग, जो समान है

@Component({ 
    selector: 'child-event-producer', 
    template: ` 
    <p (mousemove)="handle($event)"> 
     <ng-content></ng-content> 
    </p> 
    ` 
}) 
export class ChildEventProducerComponent { 
    @Output() event = new EventEmitter<MouseEvent>(); 

    handle(e:MouseEvent) { 
    this.event.emit(e); 
    } 
} 

और @ViewChild डेकोरेटर या तो इस तरह का उपयोग कर माता-पिता में वायर्ड है पहले की तकनीक के लिए।

8) अंत में, यदि आपको घटक पेड़ में नोटिफिकेशन प्रसारित करने की आवश्यकता है, तो एक साझा सेवा जाने का तरीका प्रतीत होता है।

@Injectable() 
export class LocationService { 
    private source = new ReplaySubject<{x:number;y:number;}>(1); 

    stream:Observable<{x:number;y:number;}> = this.source 
    .asObservable() 
    .sampleTime(1000); 

    moveTo(location:{x:number;y:number;}) { 
    this.source.next(location); 
    } 
} 

व्यवहार सेवा में समाहित है। बच्चे घटक में आवश्यक सभी LocationService कन्स्ट्रक्टर में इंजेक्शन दिया गया है और इवेंट हैंडलर में moveTo पर कॉल किया गया है।

@Component({ 
    selector: 'child-event-producer', 
    template: ` 
    <p (mousemove)="handle($event)"> 
     <ng-content></ng-content> 
    </p> 
    ` 
}) 
export class ChildEventProducerComponent { 
    constructor(private svc:LocationService) {} 

    handle(e:MouseEvent) { 
    this.svc.moveTo({x: e.x, y: e.y}); 
    } 
} 

घटक पेड़ आप से प्रसारित करने की आवश्यकता के स्तर पर सेवा सम्मिलित करें।

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <child-event-producer> 
     Move over me! 
    </child-event-producer> 
    <div *ngFor="let message of messages">{{message}}</div> 
    `, 
    directives: [ChildEventProducerComponent], 
    providers: [LocationService] 
}) 
export class WatchChildEventsComponent implements OnInit, OnDestroy { 
    messages:string[] = []; 
    subscription:Subscription; 

    constructor(private svc:LocationService) {} 

    ngOnInit() { 
    this.subscription = this.svc.stream 
     .subscribe((e:{x:number;y:number;}) => { 
     this.messages.push(`(${e.x}, ${e.y})`); 
     }); 
    } 

    ngOnDestroy() { 
    this.subscription.unsubscribe(); 
    } 
} 

समाप्त होने पर सदस्यता समाप्त करने के लिए नहीं भूलना। यह समाधान कुछ जटिलता के खर्च पर बहुत लचीलापन प्रदान करता है।

निष्कर्ष में, यदि घटक अंतर संचार (3) की आवश्यकता नहीं है, तो मैं घटक के विषय में एक आंतरिक आंतरिक उपयोग करूंगा। अगर मुझे घटक पेड़ को संवाद करने की ज़रूरत है तो मैं बच्चे के घटक में विषय को समाहित कर दूंगा और घटक (5) के भीतर स्ट्रीम ऑपरेटरों को लागू करूंगा। अन्यथा, अगर मुझे अधिकतम लचीलापन की आवश्यकता है, तो मैं एक धारा (8) को लपेटने के लिए एक सेवा का उपयोग करूंगा।

+1

भी देखें https://github.com/angular/angular/issues/10039 और https: // github.com/angular/angular/issues/4062। मुझे लगता है कि यह 2.0 रिलीज के बाद संबोधित किया जाएगा। –

उत्तर

1

विधि 6 में आप @ViewChild और ngAfterViewInit के बजाय event binding (scroll down to "Custom Events with EventEmitter") है, जो एक बहुत सरल उपयोग कर सकते हैं:

@Component({ 
    selector: 'watch-child-events', 
    template: ` 
    <child-event-producer (event)="onEvent($event)"> 
     Move over me! 
    </child-event-producer> 
    <div *ngFor="let message of messages">{{message}}</div> 
    `, 
    directives: [ChildEventProducerComponent] 
}) 
export class WatchChildEventsComponent { 
    messages:string[] = []; 
    onEvent(e) { this.messages.push(`${e.type} (${e.x}, ${e.y})`); } 
} 
+0

यह बच्चे घटक द्वारा उत्सर्जित घटनाओं की देखने योग्य धारा में ऑपरेटरों (नमूना समय) को लागू करने की कार्यक्षमता खो रहा है। तकनीक 5 में, बच्चा घटक उस कार्यक्षमता को समाहित करता है, जो इसे आपके जैसा उपयोग करने की अनुमति देता है। – gwhn