【问题标题】:Fitting a mat-accordion inside ag-grid在 ag-grid 内安装一个 mat-accordion
【发布时间】:2020-12-07 03:04:35
【问题描述】:

我有一个相当标准的带有嵌套组件的 ag-grid 设置,如下所示:

import { Component } from '@angular/core';
import * as agGrid from 'ag-grid-community';
import { NestedMatExpansionPanelComponent } from './nested-mat-expansion-panel/nested-mat-expansion-panel.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'aggrid-material-expansion-panel';

  dataToShow = [
    { name: 'name1', companyCountry: 'UK', reference: 'Ref 1' },
    { name: 'name2', companyCountry: 'Germany', reference: 'Ref 2' },
    { name: 'name3', companyCountry: 'France', reference: 'Ref 3' },
    { name: 'name4', companyCountry: 'UK', reference: 'Ref 4' },
    { name: 'name5', companyCountry: 'USA', reference: 'Ref 5' },
  ];

  columnDefs = [
    // tslint:disable-next-line: max-line-length
    { headerName: 'Name', colId: 'name', cellRenderer: 'nestedMatExpansionPanelRenderer', filter: false, sortable: false },
    { headerName: 'Country', field: 'companyCountry', sortable: true, filter: true },
    { headerName: 'Reference', field: 'reference', sortable: true, filter: true }
  ];

  // agG_rid
  gridApi: agGrid.GridApi;
  gridColumnApi: agGrid.ColumnApi;
  gridOptions: agGrid.GridOptions = {};
  public defaultColDef: any;
  public columnTypes: any;
  public context: any;
  public frameworkComponents: any;
  public sortingOrder: any;

  constructor() {
    this.initTable();
  }

  public onGridReady(params: any) {
    // this.gridApi = this.gridOptions.api;
    // this.gridColumnApi = this.gridOptions.columnApi;
    this.gridApi = params.api;
    this.gridColumnApi = params.columnApi;

    this.gridApi.sizeColumnsToFit();
  }

  public initTable(): void {
    this.defaultColDef = {
      flex: 1,
      autoHeight: true,
      editable: false,
      enableBrowserTooltips: true,
      resizable: true,
      filter: 'agTextColumnFilter',
      suppressMenu: true,
      floatingFilterComponentParams: { suppressFilterButton: true },
      filterParams: { newRowsAction: 'keep' },
      sortable: true,
    };
    this.columnTypes = {
      numericColumn: { filter: 'agnumericColumnFilter' },
      dateColumn: {
        filter: 'agDateColumnFilter',
        filterParams: {
          newRowsAction: 'keep',
          comparator(filterLocalDateAtMidnight, cellValue) {
            const dateParts = cellValue.split('/');
            const day = Number(dateParts[2]);
            const month = Number(dateParts[1]) - 1;
            const year = Number(dateParts[0]);
            const cellDate = new Date(day, month, year);
            if (cellDate < filterLocalDateAtMidnight) {
              return -1;
            } else if (cellDate > filterLocalDateAtMidnight) {
              return 1;
            } else {
              return 0;
            }
          }
        }
      }
    };
    this.sortingOrder = ['desc', 'asc'];
    this.context = { componentParent: this };
    this.frameworkComponents = {
      nestedMatExpansionPanelRenderer: NestedMatExpansionPanelComponent,
    };
  }

  public onRowClicked($event) {
    //
  }

}

如你所见,我有

  autoHeight: true,

所以每一行都应该根据嵌入式手风琴的展开状态自动获得正确的高度,但是该行的输出高度计算不正确:

如何根据嵌入式扩展面板的状态自动调整每行的高度,以便在打开或关闭每行内的扩展面板时不会有任何空余空间?

Link to the repository

【问题讨论】:

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


    【解决方案1】:

    基本上,您遇到的问题是 MatExpansionPanel 和 autoHeight 如何在 ag-grid 中计算的综合问题。

    使用 autoHeight 他们从单元格中获取内容,并将其放在一个临时的不可见元素中,可能位于 document.body 元素中。问题是此时没有对元素应用正确的样式,它显示了您所面对的高度。所以,autoHeight 不是这里的解决方案,应该设置为false。

    那么如何实现手动高度计算。 Ag-grid 在node 上有一个setRowHeight 属性。您可以使用它来设置高度。从那里需要通知网格 API,所有行都改变了它们的高度,并且可以在此基础上重新计算,方法是调用 onRowHeightChanged()。获得这种通信的一种方法是使用普通服务:

    @Injectable()
    export class GridService {
      readonly updateHeight$ = new Subject<void>();
    }
    

    从您在模板中创建 ag-grid 的组件中,您应该将此服务器添加到 providers 数组并监听主题(使用 debounce 以确保最初计算所有行):

    @Component({
      // ...,
      providers: [GridService]
    })
    export class GridComponent {
      gridApi: agGrid.GridApi;
    
      constructor(private gs: GridService) {
        this.gs.updateHeight$.pipe(
          debounceTime(1)
        ).subscribe(() => {
          this.gridApi?.onRowHeightChanged();
        });
      }
    
      onGridReady(params: any) {
        this.gridApi = params.api;
      }
    }
    

    现在我们需要在单元格渲染器框架组件中实现以下逻辑:

    export class ExpansionPanelComponent implements ICellRendererAngularComp, AfterViewInit {
      public params: ICellRendererParams;
    
      constructor(private el: ElementRef<HTMLElement>, private gs: GridService) {}
    
      agInit(params: ICellRendererParams): void {
        this.params = params;
      }
    
      ngAfterViewInit(): void {
        // inside setTimeout because the accordion is not properly sized (bug) and it will be too big
        setTimeout(() => this.updateHeight());
      }
    
      updateHeight(): void {
        // inside setTimeout because the accordion is not properly sized (bug) and it will be too big
        setTimeout(() => {
          this.params?.node.setRowHeight(this.el.nativeElement.offsetHeight);
          this.gs.updateHeight$.next();
        });
      }
    
      refresh(params: any): boolean {
        return false;
      }
    }
    

    我创建了一个有效的拉取请求here


    要删除左侧的填充,您可以将以下内容添加到您的 columnDefs 数组中:

    columnDefs = [
      {
        //...,
        cellRenderer: 'nestedMatExpansionPanelRenderer', 
        cellStyle: { 'padding-left': 0 }
      },
      // ...
    ]
    

    【讨论】:

    • @Excellent answer Poul,你几乎做到了。最后一点:您能否更新您的答案,以便面板的左右两侧 [图像中的“B”区域] 不会有任何空白?
    • @MHOOS 您可以通过在列定义中添加cellStyle(或cellClass,如果您想重新使用它)轻松解决此问题。我会更新我的答案
    猜你喜欢
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 2016-08-19
    • 2019-11-07
    • 2018-02-17
    • 2021-12-17
    • 1970-01-01
    • 2020-02-03
    相关资源
    最近更新 更多