11

Getting the warning below when resizing ag-Grid (change size of browser window) and switching between two tabs:

ag-Grid: tried to call sizeColumnsToFit() but the grid is coming back with zero width, maybe the grid is not visible yet on the screen?

I have reproduced the situation in a Stackblitz:

https://angular-jpmxjy.stackblitz.io/

Here is the composition of the test app:

  • PrimeNG p-tabMenu at the component: header.component
  • ag-Grid at the components: delleverancer.component and leverancer.component.

You will see the warning error in chrome dev tools, when you resize the grid and switch between tabMenu 'Leverancer' and 'Delleverancer'.

You can see the code here:

https://stackblitz.com/edit/angular-jpmxjy

How do I remove this unwanted warning error?

enter image description here

Rune Hansen
  • 954
  • 3
  • 16
  • 36

5 Answers5

10

These kind of errors usually mean that you have a memory leak in your application.

After looking at your code I noticed how you subscribe to window:resize event

window.addEventListener("resize", function () { ...

You should know that this subscription will be still there even after component has been destroyed.

You could write removeEventListener in ngOnDestroy hook. But for that you have to keep reference to original attached function. A better way would using dedicated Angular @HostListener decorator that will take responsibility for removeEventListener under the hook:

@HostListener('window:resize')
onResize() {
  if (!this.gridApi) return;

  setTimeout(() => {
    this.gridApi.sizeColumnsToFit();
  });
}

Forked Stackblitz

To not repeat yourself you can create directive like:

ag-grid-resize.directive.ts

import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: '[ag-grid-resize]'
})
export class AgGridResizeDirective {
  private gridApi;

  @HostListener('window:resize')
  onResize() {
    if (!this.gridApi) return;

    setTimeout(() => {
      this.gridApi.sizeColumnsToFit();
    });
  }

  @HostListener('gridReady', ['$event'])
  onGridReady(params) {
    this.gridApi = params.api;

    params.api.sizeColumnsToFit();
  }
}

Now, all you need to add that behavior is to add attribute to your grid:

<ag-grid-angular 
  ...
  ag-grid-resize       <============
>
</ag-grid-angular>

Stackblitz Example

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • Was about of answering the same. Wouldn't change a word you've wrote. Nice answer. Loved the extra suggestion for @HostListener and directive – benshabatnoam Jan 06 '19 at 15:40
  • Hi, if I am looking for a similar version for React, could you suggest how I can solve this issue? – AKJ Apr 12 '19 at 09:17
  • 3
    not working , showing the same error , gridPanel.js:814 ag-Grid: tried to call sizeColumnsToFit() but the grid is coming back with zero width, maybe the grid is not visible yet on the screen? even if i called sizetoFit after onFirstDataRendered event – AhammadaliPK Apr 08 '20 at 02:59
  • @DevinMcQueeney Can you please reproduce it in stackblitz? – yurzui May 22 '20 at 05:24
5

Old thread, but for the react answer and future sufferers, I was having the same problem and the issue was cleaning up the event listener with componentWillUnmount.

To see whats happening with your event listeners use (in Chrome) getEventListeners(window) and watch how your components add them but don't remove them when you change pages, etc. After implementing the solution below you should see the event listeners are removed when your component is destroyed.

Need to use a function for listener so you have proper reference to remove.

Assuming class based approach:

export class someAgGrid extends Component { your brilliance }

componentWillUnmount() {
     window.removeEventListener('resize', this.daListener);
 };

daListener = () => {
    if (!this.gridApi) return;
    setTimeout(() => { this.gridApi.sizeColumnsToFit(); }, 200);
 };

firstDataRendered = (params) => {
    this.gridApi = params.api;
    this.gridApi.sizeColumnsToFit();
    window.addEventListener('resize', this.daListener);
 };

in render function:

return (
     <div className='ag-theme-material'>
        <AgGridReact
            ...your stuff
            onFirstDataRendered={this.firstDataRendered}
        />
     </div>
 )
Jason
  • 2,493
  • 2
  • 27
  • 27
