l-lin / angular-datatables

DataTables with Angular
https://l-lin.github.io/angular-datatables/
MIT License
1.57k stars 481 forks source link

Invisible column cannot be used with a ngTemplateRef column #1721

Closed khicks closed 1 year ago

khicks commented 1 year ago

:beetle: bug report

In Angular 15 for a given table, one cannot use the visible=false property on a column when another column uses ngTemplateRef. The properties need not be on the same column. Either one used individually works, but not when both are used on columns in the same table.

When I try, I get this nondescript error:

ERROR TypeError: node is null

Additionally, the table does not render, and the template renders by itself where it would appear as if it were inline HTML.

:microscope: Minimal Reproduction

Step-by-step Instructions:

In the documentation demo app, add visible: false to any column. In my example, I tried the ID column.

import { AfterViewInit, Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ADTSettings,  } from 'angular-datatables/src/models/settings';
import { Subject } from 'rxjs';
import { IDemoNgComponentEventType } from './demo-ng-template-ref-event-type';
import { DemoNgComponent } from './demo-ng-template-ref.component';

@Component({
  selector: 'app-using-ng-template-ref',
  templateUrl: './using-ng-template-ref.component.html',
})
export class UsingNgTemplateRefComponent implements OnInit, AfterViewInit {

  constructor() { }

  pageTitle = 'Using Angular TemplateRef';
  mdIntro = 'assets/docs/advanced/using-ng-template-ref/intro.md';
  mdHTML = 'assets/docs/advanced/using-ng-template-ref/source-html.md';
  mdTS = 'assets/docs/advanced/using-ng-template-ref/source-ts.md';

  dtOptions: ADTSettings = {};
  dtTrigger: Subject<ADTSettings> = new Subject<ADTSettings>();

  @ViewChild('demoNg') demoNg: TemplateRef<DemoNgComponent>;
  message = '';

  ngOnInit(): void {
    // use setTimeout as a hack to ensure the `demoNg` is usable in the datatables rowCallback function
    setTimeout(() => {
      const self = this;
      this.dtOptions = {
        ajax: 'data/data.json',
        columns: [
          {
            title: 'ID',
            data: 'id',
            visible: false // <======================= HERE ==================
          },
          {
            title: 'First name',
            data: 'firstName',
          },
          {
            title: 'Last name',
            data: 'lastName'
          },
          {
            title: 'Actions',
            data: null,
            defaultContent: '',
            ngTemplateRef: {
              ref: this.demoNg,
              context: {
                // needed for capturing events inside <ng-template>
                captureEvents: self.onCaptureEvent.bind(self)
              }
            }
          }
        ]
      };
    });
  }

  ngAfterViewInit() {
    setTimeout(() => {
      // race condition fails unit tests if dtOptions isn't sent with dtTrigger
      this.dtTrigger.next(this.dtOptions);
    }, 200);
  }

  onCaptureEvent(event: IDemoNgComponentEventType) {
    this.message = `Event '${event.cmd}' with data '${JSON.stringify(event.data)}`;
  }

  ngOnDestroy(): void {
    // Do not forget to unsubscribe the event
    this.dtTrigger.unsubscribe();
  }
}

:8ball: Expected behavior

The TemplateRef column should render and the visible: false column should not render.

:camera: Screenshots

image

:globe_with_meridians: Your Environment

Thanks!

shanmukhateja commented 1 year ago

Bug confirmed. Let me see if I can come up with a way to resolve this.

PR is always welcome :)

khicks commented 1 year ago

Thanks for confirming I'm not crazy! That gave me enough motivation to find a fix, and I think what I have would work. Feel free to give it a look when you have a chance.

Here's a screenshot with the fix in place.

image

shanmukhateja commented 1 year ago

Closing as the fix has been merged.