2017-09-08 2 views
0

Update:Richtiger Weg Wrapperkomponenten in Angular 4 zu implementieren?

Die richtige Frage ist wahrscheinlich:. "Wie kann ich meine eigene Version von ng-container implementieren, so kann ich" <my-component ...>...</my-component> "statt" <ng-container my-directive ...>...</ng-container>

Ich entwickle eine neue App in Angular 4 Ich möchte meine gesamte App mit Wrapper-Komponenten erstellen, damit ich bei Bedarf die eigentlichen Komponenten austauschen kann.Dies funktioniert problemlos für einfache Steuerelemente, aber nicht für komplexe Steuerelemente, die wir in separate Komponenten aufteilen möchten Die Anforderungen sind ziemlich stabil: eine Liste von Registerkarten mit Beschriftungen und Inhaltsfenstern, die wir ein-/ausblenden

ng-Bootstrap kann so etwas wie folgt verwenden:

<div class="my-tab-group"> 
    <ul> 
    <li>Tab 1</li> 
    ... 
    </ul> 
    <div class="my-tab" title="Tab 1">...</div> 
    ... 
</div> 

Statt binden meine app zu dieser Zeit möchte ich auf eine bestimmte Implementierung meine definieren:

<ngb-tabset> 
    <ngb-tab title="Tab 1"> 
    <ng-template ngbTabContent>...</ng-template> 
    </ngb-tab> 
    ... 
<ngb-tabset> 

wir so eine andere Komponente aufweisen eigene Wrapper-Tabs und es so überall verwenden:

<my-tabs-control> 
    <my-tab-control title="Tab 1">...</my-tab-control> 
    ... 
<my-tabs-control> 

Dann, wenn ich die Möglichkeit, meine Tabs ändern müssen arbeiten, um es an einem Ort geschieht. Wenn wir jedoch eine Wrapper-Komponente verwenden, wird der HTML-Code mit den Host-Element-Tags verschmutzt, die mit den gewünschten Tags verschachtelt sind, was offensichtlich Dinge vermasselt, z.

<my-tabs-control> 
    <div class="my-tab-group"> 
    <ul> 
     <li>Tab 1</li> 
     ... 
    </ul> 
    <my-tab-control title="Tab 1"> 
     <div class="my-tab" title="Tab 1">...</div> 
    </my-tab-control>   
    ... 
    </div> 
<my-tabs-control> 

Meine Vermutung ist dies der Grund, warum viele Leute fragen, wie das Host-Element in einer Winkelkomponente auszupacken/entfernen - dass dies wirklich einfach machen würde, zu tun.

Die übliche Antwort ist stattdessen Attributselektoren zu verwenden, zB:

Remove the angular2 component's selector tag

How to remove/replace the angular2 component's selector tag from HTML

Dies bedeutet jedoch, müssen wir die Tag-Struktur am Einsatzort wissen, was offensichtlich die zerstört ganzer Punkt der Verwendung von gut benannten Wrapper-Tags.

So endlich, wie soll ich das tun? Ist es vielleicht aus Leistungsgründen nicht möglich? Ich habe angefangen, Renderer2 zu betrachten, habe aber keine offensichtliche Möglichkeit gefunden, das zu tun, was ich will, und ich möchte nicht-eckige DOM-Hacks vermeiden.

+0

Sieht aus wie Sie 'Einbindung' mit ng-Inhalt verwenden möchten: https://scotch.io/tutorials/angular-2-transclusion-using- ng-content Official angular docs scheinen das zu vermissen: https://github.com/angular/angular.io/issues/3099 – marvini

+0

Ich benutze ng-content schon viel für projizierten Inhalt, aber das behebt das Problem nicht der Wrapper/Container-Tags, die von der Komponente selbst erstellt wurden. Wir können bekommen, was wir wollen, indem wir ng-container mit einer Direktive anstelle einer Komponente verwenden, aber das sieht chaotisch aus. Wir können vielleicht eine Direktive mit einem Elementselektor anstelle des Standardattributselektors verwenden und dann (vielleicht?) Renderer2/code verwenden, um den Inhalt zu rendern. Was ich wirklich will, ist ein Schalter, um einfach zu sagen: "render den Inhalt dieser Komponente ohne das Wrapper/Container/Host-Element. Leider denke ich, dass das nicht möglich ist. – Etherman

