Как сделать компонент универсальным в Angular2

В основном я хочу создать настраиваемый компонент диалога, который я могу использовать из любого места в моем приложении Angular2, независимо от того, где компонент использования находится в дереве приложений. Для простоты позвольте назвать этот мой компонент SayHello.

Рассмотрим следующее дерево приложений: введите описание изображения здесь

Итак, скажем, я хочу SomeComponent.level3.component вызвать диалог SayHello.component.

В Angular 1.x я бы ввел RootScope в контроллер и осветил диалог таким образом. Теперь я понимаю (более или менее), что для Angular2 вы можете пузырить события (с помощью излучателей событий) вверх по дереву компонентов, но кажется утомительным, чтобы пузырить событие на всем пути от SomeComponent.level3.component вверх по дереву и вниз к SayHello.component.

Итак, я подумал, что создам сервис SayHello, который я бы вводил в любом месте, где бы я хотел, чтобы загорелся мой диалог. Вот эскиз кода, который я сформулировал.

myApp.component.ts

import {SayHelloComponent} from "<<folder>>/sayHello.component";
import {BunchOfComponents} from "<<folder>>/bunchOfComponents";

@Component({
    directives: [SayHelloComponent],
    selector: "my-app",
    templateUrl: `<bunch-of-components>Within this component exists
                      SomeComponent.level3.component </bunch-of-components>
                      <say-hello showdialog="{{showDialog}}" message="{{message}}">
                      </say-hello>`

})
export class myAppComponent {
    showDialog = false;
    message = "";

    constructor(private sayHelloService: SayHelloService) {
        this.showDialog = sayHelloService.showDialog;
        this.message = sayHelloService.message;

    }
}

SayHelloService.ts

import {Injectable} from 'angular2/core';

@Injectable()
export class SayHelloService {
    public showDialog: boolean = false;
    public message: string ="";

    constructor() {

    }

}

SayHello.component.ts

import {Component} from "angular2/core";
import {SayHelloService} from "<<folder>>/SayHelloService";
@Component({
    directives: [],
    selector: "say-hello",
    template: "[do hello component]"
})
export class SayHelloComponent {
    @Input() showdialog: boolean;
    @Input() message: string;

       constructor(private sayHelloService: SayHelloService) {

    }
    //This idea here is to detect change in showDialog
    //If true then do an alert with the message
    ngOnChanges(changes: { [propName: string]: SimpleChange }) {
        var obj = changes["showdialog"];
        if (obj !== null) {
            if (changes["showdialog"].currentValue === true) {
                alert(this.message);
                this.sayHelloService.showDialog = false;
            }

        };
    }

}

SomeComponent.level3.component

import {Component} from "angular2/core";
import {SayHelloService} from "<<folder>>/SayelloService";

@Component({
    directives: [],
    selector: "some-component",
    template: "<button (click)='doHello()'>Do say hello</button>"
})
export class PageContactUsComponent {

    constructor(private sayHelloService: SayHelloService) {

    }


    doHello(): void {
        this.sayHelloService.message = "Hello world";
        this.sayHelloService.showDialog = true;
    }
}

appBoot.ts

import {bootstrap} from "angular2/platform/browser";
import {MyAppComponent} from "<<folder>/MyAppComponent";
import {SayHelloService} from "<<folder>>/SayHelloService";

bootstrap(MyAppComponent, [
    SayHelloService
]);

Излишне говорить, что это не работает. Я не получаю никаких ошибок, но SayHello.component не обнаруживает никаких изменений в значении 'showdialog'... поэтому ничего не происходит. Любые идеи относительно того, как правильно делать это, будут высоко оценены.

Ответ 1

Как упоминалось в комментарии выше,

  • Поместите наблюдаемое внутри службы (обратите внимание, а не EventEmitter)
  • Поместите API/метод showDialog() в службу, которую могут вызвать другие компоненты. Метод showDialog() должен вызывать next() для отправки события.
  • Ваш компонент диалога может подписаться на событие и показать/показать себя, когда он получает событие.

Чтобы обернуть наблюдаемый в службе, см. этот ответ.