2016-02-29 17 views
8

In Angular 2 kann eine untergeordnete Komponente die übergeordnete Komponente über einen Konstruktorparameter erhalten. Beispiel:Inject übergeordnete Komponente des gleichen Typs wie untergeordnete Komponente

Dies funktioniert gut und gut, solange Eltern und Kind von verschiedenen Typen sind.

Ein weiterer typischer Anwendungsfall ist jedoch eine Baumstruktur, bei der jeder Baumknoten als separate Komponente angezeigt wird. Was sollten wir tun, wenn jede der Baumknoten-Komponenten Zugriff auf ihren übergeordneten Knoten haben sollte? Ich habe dies versucht:

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

Aber das schlägt mit der folgenden Laufzeitausnahme:

EXCEPTION: Cannot instantiate cyclic dependency! 

Ich denke, der Grund ist, dass Angular 2 die Komponenten selbst statt seine übergeordnete Komponente injiziert.

Wie kann ich angular angeben, um die Hauptkomponente einer Komponente zu injizieren, obwohl sie vom gleichen Typ sind?

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

+0

Warum injizieren Sie die Eltern, warum nicht einfach Datenbindung verwenden? –

+0

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

Antwort

15

Auf diese Weise funktioniert es

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

Plunker

  • @SkipSelf() ist, sich nicht zu bekommen injiziert, die TreeNodeComponent angefordert wird, wenn gelten würde
  • @Host() nicht weiter oben als das Hostelement suchen
  • @Optional() ?? es gibt keine übergeordnete TreeNodeComponent für den Wurzelknoten

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

+0

Sie ist ein Plünderer: [Link] (https: //plnr.co/edit/ddvupV?p=preview). Lesen Sie den Kommentar in treenode.component. – user928437

+0

Ich verstehe Ihren Kommentar über die Strategie, und ich stimme völlig zu. Bei einer Baumstruktur wie dieser hätte sie stattdessen eine Bindung verwendet. Mein tatsächlicher Anwendungsfall ist anders. Ich habe lediglich Baumknoten als Beispiel verwendet, um die Kernherausforderung zu veranschaulichen, da eine Baumstruktur ein wohlbekanntes Konzept ist. – user928437

+0

Ich konnte es nicht schaffen, auch nicht mit Thierrys Ansatz. Ich würde dies als einen Fehler betrachten. –

0

Angular2 für einen Anbieter in den aktuellen Injektor aussieht. In Ihrem Fall entspricht TreeNodeComponent der Komponente selbst.

Die Instanz der Elternkomponente befindet sich im Elterninjektor.

Ich denke, dass Sie versuchen könnten, eine Injektor-Klasse zu injizieren, um Zugriff auf den Eltern-Injektor zu haben und dann die Instanz der Eltern-Komponente zu bekommen. So etwas Ähnliches:

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

Siehe diesen Link für die Dokumentation der Injector Klasse:

das gesagt ist, glaube ich, dass der Kommentar Gunter über Bindung und Shared-Service ist besonders relevant ...

0

Dieser Beitrag wurde dank Günther gelöst. Ich würde jedoch gerne auf der Grundlage des architektonischen Feedbacks, das ich bekommen habe, nachgehen.

In erster Linie: Ich stimme völlig zu, dass das TreeNodeComponent-Beispiel ein Anti-Muster ist. Eine datengesteuerte Komponente wie ein Baum sollte durch Datenbindung gesteuert werden. Ich entschuldige mich für dieses Anti-Muster.

Allerdings ist mein tatsächlicher Anwendungsfall (der komplexer zu erklären ist), dass ich ein erweitertes Dropdown-Menü entwickeln möchte. Voraussetzungen:

  • Die Drop-Down-beliebige Anzahl von Ebenen haben sollte (Menü, Untermenü, subsubmenu usw.)
  • Der Drop-Down zur Entwurfszeit festgelegt ist - der Inhalt ist nicht auf dynamische Daten.
  • Es sollte möglich sein, Event-Handler (_) = zu jedem Dropdown-Element anzuhängen.
  • Es sollte möglich sein, benutzerdefinierte Steuerungskomponenten in das Dropdown-Menü einzufügen.

Ein Anwendungsbeispiel:

<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>  

Meine Überlegung ist, dass dies schwierig sein würde, die Bindung unter Verwendung von Daten zu implementieren. Es ist sehr praktisch, Event-Handler zu binden und benutzerdefinierte Komponenten auf diese Weise einzubinden.

Aber ich könnte falsch liegen! Alle Meinungen dazu sind sehr willkommen!

+0

Das sieht nicht wie eine Antwort aus. Ich denke, es wäre besser, deine Frage zu bearbeiten und diesen Inhalt dort hinzuzufügen. –

+0

Warum injizieren Sie überhaupt den Elternteil? Auf welche Mitglieder möchten Sie vom Elternteil zugreifen? –

+0

Ich muss die Eltern injizieren, weil das Öffnen eines Menüelements alle Geschwister schließen sollte, so dass nur ein "Menüpfad" zur gleichen Zeit geöffnet ist. Um dies zu erreichen, muss ich in der Lage sein, die Elternkomponente aufzurufen. – user928437

Verwandte Themen