2017-04-11 10 views
2

Ich erstelle eine 3d "Kartenflaps" mit eckigen 2. Eine übergeordnete 'card-flip' Komponente enthält eine verschachtelte 'card-flip-front' und ' Karte-Flip-Back-Komponente.Erstellen Sie einen "Klon" einer Angular2-Komponente mit ng-Inhalt

<card-flip card-flip-id="demo-1" class="grid_col-6"> 
    <card-flip-front class="card"> 
    <div class="card__inner"> 
     Card Front 
    </div> 
    </card-flip-front> 
    <card-flip-back class="card"> 
    <div class="card__inner"> 
     Card Back 
    </div> 
    </card-flip-back> 
</card-flip> 

Ich möchte einen „Klon“ der Karte-Flip-Vorderteil mit Inhalt Projektion und Datenbindung in Takt erzeugen. Der "Klon" würde zum Animieren verwendet werden und das "Original" würde in seiner ursprünglichen Position verborgen bleiben. Auf diese Weise habe ich einen Verweis darauf, wo der "Klon" animiert werden soll, wenn er an die ursprüngliche Position zurückgibt (auch wenn der Benutzer scrollt oder die Größe des Fensters ändert).

Die Hauptherausforderung, mit der ich konfrontiert bin, ist, dass ich den Inhalt innerhalb des Tags ng-content brauche, um auch in den "Klon" projiziert zu werden. Das Problem ist, dass das erste ng-content-Tag von Angular für die Inhaltsprojektion verwendet wird und dass zusätzliche, unmarkierte ng-content-Tags leer sind (was ich weiß, ist das erwartete Verhalten).

Man könnte fragen: "Warum nicht einfach eine dumme, statische Kopie des Elements im DOM erstellen?". Ich möchte dies vermeiden, so dass verschachtelte Komponenten und Datenbindungen, die Daten injizieren (und dadurch die Dimensionen des Elements verändern), weiterhin funktionieren.

Hier ist meine Arbeit bisher, die eine Instanz der CardFlipFront-Komponente über ComponentFactory erstellt, um als "Klon" zu dienen und fügt einfach die innereHTML der "ursprünglichen" CardFlipFront.

import { 
 
    Component, 
 
    ComponentFactory, 
 
    ComponentFactoryResolver, 
 
    ComponentRef, 
 
    ContentChild, 
 
    Inject, 
 
    Input, 
 
    OnInit, 
 
    ViewChild, 
 
    ViewContainerRef 
 
} from '@angular/core'; 
 
import { CardFlipFrontComponent } from './card-flip-front.component'; 
 
import { CardFlipBackComponent } from './card-flip-back.component'; 
 
import { CardFlipService } from './card-flip.service'; 
 

 
@Component({ 
 
    selector: 'card-flip', 
 
    templateUrl: './card-flip.component.html', 
 
    styleUrls: ['./card-flip.component.css'], 
 
    entryComponents: [ 
 
    CardFlipFrontComponent 
 
    ] 
 
}) 
 
export class CardFlipComponent implements OnInit { 
 
    @Input('card-flip-id') public id: string; 
 
    @ContentChild(CardFlipFrontComponent) private front: CardFlipFrontComponent; 
 
    @ContentChild(CardFlipBackComponent) private back: CardFlipBackComponent; 
 
    @ViewChild('frontCloneContainer', { read: ViewContainerRef }) private frontCloneContainer: ViewContainerRef; 
 
    private frontComponentRef: ComponentFactory<CardFlipFrontComponent>; 
 
