I basically want to create a custom dialog component that I can utilize from anywhere in my Angular2 app regardless of where the using component is in the application tree. For simplicity lets call this my SayHello Component.
Consider the following application tree:
So let's say i want SomeComponent.level3.component to call up the dialog in SayHello.component.
In Angular 1.x I would inject RootScope into a controller and light up a dialog that way. Now, I understand (more or less) that for Angular2 you can bubble events (with event emitters) up the component tree, but it seems tedious to bubble an event all the way from SomeComponent.level3.component up the tree and down to SayHello.component.
So I thought I would create a SayHello Service that I would inject anywhere I wanted to light up my dialog. Here is a sketch of the code I have formulated.
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
]);
Needless to say, this doesn't work. I don't get any errors, but the SayHello.component does not detect any change in the value of 'showdialog'...so nothing happens. Any ideas as to how to do properly do this would be much appreciated.
As mentioned in a comment above,
To wrap an Observable in a service, see this answer.
An alternative to using a service is dynamically creating the component using ViewContainerRef/createComponent described here:
https://www.lucidchart.com/techblog/2016/07/19/building-angular-2-components-on-the-fly-a-dialog-box-example/