AgGrid Select 单元格编辑器
AgGrid Select Cell Editor
我正在使用 v8 angular ag-grid。
this.columns = [
{headerName: "XYZ", field:"XYZ",
editable: true ,cellEditor: "select",
cellEditorParams: {values : [// list of values]},
]
我想创建一个下拉列表 select,只需单击一下键盘导航(在键盘上按下的字母应显示以该字母开头的值)。
您可以为此使用自动完成功能。首先,你需要准备自己的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',
field: 'xyz',
filter: 'agTextColumnFilter',
suppressMenu: true,
valueFormatter: (event: any) => {
let data = event.data
return data.xyz + " - " + data.desc
}
},
{
headerName: 'DESC',
field: 'desc',
filter: 'agTextColumnFilter',
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>
请尝试 return。我在本地尝试时可以得到解决方案。
工作演示:https://stackblitz.com/edit/angular-ivy-ipvkac?file=src/app/app.component.ts
我能够通过创建单元格渲染器而不是编辑器来实现所需的效果 - 这帮助我通过单击获得下拉菜单并使用 angular material 实现了下拉菜单。
我正在使用 v8 angular ag-grid。
this.columns = [
{headerName: "XYZ", field:"XYZ",
editable: true ,cellEditor: "select",
cellEditorParams: {values : [// list of values]},
]
我想创建一个下拉列表 select,只需单击一下键盘导航(在键盘上按下的字母应显示以该字母开头的值)。
您可以为此使用自动完成功能。首先,你需要准备自己的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',
field: 'xyz',
filter: 'agTextColumnFilter',
suppressMenu: true,
valueFormatter: (event: any) => {
let data = event.data
return data.xyz + " - " + data.desc
}
},
{
headerName: 'DESC',
field: 'desc',
filter: 'agTextColumnFilter',
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>
请尝试 return。我在本地尝试时可以得到解决方案。
工作演示:https://stackblitz.com/edit/angular-ivy-ipvkac?file=src/app/app.component.ts
我能够通过创建单元格渲染器而不是编辑器来实现所需的效果 - 这帮助我通过单击获得下拉菜单并使用 angular material 实现了下拉菜单。