Dynamische Komponente in ngx-datierbaren Zeilendetails

9

Ich erstelle eine wiederverwendbare Datentabelle mit ngx-datatable und möchte, dass dynamische Komponenten innerhalb der Zeilendetails gerendert werden. Die datierbare Komponente empfängt eine Komponentenklasse als Argument von einem übergeordneten Modul, und ich verwende ComponentFactory, um Component zu erstellen. Ich kann sehen, dass der Konstruktor und die onInit-Methoden für die dynamische Komponente ausgeführt werden, aber nicht an das DOM angehängt werden.

So sieht das datierbare HTML für das Zeilendetail aus:

 <!-- [Row Detail Template] -->
        <ngx-datatable-row-detail rowHeight="100" #myDetailRow (toggle)="onDetailToggle($event)">
          <ng-template let-row="row" #dynamicPlaceholder let-expanded="expanded" ngx-datatable-row-detail-template>
          </ng-template>
        </ngx-datatable-row-detail>
 <!-- [/Row Detail Template] -->

Und so sieht meine .ts-Datei aus:

@ViewChild('myDetailRow', {static: true, read: ViewContainerRef}) myDetailRow: ViewContainerRef;
@ViewChild('dynamicPlaceholder', {static: true, read: ViewContainerRef}) dynamicPlaceholder: ViewContainerRef;

renderDynamicComponent(component) {
        var componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
        var hostViewConRef1 = this.myDetailRow;
        var hostViewConRef2 = this.dynamicPlaceholder;
        hostViewConRef1.createComponent(componentFactory);
        hostViewConRef2.createComponent(componentFactory);
}

Ein weiterer Punkt ist, dass wenn meine #dynamicPlaceholderng-Vorlage außerhalb von ngx-datatable platziert wird, sie funktioniert und das dynamische Modul gerendert und angezeigt wird.

Raghav Kanwal
quelle
1
Dies hat mit der Inhaltsprojektion zu tun. Alles, was zwischen einem Komponenten-Tag platziert wird, wird nicht gerendert, es sei denn, die Komponente verfügt über ein <ng-content>Tag zum Rendern verschachtelter Markups.
C_Ogoo
Könnten Sie mir bitte mit einem kurzen Beispiel helfen, um in meinem Fall zu helfen?
Raghav Kanwal

Antworten:

2

Wir können eine Komponente zur <ng-template>Laufzeit nicht in eine Vorlage ( ) rendern, createComponent
da afaik-Vorlagen zur Kompilierungszeit von Angular verarbeitet werden. Wir brauchen also eine Lösung, die zur Kompilierungszeit funktioniert.


Lösung mit Nachteilen

ng-content kann uns hier helfen:

<!-- [Row Detail Template] -->
<ngx-datatable-row-detail rowHeight="100" (toggle)="onDetailToggle($event)">
   <ng-template let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template>
      <ng-content></ng-content>
   </ng-template>
</ngx-datatable-row-detail>
<!-- [/Row Detail Template] -->

Wir können dann alles, was wir wollen, an die Detailansicht übergeben:

<my-table>From the ouside but I cant access the current row :(</my-table>

Es gibt jedoch ein Problem: Wir können nicht verwenden, ng-contentwenn wir auf die aktuelle Zeile in der übergebenen Vorlage zugreifen möchten.


Lösung

Aber ngx-datatablehat uns gedeckt. Wir können eine Vorlage an die ngx-datatable-row-detailRichtlinie übergeben:

<ngx-datatable-row-detail [template]="myDetailTemplate "rowHeight="100" (toggle)="onDetailToggle($event)">
</ngx-datatable-row-detail>

Die Vorlage kann dann von jeder externen Komponente über eine @InputVariable übergeben werden:

<ng-template #myDetailTemplate let-row="row">
  From the outside with access to the current row: {{row.name}}
</ng-template>

Schauen Sie sich den Stackblitz an , in dem ich eine my-tableKomponente als poc geschrieben habe.

ChrisY
quelle
0

Definieren Sie eine Komponente, die ihren Inhalt als verfügbar macht TemplateRef

<ng-template #myTemplate let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template>

    <div><strong>Address</strong></div>
    <div>{{ row?.address?.city }}, {{ row?.address?.state }}</div>
</ng-template>

Verwenden Sie ViewChilddiese Option , um eine zugängliche Eigenschaft für zu erstellenTemplateRef

export class DynamicComponent implements OnInit {

  @ViewChild("myTemplate",{static:true}) myTempalte : TemplateRef<any>
...
}

Definieren Sie Ihre Zeilendetails ohne Vorlage

<ngx-datatable-row-detail rowHeight="100" (toggle)="onDetailToggle($event)">
</ngx-datatable-row-detail>

Definieren Sie eine Eigenschaft für den Zugriff auf die Direktive

@ViewChild(DatatableRowDetailDirective,{static:true}) templ:DatatableRowDetailDirective; 
 constructor(  
    private cfr: ComponentFactoryResolver, //import cfr
  )
....
toggleExpandRow(row) { 
   const factory = this.cfr.resolveComponentFactory<DynamicComponent>(
      DynamicComponent
    );

    const component = factory.create(this.injector,[]);   //create component dynamically
    this.templ._templateInput = component.instance.myTempalte; // set directives template to your components template 
    this.table.rowDetail.toggleExpandRow(row);
}

Stackblitz

Bearbeiten: Ich habe mit der ngx-datatableQuelle herumgespielt. Ein trauriger Teil davon ngx-datatable-row-detailist keine Komponente, sondern eine Direktive und sie ist nicht an DOM gebunden. Es hat also keine ViewContainerReferenz. Dies macht das Einspritzen von Elementen etwas schwierig. Sie können Vorlagen in Ihrer Komponente definieren, TemplateRefs verwenden und sie dort zuweisen, wo Sie Ihre Komponente rendern.

Eldar
quelle
Vielen Dank für die Eingabe. Ich habe versucht, Ihre Methode zu übernehmen, aber es wird eine el.setAttribute is not a functionFehlermeldung für die componentFactory.create-Methode angezeigt. Irgendeine Idee, warum das passieren könnte? this.dynamicPlaceholder.elementRef.nativeElement gibt einen Kommentar zurück. Könnte das sein?
Raghav Kanwal
@RaghavKanwal siehe meine aktualisierte Antwort.
Eldar