AgGrid 选择单元格编辑器

问题描述

我使用的是 v8 angular ag-grid。

this.columns = [
    {headerName: "XYZ",field:"XYZ",editable: true,cellEditor: "select",cellEditorParams: {values : [// list of values]},] 

我想通过单击鼠标和键盘导航来创建下拉选择(按下键盘上的字母应显示以该字母开头的值)。

解决方法

您可以为此使用自动完成功能。首先,您需要准备自己的 AutoComplete 组件。

AutoCompleteComponent.ts

import { Component,AfterViewInit,ViewChild,ViewEncapsulation,ElementRef,HostListener } from '@angular/core';
import { ICellEditorAngularComp } from 'ag-grid-angular'; 

@Component({
  selector: 'auto-complete',encapsulation: ViewEncapsulation.None,template: ` 
        <input #input
            [(ngModel)]="inputValue"
            (ngModelChange)="processDataInput($event)"  >
        <ag-grid-angular 
            [style.height]="gridHeight + 'px'"
            [style.max-width]="gridWidth + 'px'"
            class="ag-theme-balham"
            [rowData]="rowData" 
            [columnDefs]="columnDefs"
            [rowSelection]="rowSelection"
            (gridReady)="onGridReady($event)"
            [headerHeight]="headerHeight"
            (rowClicked)="rowClicked($event)">
        </ag-grid-angular>
    `
})
export class AutoCompleteComponent implements ICellEditorAngularComp,AfterViewInit {
  // variables for agGrid
  public params: any;
  public gridApi: any;
  public rowData: any;
  public columnDefs: [{}];
  public rowSelection: string = 'single';
  public columnFilter: any;
  // variables for component
  public returnObject: boolean;
  public cellValue: string;
  public filteredRowData: any;
  public inputValue: string;
  public apiEndpoint: string;
  public gridHeight: number = 175;
  public gridWidth: number = 375;
  public useApi: boolean;
  public propertyName: string;
  public isCanceled: boolean = true;
  public selectedObject: any = {}
  public headerHeight: number = 0;
  private cellFocusIndex: number;

  @ViewChild("input",{ static: false }) input: ElementRef;
  showedColumn: any;

  constructor() { }


  // will be selected if there is a default value
  ngAfterViewInit() {
    window.setTimeout(() => {
      if (this.inputValue == this.cellValue) {
        this.input.nativeElement.select();
      } else {
        this.input.nativeElement.focus();
      }
      if (this.inputValue && !this.useApi) this.updateFilter();
    })
  }

  // ICellEditorAngularComp functions
  agInit(params: any): void {
    this.params = params;
    if (!params.rowData) {
      this.apiEndpoint = params.apiEndpoint;
      this.useApi = true;
      this.rowData = [{}]
    } else {
      this.rowData = params.rowData;
    }
    if (params.gridHeight) this.gridHeight = params.gridHeight;
    if (params.gridWidth) this.gridWidth = params.gridWidth;
    params.columnDefs.forEach((el: any) => {
      if (typeof el.filter === "undefined") {
        el.filter = 'agTextColumnFilter'
      }
    });
    this.columnDefs = params.columnDefs;
    this.propertyName = params.propertyRendered;
    this.showedColumn = params.showedColumn;
    this.cellValue = params.data[this.propertyName];
    this.returnObject = params.returnObject;

    if (!params.charPress) {
      if (this.cellValue) this.inputValue = this.cellValue;
    } else {
      this.inputValue = params.charPress;
    }
  }

  getValue(): any {
    if (!this.returnObject) return this.selectedObject[this.propertyName];
    return this.selectedObject;
  }
  isPopup(): boolean {
    return true;
  }
  isCancelAfterEnd(): boolean {
    return this.isCanceled
  }

  // ag-Grid functions
  onGridReady(params: any) {
    this.gridApi = params.api;
    this.gridApi.sizeColumnsToFit();
    this.columnFilter = this.gridApi.getFilterInstance(this.propertyName);
  }

  // component functions
  // double clicked value will be selected and combobox will be closed.
  rowClicked(params: any) {
    this.selectedObject = params.data;
    this.isCanceled = false;
    this.params.api.stopEditing();
  }


  // Board Event
  @HostListener('keydown',['$event'])
  onKeydown(event: any) {
    event.stopPropagation();
    if (event.key == "Escape") {
      this.params.api.stopEditing();
      return false;
    }
    if (event.key == "Enter" || event.key == "Tab") {
      this.rowConfirmed();
      return false;
    }
    if (event.key == "ArrowUp") {
      this.navigateGrid();
      if (this.cellFocusIndex == 0 && this.gridApi.getFocusedCell().rowIndex == 0) { //-- yukarı çıkmak istiyor
        this.input.nativeElement.focus();
      } else {
        this.cellFocusIndex = this.gridApi.getFocusedCell().rowIndex;
      }
      return false;
    }
    if (event.key == "ArrowDown") {
      this.navigateGrid();
      return false;
    }
  }

  processDataInput(event: any) {
    this.updateFilter()
  }

  updateFilter() {
    this.columnFilter.setModel({
      type: 'contains',filter: this.inputValue,});
    this.columnFilter.onFilterChanged();
    if (this.gridApi.getDisplayedRowAtIndex(0)) {
      this.gridApi.getDisplayedRowAtIndex(0).setSelected(true);
      this.gridApi.ensureIndexVisible(0,'top');
    } else {
      this.gridApi.deselectAll();
    } 
  }

  // Enter Event Process
  rowConfirmed() {
    if (this.gridApi.getSelectedRows()[0]) {
      this.selectedObject = this.gridApi.getSelectedRows()[0];
      this.isCanceled = false;
    }
    this.params.api.stopEditing();
  } 

  // Arrow change event
  // The data navigated on it is written to adjust its position on the screen with the arrow keys.
  navigateGrid() {
    if (this.gridApi.getFocusedCell() == null || this.gridApi.getDisplayedRowAtIndex(this.gridApi.getFocusedCell().rowIndex) == null) { // check if no cell has focus,or if focused cell is filtered
      this.gridApi.setFocusedCell(this.gridApi.getDisplayedRowAtIndex(0).rowIndex,this.showedColumn != undefined ? this.showedColumn : this.propertyName);
      this.gridApi.getDisplayedRowAtIndex(this.gridApi.getFocusedCell().rowIndex).setSelected(true);
    } else {
      this.gridApi.setFocusedCell(this.gridApi.getFocusedCell().rowIndex,this.showedColumn != undefined ? this.showedColumn : this.propertyName);
      this.gridApi.getDisplayedRowAtIndex(this.gridApi.getFocusedCell().rowIndex).setSelected(true);
    }
  }
}

新创建的组件必须在模块中定义

custom.module.ts

import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AgGridModule} from 'ag-grid-angular';
import {AutoCompleteComponent} from './auto-complete.component';

@NgModule({
  declarations: [CustomComponent],imports: [CommonModule,AgGridModule.withComponents([AutoCompleteComponent])],exports: [],providers: []
})
export class CustomModule {
}

我们的新组件现在可以使用了

在 custom.component.ts 中


  frameworkComponents: any = { 
    autoComplete: AutoCompleteComponent
  };

columnsDef = [
{
        headerName: 'XYZ,field: 'xyz',editable: true,filter: 'agSetColumnFilter',cellEditorSelector: function () {
          return {
            component: 'autoComplete',params: {
              propertyRendered: 'xyz',returnObject: true,showedColumn: 'xyz',rowData: [{xyz : '1',desc : 'One'},{xyz :'2',desc : 'Two'},{xyz:'3',desc : 'Three'}],columnDefs: [
                {
                  headerName: 'XYZ',filter: 'agTextColumnFilter',suppressMenu: true,valueFormatter: (event: any) => {
                    let data = event.data
                    return data.xyz + " - " + data.desc
                  }
                },{
                  headerName: 'DESC',field: 'desc',hide: true
                }
              ]
            }
          }
        },comparator: this.customComparator,valueGetter: (event: any) => {
           const val = event.data.xyz;
            return val.xyz+ " - " + val.desc;
        }
      }]

在custom.component.html

<ag-grid-angular #agGrid (gridReady)="onGridReady($event)"
   (selectionChanged)="onSelectionChanged($event)" 
   [columnDefs]="columnDefs" 
   [frameworkComponents]="frameworkComponents"  
   [rowData]="rowData" 
   [suppressRowClickSelection]="true" 
   class="ag-theme-balham"  >
</ag-grid-angular>

请尝试返回。当我在本地尝试时,我可以得到解决方案。

工作演示:https://stackblitz.com/edit/angular-ivy-ipvkac?file=src/app/app.component.ts