Komponent dynamiczny wewnątrz szczegółów wiersza z danymi ngx

9

Tworzę plik danych wielokrotnego użytku za pomocą ngx-datatable i chciałbym, aby dynamiczne komponenty były renderowane wewnątrz szczegółów wiersza. Składnik danych otrzymuje klasę składnika jako argument z modułu nadrzędnego i używam ComponentFactory do utworzenia składnika. Widzę, że konstruktor i metody onInit działają dla komponentu dynamicznego, ale nie jest on dołączany do DOM.

Tak wygląda html z datacją dla szczegółów wiersza:

 <!-- [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] -->

I tak wygląda mój plik .ts:

@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);
}

Inną kwestią jest to, że jeśli mój #dynamicPlaceholderszablon ng jest umieszczony poza ngx-datatable, to działa, a moduł dynamiczny jest renderowany i wyświetlany.

Raghav Kanwal
źródło
1
Ma to związek z projekcją treści. Cokolwiek umieszczone między znacznikiem komponentu, nie jest renderowane, chyba że komponent ma <ng-content>znacznik do renderowania zagnieżdżonego znacznika.
C_Ogoo
Czy możesz mi pomóc z krótkim przykładem, który pomoże w mojej sprawie?
Raghav Kanwal

Odpowiedzi:

2

Nie możemy renderować komponentu w szablonie ( <ng-template>) w czasie wykonywania, createComponent
ponieważ szablony afaik są przetwarzane przez Angular w czasie kompilacji. Potrzebujemy więc rozwiązania, które działa w czasie kompilacji.


Rozwiązanie z wadami

ng-content może nam pomóc tutaj:

<!-- [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] -->

Następnie możemy przekazać wszystko, co chcemy, do widoku szczegółów:

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

Ale jest problem: nie możemy użyć, ng-contentgdy chcemy uzyskać dostęp do bieżącego wiersza w przekazanym szablonie.


Rozwiązanie

Ale ngx-datatable nas ochronił. Możemy przekazać szablon do ngx-datatable-row-detaildyrektywy:

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

Szablon można następnie przekazać z dowolnego komponentu na zewnątrz za pomocą @Input zmiennej:

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

Spójrz na stackblitz , w którym napisałem my-tablekomponent jako poc.

ChrisY
źródło
0

Zdefiniuj komponent, który ujawnia jego zawartość jako 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>

Użyj, ViewChildaby zrobić dostępną właściwość dlaTemplateRef

export class DynamicComponent implements OnInit {

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

Zdefiniuj szczegóły wiersza bez szablonu

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

Zdefiniuj właściwość, aby uzyskać dostęp do dyrektywy

@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

Edycja: bałem się, że jego ngx-datatableźródłowa część nie ngx-datatable-row-detailjest komponentem, lecz dyrektywą i nie jest dołączona do DOM. Więc nie ma ViewContainerref. To sprawia, że ​​wstrzykiwanie do niego elementów jest trochę trudne. Możesz zdefiniować szablony w komponencie i użyć TemplateRefs oraz przypisać je tam, gdzie renderujesz komponent.

Eldar
źródło
Dzięki za dane wejściowe, próbowałem adoptować twoją metodę, ale otrzymuję el.setAttribute is not a functionbłąd w metodzie componentFactory.create. Masz pojęcie, dlaczego tak się dzieje? this.dynamicPlaceholder.elementRef.nativeElement zwraca komentarz, czy to może być?
Raghav Kanwal
@RaghavKanwal zobacz moją zaktualizowaną odpowiedź.
Eldar