2016-12-06 3 views
1

Я хочу вручную подписаться на событие, выпущенное директивой, которая по дизайну должна быть доступна для нескольких компонентов моего приложения. На данный момент структура выглядит следующим образом:Angular2: rxjs Subject in Angular2 взаимодействие с родительским компонентом

AppComponent 
    Draggable.Directive (uses an attribute of a DOM element to control the behaviour) 

    (and then, via routing) 
    Parent1 Component 
    Child1 Component 
    Child2 Component 

app.module выглядит следующим образом:

@NgModule({ 
    imports:  [ BrowserModule, HttpModule, JsonpModule, RouterModule.forRoot(appRoutes) ], 
    declarations: [ AppComponent, FooComponent, BarComponent, ParentComponent, DraggableDirective ], 
    bootstrap: [ AppComponent ] 
}) 

Позже в развитии, другой компонент Родителя будет слушать перетаскиваемую директиву и реализовывать свои собственный логика.

Ни один из компонентов для детей не знает (или не должен заботиться) о директиве Draggable, что-либо делает с ней. Родительский компонент должен. Так, в родительском компоненте:

import { Component, OnInit, ViewChild } from '@angular/core'; 
import { DraggableDirective } from './draggable.directive'; 
import { FooComponent } from './foo.component'; 
import { BarComponent } from './bar.component'; 

@Component({ 
    selector: 'parent-view', 
    templateUrl: './parent.component.html', 
    providers: [DraggableDirective], 
    moduleId: module.id 
}) 

export class ParentComponent implements OnInit { 
    @ViewChild('foo') fooC:FooComponent; 
    @ViewChild('bar') barC:BarComponent; 

    constructor(private draggable:DraggableDirective){ 
    draggable.droppedOn.subscribe(event => { 
     console.log('listening', event); 
    }) 
    } 

    ngOnInit(): void { 
    // updated 
    // child view components 
    this.fooC.fooInit(); 
    } 

А вот директива, используя Subject и не EventEmitter, как это было рекомендовано в другом месте:

import { Directive, ElementRef, Renderer, HostListener, AfterViewInit } from '@angular/core'; 
import {Subject} from 'rxjs/Rx'; 

@Directive({ 
    selector: '[draggable], [data-draggable]' 
}) 

export class DraggableDirective implements AfterViewInit { 

    public droppedOn = new Subject(); 

    //... at some point this method is envoked 
    couldDrop():void { 

     if (this.dElem) { 
      let _attr = this.dElem.dataset.indexed; 
      console.log('emitting', _attr); 
      this.droppedOn.next(_attr); 

     } 

    } 
} 

я получаю консольного протоколирование "излучающий" с правильным значения. Я никогда не получаю «прослушивание» от родительского компонента в консоли. Что я здесь делаю неправильно?

ответ

2

Директива, которую вы создаете, не является сервисом, поэтому она не переходит в @Component в providers массив, а вместо этого в declarations. См. Например, https://angular.io/docs/ts/latest/guide/attribute-directives.html (вы можете добавить его в NgModule)

Также ParentComponent не может получить экземпляр директивы, используемой где-то в вашем шаблоне, в свой конструктор. Вот что такое ViewChildren. См. Например: https://angular.io/docs/ts/latest/api/core/index/QueryList-class.html

Итак, в ParentComponent вы подписались на другой экземпляр DraggableDirective, который использует ваш шаблон.

+0

Хорошо, пока все хорошо. Должен ли я затем подписываться на Subject() на дочернем компоненте и перенаправлять его на родительский компонент? – pop

+0

@pop Нет, вы используете аннотацию '@ ViewChildren' и' QueryList', которая сама наблюдает в родительском компоненте, чтобы получить обновленный список всех директив 'DraggableDirective'. Там вы можете получить доступ к свойству 'lostOn', в котором каждый из них подписал его. – martin

+0

См. Http://stackoverflow.com/questions/32693061/angular-2-typescript-get-hold-of-an-element-in-the-template/35209681#35209681 – martin