2016-01-03 13 views
7

Po prostu chcę utworzyć niestandardowy komponent okna dialogowego, który mogę wykorzystać z dowolnego miejsca w mojej aplikacji Angular2, bez względu na to, gdzie w drzewie aplikacji jest używany składnik. Dla uproszczenia, nazwijmy to moim Komponentem SayHello.Jak sprawić, by komponent był powszechnie dostępny w Angular2

Rozważmy następujący drzewie aplikacji: enter image description here

Więc powiedzmy chcę SomeComponent.level3.component, aby wywołać okno w SayHello.component.

W Angular 1.x wprowadziłbym RootScope do kontrolera i uruchomiłam okno dialogowe w ten sposób. Teraz rozumiem (mniej więcej), że dla Angular2 można dymić zdarzenia (z emiterami zdarzeń) w górę drzewa komponentów, ale nudne wydaje się wydarzenie z systemu SomeComponent.level3.component w górę drzewa i w dół do SayHello .składnik.

Więc pomyślałem, że stworzę usługę SayHello, którą będę wstrzykiwać wszędzie, gdzie chcę oświetlić mój dialog. Oto szkic kodu, który sformułowałem.

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

trzeba dodawać, że to nie działa. Nie dostaję żadnych błędów, ale SayHello.component nie wykrywa żadnej zmiany wartości "showdialog" ... więc nic się nie dzieje. Wszelkie sugestie, jak to zrobić właściwie, będą mile widziane.

+2

Zamiast (albo oprócz) wysyłania wszystkie te fragmenty kodu indywidualnie o plunkr z wszystkie te działające razem części ułatwiłyby mi/nam zabawę z twoją implementacją i pokazałoby ci, co trzeba zmienić – drewmoore

+0

#drewmoore, dobry pomysł będzie działał w plunkr. #pixelbits, tak to jest moja strategia, ale robię coś złego. – brando

+0

FYI, zdarzenia niestandardowe (według emitera zdarzeń) nie mogą być bąbelkowane (tylko zdarzenia DOM mogą). – pixelbits

Odpowiedz

8

Jak wspomniano w komentarzu powyżej,

  • Put obserwowanej wewnątrz usługi (uwaga, a nie EventEmitter)
  • umieścić ShowDialog() API/metoda na służbie, że inne składniki mogą wywołać. Metoda showDialog() powinna wywołać next(), aby wysłać zdarzenie.
  • Twój komponent okna dialogowego może zasubskrybować zdarzenie i odkryć/pokazać się po odebraniu zdarzenia.

Aby zawinąć obserwowalne w serwisie, zobacz this answer.

+0

Chciałbym zobaczyć to przed komunikacją między komponentami zaczęło ranić mój mózg (: wymyśliłem [to rozwiązanie] (http://stackoverflow.com/a/34576997/1876949) (przekazywanie emitera jako @Input) .Myślę, że to jest bardziej nadaje się do ponownego użycia, ponieważ nie muszę importować usługi do komponentów, które mogą jej nie potrzebować, i można swobodniej przenosić komponent między projektami. – Sasxa

Powiązane problemy