Angular - dynamické zobrazování komponent rubrika: Programování: JavaScript
Ahojte vývojáři,
jsem v angularu 6 nováček, proto bych potřeboval radu od vás - odborníků. Mám několik podobných komponent reprezentující „dialogy“ na stránce. Ty potom v šablonách procházím takto:
wrapper.component.html:
<div *ngFor="let dialog of myService.dialogs" [dialog]="dialog"> </div>
dialog.component.html:
<h1 class="dialog__caption noselect draggable"> {dialog.Caption}} <span class="dialog__toggle" (click)="dialog.toggle()">{{dialog.Minimized ? 'o' : 'n'}}</span> </h1> <div *ngIf="!dialog.Minimized" class="dialog__wrapper" [ngSwitch]="dialog.Id"> <app-dialog-a *ngSwitchCase="'DialogA'"></app-dialog-a> <app-dialog-b *ngSwitchCase="'DialogB'"></app-dialog-b> <app-dialog-c *ngSwitchCase="'DialogC'"></app-dialog-c> <app-dialog-d *ngSwitchCase="'DialogD'"></app-dialog-d> <app-dialog-e *ngSwitchCase="'DialogE'"></app-dialog-e> </div>
Zajímalo by mě, zdali by blok ngSwitch
šel nahradit nějakým elegatnějším řešením, např. tak, že v dialogu bude už informace o komponentě a tu jednoduše „zobrazit“ místo těch app-dialog-*
. Moje představa by byla přibližně tato:
... <div *ngIf="!dialog.Minimized" class="dialog__wrapper"> <{{dialog.Component}}></{{dialog.Component}}> </div> ...
Doporučili byste mi něco, prosím, jak toto vyřešit?
Předem děkuji
Petr Jajtner
Ja som nieco podobne teraz riesil, v Anugulari 6 to sice ide a funguje, ale rataj aj s tym, ze to nebude uplne bez problemov.
Tak ako ty, aj ja som si urobil nejaky wrapper komponent. Ten vo vnutri mal (okrem ineho) aj <ng-template appDynamicHost></ng-template>
, cize template spolu s vlastnou direktivou appDynamicHost
. Tato direktiva je sama o sebe prazdna, neobsahuje ziadnu logiku, len v kostruktore je definovana zavislost na ViewContainerRef
aby sa s obsahom dalo neskor pracovat.
Cize vyzera takto:
import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ selector: '[appDynamicHost]' }) export class DynamicHostDirective { constructor (public viewContainerRef: ViewContainerRef) { } }
Naspat ku wrapperu. Ten ma idealne v ngOnInit
kod, ktory s pomocou ComponentFactoryResolver
dokaze dynamicky vytvorit akykolvek komponent a v podstate ho "vlozi" na potrebne miesto. Uryvok kodu moze vyzerat nejako takto:
const factory = this.componentFactoryResolver.resolveComponentFactory(TargetComponentClass); const viewContainerRef = this.dynamicHost.viewContainerRef; // toto je referencia na nasu direktivu vo wrapperi viewContainerRef.clear(); // v pripade ak sa to v case updatuje, radsej vycistit const componentRef = viewContainerRef.createComponent(factory); (<any>componentRef.instance).foo = 'bar'; // takto sa binduju @Input() premenne this.templateInstance = <any>componentRef.instance; // ulozenie referencie na dynamicky komponent; takto s nim ak treba vieme dalej robit cokolvek
Miesto typu any
odporucam pouzit nejaky vlastny interface, ktory budu mat vsetky takto dynamicky vytvarane komponenty spolocny, ale to nieje v tomto priklade relevantne.
Takto nejako (ak som na nic podstatne nezabudol) to bude fungovat. Predom vsak zdoraznim aj par problemov, ktore takyto pristup ma. Najdolezitejsie je, ze takto dynamicky vytvoreny komponent je akoby vytrhnuty z kontextu angularu a teda nebude dostavat ngOnChanges
updaty a pod.. Ak je teda potrebne reagovat/zobrazovat v case ine data, tak sa to velmi vyrazne skomplikuje. Ja som to riesil tak, ze tu inicializaciu som prehodil do ngOnChanges
uz vo wrapperi a ukladal si instanciu a tu dalej pouzival (nieco na sposob singletonu, aby som nemal ten isty komponent n krat zbytocne) a nasledne vsetky zmeny rucne posielam dalej do komponentu (cez this.templateInstance
).
Odporucam si to vyskusat, ci ti tento postup bude fungovat. Ak to ale bude robit viac problemov, radsej to nepouzi. Ak naopak niekto vidi v tomto rieseni nejake pripomienky alebo sa to da urobit este lepsie, sem s tym, samemu by mi to velmi pomohlo :)
PS sorry ak tam je nejake typo alebo syntax chyba, kod pisem z pamati a anonymizujem :)
Pro zobrazení všech 2 odpovědí se prosím přihlaste:
Nebo se přihlaste jménem a heslem:
Komentáře