2016-01-03 17 views
7

Fondamentalmente voglio creare un componente di dialogo personalizzato che posso utilizzare da qualsiasi punto della mia app Angular2 indipendentemente da dove si trova il componente di utilizzo nell'albero delle applicazioni. Per semplicità, chiamiamo questo mio componente SayHello.Come rendere un componente universalmente accessibile in Angular2

Si consideri il seguente albero di applicazione: enter image description here

Quindi diciamo che voglio SomeComponent.level3.component per richiamare la finestra di dialogo in SayHello.component.

In Angular 1.x, inserisco RootScope in un controller e accendo una finestra di dialogo in questo modo. Ora capisco (più o meno) che per Angular2 è possibile creare degli eventi a bolla (con gli emettitori di eventi) nell'albero dei componenti, ma sembra noioso bombardare un evento fino in fondo da SomeComponent.level3.componente sull'albero e giù fino a SayHello .componente.

Quindi ho pensato di creare un servizio SayHello che avrei iniettato ovunque volessi illuminare il mio dialogo. Ecco uno schizzo del codice che ho formulato.

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

Inutile dire che questo non funziona. Non ricevo errori, ma il SayHello.component non rileva alcun cambiamento nel valore di 'showdialog' ... quindi non succede nulla. Qualsiasi idea su come farlo correttamente sarebbe molto apprezzata.

+2

Anziché (o forse in aggiunta a) pubblicare tutti questi frammenti di codice singolarmente, avente una plunkr con tutte queste parti di lavoro insieme renderebbero molto più facile per me/noi giocare con la tua implementazione e mostrarti cosa deve cambiare – drewmoore

+0

#drewmoore, una buona idea funzionerà in plunkr. #pixelbits, sì, questa è la mia strategia, ma sto facendo qualcosa di sbagliato. – brando

+0

FYI, gli eventi personalizzati (dall'emettitore di eventi) non possono essere fatti bollire (solo gli eventi DOM possono). – pixelbits

risposta

8

Come menzionato in un commento sopra,

  • porre osservabile all'interno del servizio (nota, non un EventEmitter)
  • Mettere un'API/metodo showDialog() sul servizio che altri componenti possono chiamare. Il metodo showDialog() dovrebbe chiamare next() per inviare un evento.
  • Il componente di dialogo può iscriversi all'evento e mostrare/mostrare se riceve un evento.

Per avvolgere un Osservabile in un servizio, vedere this answer.

+0

Vorrei averlo visto prima di comunicare tra componenti che hanno iniziato a farmi male al cervello (: ho trovato [questa soluzione] (http://stackoverflow.com/a/34576997/1876949) (passando emettitore come @Input). Penso che sia un un po 'più riutilizzabile, perché non devo importare il servizio in componenti che potrebbero non averne bisogno e posso spostare il componente tra i progetti più liberamente – Sasxa