    private frontClone: ComponentRef<CardFlipFrontComponent>; 
 

 
    constructor(
 
    @Inject(CardFlipService) private _cardFlipService: CardFlipService, 
 
    private _componentFactoryResolver: ComponentFactoryResolver 
 
) { 
 
    this.frontComponentRef = this._componentFactoryResolver.resolveComponentFactory(CardFlipFrontComponent); 
 
    } 
 

 
    ngOnInit() { 
 
    this._cardFlipService.register(this.id); 
 
    } 
 

 
    ngAfterViewInit() { 
 
    // Create a card-flip-front component instance to serve as a "clone" 
 
    this.frontClone = this.frontCloneContainer.createComponent(this.frontComponentRef); 
 
    // Copy the innerHTML of the "original" into the "clone" 
 
    this.frontClone.instance.el.nativeElement.innerHTML = this.front.el.nativeElement.innerHTML; 
 
    } 
 

 
    ngOnDestroy() { 
 
    this.frontClone.destroy(); 
 
    } 
 
}
<ng-content select="card-flip-front"></ng-content> 
 
<ng-container #frontCloneContainer></ng-container> 
 
<ng-content select="card-flip-back"></ng-content>

import { 
 
    Component, 
 
    ElementRef, 
 
    HostBinding, 
 
    Input, 
 
    OnInit, 
 
    Renderer 
 
} from '@angular/core'; 
 

 
@Component({ 
 
    selector: 'card-flip-front', 
 
    templateUrl: './card-flip-front.component.html', 
 
    styleUrls: ['./card-flip-front.component.css'] 
 
}) 
 
export class CardFlipFrontComponent implements OnInit { 
 
    constructor(private _el: ElementRef, private _renderer: Renderer) { } 
 

 
    public get el(): ElementRef { 
 
    return this._el; 
 
    } 
 

 
    public get renderer(): Renderer { 
 
    return this._renderer; 
 
    } 
 

 
    ngOnInit() { } 
 
}
<ng-content></ng-content>

UPDATE:

Ok, also über einige ähnliche Herausforderungen nach der Lektüre und dem github issue here, ich folgendes versucht.

<ng-template #frontTemplate> 
    <ng-content select="card-flip-front"></ng-content> 
</ng-template> 

<ng-container *ngIf="isOpen == true" #front1> 
    <ng-container *ngTemplateOutlet="frontTemplate"></ng-container> 
</ng-container> 

<ng-container *ngIf="isOpen == false" #front2> 
    <ng-container *ngTemplateOutlet="frontTemplate"></ng-container> 
</ng-container> 

<ng-content select="card-flip-back"></ng-content> 

Grundsätzlich können wir mit ng-content um die einzelnen Vorsprung Ausgabe erhalten, indem sie innerhalb einer Vorlage platzieren und mit zwei ng-container Tags mit einer *ngIf Anweisung, die nur eine Instanz der Vorlage auf einer Klasseneigenschaft isOpen Basis zeigen.

Dies löst jedoch nicht das gesamte Problem, da immer nur ein Container gerendert wird. Daher kann ich die aktuelle Position von "Original" nicht herausfinden, um herauszufinden, wo der "Klon" während der oben beschriebenen Rückkehranimation zu animieren ist.

Antwort

0

Ich denke, man kann eine vermittelnde Komponente <card-flip-content> innerhalb <card-flip> Vorlage haben, die doppelt vorhanden ist und welche empfängt die <ng-content> des <card-flip>.

Etwas wie:

@Component(
    selector = 'card-flip', 
    template = ` 
    <card-flip-content #theOne> 
     <ng-content /> 
    </card-flip-content> 
    <card-flip-content #theClone> 
     <ng-content /> 
    </card-flip-content> 
`) 

Dann wie zu #theOne und #theClone binden Daten benötigt und nur #theClone animieren. Auf diese Weise können @Input und @Output so definiert werden, dass die Aktionen einer Komponente von der übergeordneten Komponente interpretiert werden, um auf die andere Komponente zu wirken.

Würde das funktionieren?

+0

Danke für den Gedanken, aber ich denke, dass ich ein Missverständnis sein könnte. In dem von Ihnen bereitgestellten Beispiel verwenden Sie ng-content zweimal. Nur das erste ng-content-Tag enthält den projizierten Inhalt, sodass das Hauptproblem weiterhin besteht. – Jbird

+2

Diese Einschränkung des ng-Inhalts ist das beabsichtigte Verhalten und wird hier ausführlich besprochen https://github.com/angular/angular/issues/7795 – Jbird

Verwandte Themen