javascriptangulartypescriptuser-interfacengx-datatable

Recalculate ngx-datatable on Click Event from another Directive


I have a Side Navigation with a docking feature and a data table in Main View. Upon un-docking the side navigation, the data table in Main View does not recalculate (this will leave some empty space that the Side Navigation came from) so I need to recalculate manually upon click. However, problem lies in the fact that the Side Navigation and Data Table are two different directives.

PS. I have multiple modules with different data table names

Same Problem here: https://github.com/swimlane/ngx-datatable/issues/193#issuecomment-334809144


Solution

  • I made it using MutationObserver which tracks style change for left menu and sets DatatableComponent width.

    @Directive({ selector: '[sidePanelToggle]' })
    export class SidePanelToggleDirective implements OnDestroy {
      private changes: MutationObserver;
      wasVisible: boolean | undefined;
    
      constructor(
        private elementRef: ElementRef,
        @Host() @Self() private tableComponent: DatatableComponent
      ) {
        this.changes = new MutationObserver((mutations: MutationRecord[]) => {
            mutations.forEach((mutation: MutationRecord) => {
                const sideNavElement = mutation.target as HTMLElement;
                const tableElement = this.elementRef.nativeElement as HTMLElement;
                const isVisible = sideNavElement?.style.visibility === 'visible';
                if (this.wasVisible === undefined || this.wasVisible && !isVisible || !this.wasVisible && isVisible) {
                  if (tableElement.style.width) {
                    tableElement.style.width = `${SidePanelToggleDirective.floatOrZero(tableElement.style.width) + (isVisible ? -sideNavElement.offsetWidth : sideNavElement.offsetWidth)}px`;
                    console.log('Already set before, now will be ', tableElement.style.width);
                  }
                  else {
                    tableElement.style.width = `${tableElement.offsetWidth + (isVisible ? -sideNavElement.offsetWidth : sideNavElement.offsetWidth)}px`;
                    console.log('Setting first time as ', tableElement.style.width);
                  }
                  this.tableComponent.recalculate();
                }
                this.wasVisible = isVisible;
            });
        });
    
        document.querySelectorAll('mat-sidenav[position="start"]').forEach(element => {
          this.changes.observe(element, { attributeFilter: ['style'] });
        });
      }
    
      private static floatOrZero(value: any) {
        const result = parseFloat(value);
        return isNaN(result) ? 0 : result;
      }
    
      ngOnDestroy(): void {
        this.changes.disconnect();
      }
    }
    

    Change in markup is minimal:

    <ngx-datatable sidePanelToggle ...