Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mat-table can not be used inside ngTemplateOutlet #98

Open
Grochni opened this issue Apr 7, 2022 · 1 comment
Open

mat-table can not be used inside ngTemplateOutlet #98

Grochni opened this issue Apr 7, 2022 · 1 comment

Comments

@Grochni
Copy link

Grochni commented Apr 7, 2022

I have a fairly complex table to which I added virtual scroll using this excellent project.

However, as I still want to be able to use my table component without virtual scroll and I do not want to duplicate the whole table component, I tried putting it into an ng-template like this:

<cdk-virtual-scroll-viewport *ngIf="virtualScroll; else tableTemplate" [tvsItemSize]="rowHeight">
    <ng-container [ngTemplateOutlet]="tableTemplate"></ng-container>
</cdk-virtual-scroll-viewport>
<ng-template #tableTemplate>
   <mat-table>...</mat-table>
</ng-template>

There is an open issue in angular material explaining this behavior. It is stated in the comments that there's a workaround using ContentChildren instead of ContentChild. I tried around and was not able to get it to work.

What I ended up doing as a workaround is to subclass your TableItemSizeDirective and add an input to provide the table manually (because I can easily pick it up as a ViewChild in my component). This comes with some hacks like manually calling the ngAfterContentInit again when the input is set and overriding the ngAfterContentInit to null-check the table. Also, I had to copy your entire Directive decorator, as this is not inherited. The whole setup will make it hard to update my dependency to your library in the future and I therefor consider it a undesirable solution.

I can't say if there's an easy way to make Angular automatically pick up content children from inside an ngTemplateOutlet, but an other option would be to accept a reference to a MatTable as an input to your TableItemSizeDirective. This would be a small change that allows my usecase to work.

Kind regards and thanks for your work on this great project.

For others struggling with this, my workaround looks like this:

import { VIRTUAL_SCROLL_STRATEGY } from '@angular/cdk/scrolling';
import { AfterContentInit, Directive, Input, forwardRef } from '@angular/core';
import { MatTable } from '@angular/material/table';

import { TableItemSizeDirective, _tableVirtualScrollDirectiveStrategyFactory } from 'ng-table-virtual-scroll';

@Directive({
  selector: 'cdk-virtual-scroll-viewport[appItemSize]',
  providers: [{
    provide: VIRTUAL_SCROLL_STRATEGY,
    useFactory: _tableVirtualScrollDirectiveStrategyFactory,
    deps: [forwardRef(() => AppTableItemSizeDirective)]
  }]
})
export class AppTableItemSizeDirective extends TableItemSizeDirective implements AfterContentInit {

  @Input()
  set appItemSize(itemSize: string | number) {
    this.rowHeight = itemSize;
  }

  @Input()
  set tableComponent(table: MatTable<any>) {
    this.table = table;
    this.ngAfterContentInit();
  }

  override ngAfterContentInit() {
    if (!!this.table) {
      super.ngAfterContentInit();
    }
  }
}
@wS2Zth
Copy link

wS2Zth commented Sep 12, 2022

You saved me thx! Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants