【问题标题】:Warning 'grid zero width' when using ag-Grid's sizeColumnsToFit() on two separate ag-Grids, displayed by a tab menu在两个单独的 ag-Grid 上使用 ag-Grid 的 sizeColumnsToFit() 时警告“网格零宽度”,由选项卡菜单显示
【发布时间】:2019-05-30 23:18:50
【问题描述】:

在调整 ag-Grid 的大小(更改浏览器窗口的大小)并在两个选项卡之间切换时收到以下警告:

ag-Grid: 试图调用 sizeColumnsToFit() 但网格又回来了 宽度为零,屏幕上可能还看不到网格吗?

我已经在 Stackblitz 中重现了这种情况:

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

这里是测试应用的组成:

  • PrimeNG p-tabMenu 在组件:header.component
  • ag-Grid 在 组件:delleverancer.component 和leverancer.component。

您会在 chrome 开发工具中看到警告错误, 当您调整网格大小并在 tabMenu 'Leverancer' 和 'Delleverancer' 之间切换时。

您可以在此处查看代码:

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

如何删除这个不需要的警告错误?

【问题讨论】:

    标签: angular tabs ag-grid ag-grid-ng2 ag-grid-angular


    【解决方案1】:

    此类错误通常意味着您的应用程序中存在内存泄漏。

    查看您的代码后,我注意到您如何订阅 window:resize 事件

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

    您应该知道,即使在组件被销毁后,此订阅仍然存在。

    您可以在 ngOnDestroy 挂钩中写入 removeEventListener。但是为此,您必须保留对原始附加功能的引用。更好的方法是使用专门的 Angular @HostListener 装饰器来负责removeEventListener

    @HostListener('window:resize')
    onResize() {
      if (!this.gridApi) return;
    
      setTimeout(() => {
        this.gridApi.sizeColumnsToFit();
      });
    }
    

    Forked Stackblitz

    为了不重复自己,您可以创建如下指令:

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

    现在,您需要添加该行为的只是将属性添加到您的网格:

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

    Stackblitz Example

    【讨论】:

    • 大概是这样回答的。不会改变你写的一个字。不错的答案。喜欢@HostListener 和指令的额外建议
    • 您好,如果我正在寻找类似的 React 版本,您能建议我如何解决这个问题吗?
    • 不工作,显示相同的错误,gridPanel.js:814 ag-Grid: 试图调用 sizeColumnsToFit() 但网格以零宽度返回,可能网格在屏幕?即使我在 onFirstDataRendered 事件后调用 sizetoFit
    • @DevinMcQueeney 你能在 stackblitz 中重现它吗?
    【解决方案2】:

    旧线程,但对于反应答案和未来的受害者,我遇到了同样的问题,问题是用 componentWillUnmount 清理事件侦听器。

    要查看您的事件侦听器发生了什么,请使用(在 Chrome 中)getEventListeners(window) 并观察您的组件如何添加它们,但在您更改页面等时不要删除它们。在实施下面的解决方案后,您应该会看到事件当你的组件被销毁时,监听器会被移除。

    需要为监听器使用一个函数,以便您有适当的参考来删除。

    假设基于类的方法:

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

    【讨论】:

    • setTimeout(() =&gt; { this.gridApi.sizeColumnsToFit(); }, 200); 有什么用?您已经在 firstDataRendered 中调用了 sizeColumnsToFit()
    【解决方案3】:

    这对我有帮助

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

    【讨论】:

      【解决方案4】:

      在使用 Bootstrap Angular 选项卡时遇到此问题,但其他库的解决方案应该类似。希望这可以帮助其他仍在努力寻找解决方案的人。

      1. 每个 ag-grid 都需要有 onGridReady 函数。
      2. 显示网格的第一个选项卡没有问题,因为它在 DOM 中呈现时调整列大小以适应它。
      3. 对于其他选项卡中的网格,在选项卡更改时触发的事件中调用 sizeColumnsToFit()(对于 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;
        }
      }
      
      

      【讨论】:

        猜你喜欢
        • 2019-12-26
        • 2020-04-20
        • 2019-08-30
        • 2020-10-28
        • 2017-07-18
        • 2020-05-07
        • 2020-08-23
        • 2020-08-19
        • 2020-08-20
        相关资源
        最近更新 更多