2016-02-29 29 views
8

In Angular 2, un componente figlio può ottenere il componente principale iniettato tramite un parametro costruttore. Esempio:Iniettare un componente principale dello stesso tipo del componente figlio

@Component({...}) 
export class ParentComponent { 
    ... 
} 

@Component({...}) 
export class ChildComponent { 
    constructor(private parent: ParentComponent) { } 
    ... 
} 

Questo funziona bello e ben più a lungo del genitore e figlio sono di diversi tipi.

Tuttavia, un altro caso di utilizzo tipico è una struttura ad albero in cui ciascun nodo dell'albero viene visualizzato come componente separato. Cosa dovremmo fare se ognuno dei componenti del nodo dell'albero avesse accesso al suo genitore? Ho provato questo:

@Component({...}) 
export class TreeNodeComponent { 
    constructor(private parent: TreeNodeComponent) { } 
... 
} 

Ma questo non riesce con la seguente eccezione di runtime:

EXCEPTION: Cannot instantiate cyclic dependency! 

Credo che la ragione è che angolare 2 inietta il componente stesso invece del suo componente principale.

Come posso dire angolare per iniettare il componente padre di un componente anche se sono dello stesso tipo?

Plunkerhttps://plnkr.co/edit/ddvupV?p=preview

+0

Perché si inietta il genitore, perché non utilizzare solo l'associazione dati? –

+0

Prova questo: http://stackoverflow.com/questions/34540615/how-do-i-inject-a-parent-component-into-a-child-component – Damitha

risposta

15

In questo modo si sta lavorando

constructor(@SkipSelf() @Host() @Optional() parent: TreeNodeComponent) {} 

Plunker

  • @SkipSelf() è quello di non ottenere se stessi iniettato che si applicherebbe se TreeNodeComponent è richiesto
  • @Host() non guardare oltre l'elemento host
  • @Optional() ?? non v'è nessun genitore TreeNodeComponent per il nodo radice

Vedi anche http://blog.thoughtram.io/angular/2015/08/20/host-and-visibility-in-angular-2-dependency-injection.html

+0

Her is a plunker: [link] (https: //plnkr.co/edit/ddvupV?p=preview). Leggi il commento su treenode.component. – user928437

+0

Capisco il tuo commento sulla strategia e sono totalmente d'accordo. Avrebbe usato invece il binding nel caso di una struttura ad albero come questa. Il mio caso d'uso reale è diverso. Ho semplicemente usato i nodi dell'albero come esempio per illustrare la sfida principale poiché una struttura ad albero è un concetto ben noto. – user928437

+0

Non ero in grado di farlo funzionare, anche con l'approccio di Thierrys. Lo considererei un bug. –

0

Angular2 indaga l'iniettore di corrente per un provider. Nel tuo caso, TreeNodeComponent corrisponde al componente stesso.

L'istanza del componente principale si trova nell'iniettore principale.

Penso che si possa provare a iniettare una classe Injector per accedere all'iniettore padre e quindi ottenere l'istanza del componente padre. Qualcosa del genere:

@Component({ 
    (...) 
}) 
export class TreeNodeComponent { 
    constructor(injector:Injector) { 
    let parentInjector = injector.parent; 
    let parent = patentInjector.get(TreeNodeComponent); 
    } 
} 

Vedere questo link per la documentazione della classe iniettore:

Detto questo, penso che il commento del Gunter sulla rilegatura e servizio condiviso è particolarmente rilevante ...

0

Questo post è stato risolto grazie a Günther. Tuttavia, mi piacerebbe dare un seguito basato sul feedback architettonico che ho ricevuto.

Prima di tutto: Sono completamente d'accordo che l'esempio di caso di utilizzo di TreeNodeComponent sia un pattern anti. Un componente guidato dai dati come un albero dovrebbe essere controllato dall'associazione dati. Le mie scuse per questo modello anti.

Tuttavia, il mio caso di utilizzo effettivo (che è più complesso da spiegare) è che voglio sviluppare un menu a discesa avanzato. Requisiti:

  • La discesa deve avere numero arbitrario di livelli (menu, sottomenu, sottosottomenu ecc)
  • La discesa è definita in fase di progettazione - il suo contenuto non si basa su dati dinamici.
  • Dovrebbe essere possibile associare gestori di eventi (_) = a ogni articolo a discesa.
  • Dovrebbe essere possibile inserire componenti di controllo personalizzati nel menu a discesa.

Un esempio di utilizzo:

<dropdown label="Actions"> 
    <dropdown-item label="Action 1" (click)="action1()"></dropdown-item> 
    <dropdown-item label="Action 2" (click)="action2()"></dropdown-item> 
    <dropdown-item label="Submenu"> 
    <dropdown-item label="Action 3.1" (click)="action31()"></dropdown-item> 
    <dropdown-item label="Action 3.2"> 
     <dropdown-slider (change)="changeHandler()"></dropdown-slider> 
    </dropdown-item> 
    <dropdown-item label="Submenu"> 
     <dropdown-item label="Action 3.3.1" (click)="action331()"></dropdown-item> 
     <dropdown-item label="Action 3.3.2" (click)="action332()"></dropdown-item> 
    </dropdown-item> 
    </dropdown-item> 
</dropdown>  

La mia considerazione è che questo sarebbe difficile da attuare mediante l'associazione dati. È molto pratico essere in grado di associare gestori di eventi e includere componenti personalizzati in questo modo.

Ma potrei sbagliarmi! Qualsiasi opinione su questo è altamente gradita!

+0

Non sembra una risposta. Penso che sarebbe meglio modificare la tua domanda e aggiungere lì questo contenuto. –

+0

Perché si fa l'iniezione del genitore? A quali membri si desidera accedere dal genitore? –

+0

Ho bisogno di iniettare il genitore perché l'apertura di una voce di menu dovrebbe chiudere tutti i fratelli in modo che solo un "percorso del menu" sia aperto allo stesso tempo. Per raggiungere questo obiettivo, devo essere in grado di invocare il componente principale. – user928437

Problemi correlati