Angular: TabulatorPlus

สำหรับการใช้งานใน Angular เราจะใช้ประโยชน์จาก Lifecycle Hooks และ @ViewChild เพื่อเข้าถึง DOM Element ครับ โดยแนวคิดจะเน้นไปที่การรักษา Instance ไว้ใน Property ของ Class เพื่อเรียกใช้งานซ้ำ ( Reused ) และทำลายทิ้งเมื่อ Component ถูกถอดออก (Unmount)

นี่คือตัวอย่างการปรับใช้ TabulatorPlus ใน Angular ครับ
user-table.component.ts

import { Component, ElementRef, Input, OnChanges, OnDestroy, AfterViewInit, ViewChild, SimpleChanges } from '@angular/core';
import TabulatorPlus from './TabulatorPlus';

@Component({
  selector: 'app-user-table',
  template: `
    <div class="table-controls">
      <button (click)="refreshTable()">Redraw Table</button>
      <button (click)="clearFilters()">Clear Filters</button>
    </div>
    <div #tableElement></div>
  `,
  styles: [`
    .table-controls { margin-bottom: 10px; }
    :host ::ng-deep .tabulator { border: 1px solid #ccc; } /* จัดการ CSS Scoping */
  `]
})
export class UserTableComponent implements AfterViewInit, OnChanges, OnDestroy {
  
  // 1. อ้างอิงถึง HTML Element ใน Template
  @ViewChild('tableElement', { static: true }) tableElement!: ElementRef;

  // 2. รับข้อมูลจาก Parent Component
  @Input() data: any[] = [];

  // 3. เก็บ Instance ไว้เพื่อใช้งานซ้ำ (Reused Instance)
  private tabulatorInstance: any;

  constructor() {}

  // 4. Initialize: สร้างตารางเมื่อ View พร้อมใช้งาน
  ngAfterViewInit(): void {
    this.tabulatorInstance = new TabulatorPlus(this.tableElement.nativeElement, {
      data: this.data,
      columns: [
        { title: "Name", field: "name", width: 150 },
        { title: "Role", field: "role" },
        { title: "Last Login", field: "lastLogin" },
      ],
    }, "angular-storage-key");
  }

  // 5. Refresh: อัปเดตข้อมูลเมื่อ Props (Input) เปลี่ยนแปลง
  ngOnChanges(changes: SimpleChanges): void {
    if (changes['data'] && this.tabulatorInstance) {
      console.log("Refreshing data...");
      // ใช้ .setData() เพื่ออัปเดตข้อมูลโดยไม่ต้องสร้างตารางใหม่
      this.tabulatorInstance.setData(this.data);
    }
  }

  // 6. Manual Actions: การเรียกใช้ Instance จากฟังก์ชันอื่น
  refreshTable(): void {
    if (this.tabulatorInstance) {
      this.tabulatorInstance.redraw(true);
    }
  }

  clearFilters(): void {
    if (this.tabulatorInstance) {
      this.tabulatorInstance.clearFilter(true);
    }
  }

  // 7. Unmount & Cleanup: ล้างข้อมูลและทำลาย Instance
  ngOnDestroy(): void {
    if (this.tabulatorInstance) {
      console.log("Cleaning up Tabulator before component destroy...");
      this.tabulatorInstance.destroy(); // ป้องกัน Memory Leak
      this.tabulatorInstance = null;
    }
  }
}

💡 จุดที่ควรทราบสำหรับ Angular

  • @ViewChild และ ElementRef: ใน Angular เราไม่ควรใช้ document.getElementById แต่ควรใช้ @ViewChild เพื่อดึง reference ของ element มาใช้ใน ngAfterViewInit ( จุดที่ DOM พร้อมที่สุด )
  • ngOnChanges: เมื่อข้อมูลที่ส่งมาจาก @Input() data เปลี่ยนแปลง Hook นี้จะทำงาน เราจึงใช้ .setData() ตรงนี้เพื่อทำ Hot Refresh ข้อมูลในตารางโดยที่ User ไม่รู้สึกว่าตารางถูกโหลดใหม่
  • ::ng-deep: Angular มีระบบ View Encapsulation ( การแยก CSS ของแต่ละ Component ) หากคุณต้องการเขียน CSS ทับ Style ของ Tabulator ภายในไฟล์ .scss ของ Component ต้องใช้คำสั่ง ::ng-deep เพื่อให้ Style เข้าถึง Library ภายนอกได้
  • ngOnDestroy ( Unmount ): สำคัญมากสำหรับการล้าง Event Listeners และ DOM ที่ Tabulator สร้างขึ้น เพื่อไม่ให้เกิดอาการหน่วงเมื่อใช้งานแอปพลิเคชันไปนาน ๆ

อ่านเพิ่มเติม