html - Angular 4 - Jak zobrazit šablonu komponenty děděné třídy
Snažím se zobrazit seznam položek (komponent) podle jejich typů:
Mám pole komponent. Všechny dědí z základní třídy. Typ pole je definován jako typ základní třídy. Chci pole zobrazit (řekněme jako seznam položek), přičemž každá položka má svou vlastní šablonu, místo základní šablony.
Zkoušel jsem to:
V souboru app.component.html:
<app-shape *ngFor="let shape of shapes"></app-shape>
V souboru app.component.ts:
shapes: ShapeComponent[] = [new CircleComponent(), new SquareComponent()];
Definoval jsem 3 komponenty:
export class ShapeComponent {
}
export class CircleComponent extends ShapeComponent{
}
export class SquareComponent extends ShapeComponent{
}
A výsledkem je, že dostanu seznam tvarů.
Podporuje Angular takovou věc?
Díky!
Odpověď č. 1
Deklarativní přístup
Můžete použít ngComponentOutlet.
Kód :
shapes: ShapeComponent[] = [CircleComponent, SquareComponent];
šablona :
<ng-container *ngFor="let shape of shapes">
<ng-container *ngComponentOutlet="shape">
</ng-container>
</ng-container>
ngComponentOutlet - Instanciuje jeden typ komponenty a vkládá její hostitelský pohled do aktuálního pohledu. NgComponentOutlet poskytuje deklarativní přístup pro dynamické vytváření komponent.
NgComponentOutlet vyžaduje typ komponenty, pokud je nastavena nepravdivá hodnota, zobrazení se vymaže a jakákoli existující komponenta bude zničena.
Takže v šabloně není potřeba žádný tvrdý kód. *ngFor bude iterovat přes pole typů komponent ve vašem kódu
Aktualizace
Nezapomeňte přidat komponentu dynamického vykreslování do entryComponents AppModule:
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent, HelloComponent, AComponent, BComponent ],
entryComponents: [
AComponent, BComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Ukázka StackBlitz
Imperativní přístup s nastavováním dat
app-component.template:
<ng-container #comps>
</ng-container>
Získejte přístup k zobrazení #comps(ng-container) pomocí dekorátoru ViewChild a vytvořte komponenty. Takže nemůžete inicializovat komponentu jako b=new BComponent().
- Nejdříve je potřeba vyřešit továrnu komponent.
- Inicializujte komponentu pomocí metody createComponent objektu viewContainerRef. Vrací odkaz na instanci komponenty.
- Pomocí reference získejte přístup k vlastnosti instance a aktualizujte libovolná data podle potřeby
app-component.ts:
@ViewChild('comps', { read: ViewContainerRef }) comps: ViewContainerRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
this.comps.clear();
let aComponentFactory = this.componentFactoryResolver.resolveComponentFactory(this.compArr[0]);
let aComponentRef = this.comps.createComponent(aComponentFactory);
(<AComponent>aComponentRef.instance).name = 'A name';
let bComponentFactory = this.componentFactoryResolver.resolveComponentFactory(this.compArr[1]);
let bComponentRef = this.comps.createComponent(bComponentFactory);
(<BComponent>bComponentRef.instance).name = 'B name';
}
Demo StackBlitz
Odpověď č. 2
Každá součást musí mít samostatný selektor.
import {Component} from "@angular/core";
@Component({
selector: "app-shape" //maybe even is not needed here
})
class Shape {
}
@Component({
selector: "app-rect"
})
class Rect extends Shape {
}
Takže můžete udělat něco takového.
<div *ngFor="let shape of shapes">
<app-rect *ngIf="//check if shape is rect"></app-rect>
<app-circle *ngIf="//check if shape is circle"></app-circle>
</div>
