Предупреждение 'нулевой ширины сетки' при использовании sizeColumnsToFit() ag-Grid на двух отдельных ag-гридах, отображаемых в меню вкладок

Получение предупреждения ниже при изменении размера ag-Grid (изменение размера окна браузера) и переключение между двумя вкладками:

ag-Grid: попытался вызвать sizeColumnsToFit(), но сетка возвращается с нулевой шириной, может быть, сетка еще не видна на экране?

Я воспроизвел ситуацию в Stackblitz:

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

Вот состав тестового приложения:

  • PrimeNG p-tabMenu в компоненте: header.component
  • ag-Grid в компонентах: delleverancer.component и leverancer.component.

Вы увидите ошибку предупреждения в инструментах Chrome Dev, когда вы измените размер сетки и переключитесь между tabMenu 'Leverancer' и 'Delleverancer'.

Вы можете увидеть код здесь:

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

Как мне удалить эту нежелательную ошибку предупреждения?

5 ответов

Решение

Подобные ошибки обычно означают, что в вашем приложении есть утечка памяти.

После просмотра вашего кода я заметил, как вы подписываетесь на window:resize событие

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

Вы должны знать, что эта подписка останется там даже после уничтожения компонента.

Вы могли бы написать removeEventListener в ngOnDestroy крюк. Но для этого вы должны сохранить ссылку на оригинальную прикрепленную функцию. Лучше было бы использовать выделенный Angular @HostListener декоратор, который будет нести ответственность за removeEventListener под крюком:

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

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

Разветвленный стекблиц

Чтобы не повторяться, вы можете создать директиву вроде:

AG-грид-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();
  }
}

Теперь все, что вам нужно, чтобы добавить это поведение, это добавить атрибут в вашу сетку:

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

Пример Stackblitz

Старый поток, но для ответа и будущих страдальцев у меня была такая же проблема, и проблема заключалась в очистке прослушивателя событий с помощью componentWillUnmount.

Чтобы увидеть, что происходит с вашими слушателями событий, используйте (в Chrome) getEventListeners (окно) и посмотрите, как ваши компоненты добавляют их, но не удаляют их при смене страниц и т. Д. После реализации решения ниже вы должны увидеть, что слушатели событий удалены. когда ваш компонент разрушен.

Необходимо использовать функцию для слушателя, чтобы у вас была надлежащая ссылка для удаления.

Предполагая подход на основе классов:

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);
 };

в функции рендеринга:

return (
     <div className='ag-theme-material'>
        <AgGridReact
            ...your stuff
            onFirstDataRendered={this.firstDataRendered}
        />
     </div>
 )

Столкнулся с этой проблемой при использовании вкладок Bootstrap Angular, но решение для других библиотек должно быть аналогичным. Надеюсь, это поможет другим, кто все еще пытается найти решение.

  1. Каждая аг-сетка должна иметь функцию onGridReady.
  2. Сетка отображения первой вкладки не имеет проблем с размером столбцов, чтобы они соответствовали тому, как она отображается в DOM.
  3. Для сеток на других вкладках вызовите sizeColumnsToFit() в событии, срабатывающем при изменении вкладки (selectTab для Bootstrap). Проверьте документацию для других соответствующих библиотек.

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>

Машинопись:

      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;
  }
}

Проблема для меня заключалась в том, что на странице были скрытые элементы div, которые также использовали ag-grids, и каждый раз при изменении размера окна те скрытые элементы div, содержимое которых еще не было сгенерировано, приводили к ошибке.

Изменение[hidden]к*ngIfизбавился от ошибок для меня.

HTML

От

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

к

      <div>
  <app-summary>
    *ngIf="showSummaryView"
  ></app-summary>
  <app-detailed
    *ngIf="showDetailedView"
  ></app-detailed>
</div>

Это помогло мне

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

    } catch (error) {

    }
}
Другие вопросы по тегам