ADayton
  • 51
  • 1
  • 1
  • What's the `setTimeout(() => { this.gridApi.sizeColumnsToFit(); }, 200);` for? You're already calling `sizeColumnsToFit()` inside `firstDataRendered`. – blankface Mar 10 '20 at 00:36
1

Faced this issue while using Bootstrap Angular tabs but solution for other libraries should be similar. Hopefully this might help others who are still struggling for a solution.

  1. Each ag-grid needs to have onGridReady function.
  2. First tab displaying grid has no issue sizing columns to fit as it is rendered in DOM.
  3. For grids in other tabs, call sizeColumnsToFit() in event fired on tab change (selectTab for Bootstrap). Check documentation for other respective libraries.

HTML:

 <tabset type="pills">
    <tab heading="heading1" id="tab1">
        <ag-grid-angular
          class="ag-theme-balham ag-grid-table"
          [rowData]="data1$ | async"
          [defaultColDef]="defaultColDef"
          [columnDefs]="columnDefs1"
          (gridReady)="onGridReady1($event)"
        >
        </ag-grid-angular>
    </tab>
    <tab heading="heading2" id="tab2" (selectTab)="onSelect($event)">
        <ag-grid-angular
          class="ag-theme-balham ag-grid-table"
          [rowData]="data2$ | async"
          [defaultColDef]="defaultColDef"
          [columnDefs]="columnDefs2"
          (gridReady)="onGridReady2($event)"
        >
        </ag-grid-angular>
    </tab>
<tabset>

Typescript:

import { Component, OnInit} from '@angular/core';
import { BehaviorSubject } from 'rxjs';

import { ColDef, GridReadyEvent } from 'ag-grid-community';
import { TabDirective } from 'ngx-bootstrap/tabs';

@Component({
  selector: 'app-tabs',
  templateUrl: './tabs.component.html',
  styleUrls: ['./tabs.component.css'],
})

export class TabsetComponent implements OnInit {

  data1$ = new BehaviorSubject<any[]>([]);
  data2$ = new BehaviorSubject<any[]>([]);

  private gridApi2;
  private gridColumnApi2;

  defaultColDef: ColDef = {
    sortable: true,
    filter: true,
    resizable: true,
  };

  columnDefs1: ColDef[] = [
    { headerName: 'Category', field: 'category' },
    { headerName: 'Name', field: 'name' },
  ];

  columnDefs2: ColDef[] = [
    { headerName: 'Module', field: 'module' },
    { headerName: 'Approval', field: 'approvalName' },
  ];

  constructor() {}

  ngOnInit(): void {}

  // Event fired on tab change, needed only for tabs that are not rendered on page laod
  onSelect(event: TabDirective) {
    switch (event.heading) {
        case 'heading2':
            return this.gridApi2.sizeColumnsToFit();
        default:
            return;
    }
  }

  // tab displayed on page load can call sizeColumnsToFit() directly
  onGridReady1(event: GridReadyEvent) {
      event.api.sizeColumnsToFit();
  }

  onGridReady2(event: GridReadyEvent) {
    this.gridApi2 = event.api;
    this.gridColumnApi2 = event.columnApi;
  }
}

1

The problem for me was that there were hidden divs on the page that also used ag-grids, and every time the window was resized, those hidden divs that don't have their contents generated yet would result in the error.

Changing [hidden] to *ngIf got rid of the errors for me.

HTML

From

<div>
  <app-summary>
    [hidden]="showSummaryView"
  ></app-summary>
  <app-detailed
    [hidden]="showDetailedView"
  ></app-detailed>
</div>

to

<div>
  <app-summary>
    *ngIf="showSummaryView"
  ></app-summary>
  <app-detailed
    *ngIf="showDetailedView"
  ></app-detailed>
</div>
IceTea
  • 598
  • 1
  • 6
  • 19
0

this helped for me

ngOnDestroy() {
    try { 
        if (this.gridApi) {
            this.gridApi.destroy();
            this.gridApi = false;
        }

    } catch (error) {

    }
}
Michal Orlík
  • 501
  • 4
  • 3