Antwort

1

Ich habe eine Lösung, die funktioniert, obwohl nicht so elegant, wie ich es mir gewünscht hätte. Ich würde viel lieber eine Option wählen, um einfach die "Host-Elemente" loszuwerden, da das viel besser wäre.

Ich leitete diese Lösung von einfach aus, wie sie Registerkarten im ng-Bootstrap-Projekt um implementiert: https://github.com/ng-bootstrap/ng-bootstrap.

Die Lösung besteht darin, eine @Component als Hauptcontainer zu verwenden und dann @Directives für alle internen untergeordneten Komponenten zu verwenden. Normalerweise verwenden wir eine Direktive als Add-on zu einem anderen Element - aber hier verwenden wir die Direktive als das eigentliche Element. Dies scheint wie eine Komponente zu funktionieren, die ihren eigenen Inhalt nicht darstellt oder einen eigenen Host-Container erstellt. Stattdessen kann die Hostkomponente entscheiden, was mit dem Inhalt der Richtlinie geschehen soll. Die zusätzliche Bedingung ist, dass wir ng-templates verwenden müssen - ich kann nicht sehen, wie man den Direktiveninhalt direkt projiziert, ohne ng-templates zu verwenden.

Hier ist, wie ich eine Registerkarte Container Markup meine Wrapper-Komponente mit:

<my-tab-container> 
    <my-tab title="Tab 1"> 
    <ng-template myTabContent> 
     This is panel 1! 
    </ng-template> 
    </my-tab> 
    <my-tab title="Tab 2"> 
    <ng-template myTabContent> 
     This is panel 2! 
    </ng-template> 
    </my-tab> 
    <my-tab title="Tab 3"> 
    <ng-template myTabContent> 
     This is panel 3! 
    </ng-template> 
    </my-tab> 
</my-tab-container> 

Hier eine minimale Umsetzung meiner Registerkarten Wrapper-Komponente ist, die die beiden Richtlinien für einzelne Registerkarten und Registerkarte Inhalt enthält.

Jetzt kann ich verschiedene Arten von Tabs rendern, indem Sie die HTML-Vorlage für meine Registerkarte Container-Komponente ausschalten.

z.B. für ng-bootstrap:

<ngb-tabset> 
    <ngb-tab *ngFor="let tab of tabs"> 
    <ng-template ngbTabTitle>{{tab.title}}</ng-template> 
    <ng-template ngbTabContent> 
     <ng-template [ngTemplateOutlet]="tab.content.templateRef"></ng-template> 
    </ng-template> 
    </ngb-tab> 
</ngb-tabset> 

z.B. für Angular Material2:

<md-tab-group> 
    <md-tab *ngFor="let tab of tabs" label="{{tab.title}}"> 
    <ng-template [ngTemplateOutlet]="tab.content.templateRef"></ng-template> 
    </md-tab> 
</md-tab-group> 

oder einige andere benutzerdefinierte Sache (jQueryUI Stil): alle über

<ul> 
    <li *ngFor="let tab of tabs">{{tab.title}}</li> 
</ul> 
<div *ngFor="let tab of tabs"> 
    <ng-template [ngTemplateOutlet]="tab.content.templateRef"></ng-template> 
</div> 

Es bedeutet, dass wir jetzt über das Hinzufügen von Registerkarten (und alle anderen Arten von Kontrollen) an die UI tragen kann Der Ort, an dem wir uns keine Sorgen machen müssen, wenn wir die besten Komponenten für unser Projekt ausgewählt haben - wir können die Dinge später bei Bedarf leicht umstellen.

(hoffentlich ist dies nicht Performance-Probleme vorstellen!)

Verwandte Themen