1

简而言之:有没有办法为数字列过滤器实现自定义比较器?

很长的故事:

我在 Angular (2) 中使用 ag-grid。我为我的 ag-grid 中的单元格提供了我自己的组件:

let column = {
  headerName: column.header,
  field: column.id,
  cellRendererFramework: DynamicComponent,
  filter: this.convertFormatToFilterType(column.format) // returns "text", "number" or "date"
}

为了使过滤器正确地从我的单元格中获取值,我提供了自定义比较器(这个用于文本列过滤器):

if (c.filter === "text")
  c['filterParams'] = {
    textCustomComparator: (filter, cell, filterText): boolean => {
    var filterTextLowerCase = filterText.toLowerCase();
    var valueLowerCase = cell.value.toString().toLowerCase();
    switch (filter) {
      case 'contains':
        return valueLowerCase.indexOf(filterTextLowerCase) >= 0;
      case 'notContains':
        return valueLowerCase.indexOf(filterTextLowerCase) === -1;
      case 'equals':
        return valueLowerCase === filterTextLowerCase;
      case 'notEqual':
        return valueLowerCase != filterTextLowerCase;
      case 'startsWith':
        return valueLowerCase.indexOf(filterTextLowerCase) === 0;
      case 'endsWith':
        var index = valueLowerCase.lastIndexOf(filterTextLowerCase);
        return index >= 0 && index === (valueLowerCase.length - filterTextLowerCase.length);
      default:
        // should never happen
        console.warn('invalid filter type ' + filter);
          return false;
        }
      }
    };

您可以看到我需要使用“cell.value”访问单元格的值。上面的代码工作正常。

我遇到的麻烦是为数字列过滤器提供类似的功能——它们似乎没有使用任何自定义比较器。因此,发生了什么,过滤器尝试直接访问单元格的值,而不是使用“cell.value”。

那么,有没有办法为数字列过滤器实现自定义比较器?或者,如果没有,在这种情况下,我可以通过其他任何方式正确地从我的单元格中获取值吗?

4

1 回答 1

1

我最终做的是实现一个ag-grid 自定义过滤器组件

import { Component, ViewChild, ViewContainerRef } from '@angular/core';

import { IFilterParams, IDoesFilterPassParams, RowNode, IAfterGuiAttachedParams } from 'ag-grid/main';
import { IFilterAngularComp } from 'ag-grid-angular/main';

// https://www.ag-grid.com/javascript-grid-filter-component/#gsc.tab=0 / Angular Filtering
// create your filter as a Angular component
@Component({
    selector: 'filter-cell',
    template: `
    <select #select (ngModelChange)="onSelectChange($event)" [ngModel]="operator">
      <option value="eq">Equals</option>
      <option value="neq">Not equal</option>
      <option value="lt">Less than</option>
      <option value="lte">Less than or equals</option>
      <option value="gt">Greater than</option>
      <option value="gte">Greater than or equals</option>
      <option value="inrange">In range</option>
    </select>

    <br>

    <input #input (ngModelChange)="onChange($event)" [ngModel]="text">
    <br>
    <div *ngIf='operator === "inrange"'>
      <input #input2 (ngModelChange)="onChange2($event)" [ngModel]="text2">
    </div>
    `,
    styles: ['select { margin: 2px 4px; }', 'input { height: 26px; margin: 2px 4px; }']
})
export class GridNumberFilterComponent implements IFilterAngularComp {
    private params: IFilterParams;
    private valueGetter: (rowNode: RowNode) => any;
    public operator: string = 'eq';
    public text: string = '';
    public text2: string = '';

    @ViewChild('select', { read: ViewContainerRef }) public select;
    @ViewChild('input', { read: ViewContainerRef }) public input;
    @ViewChild('input2', { read: ViewContainerRef }) public input2;

    agInit(params: IFilterParams): void {
        this.params = params;
        this.valueGetter = params.valueGetter;
    }

    isFilterActive(): boolean {
        return this.text !== null && this.text !== undefined && this.text !== '';
    }

    doesFilterPass(params: IDoesFilterPassParams): boolean {
        let cellNumber = Number(this.valueGetter(params.node).value);
        let filterNumber = this.text ? Number(this.text) : -Infinity;
        let filterNumber2 = this.text2 ? Number(this.text2) : Infinity;

        switch (this.operator) {
            case 'eq': return cellNumber === filterNumber;
            case 'neq': return cellNumber !== filterNumber;
            case 'lt': return cellNumber < filterNumber;
            case 'lte': return cellNumber <= filterNumber;
            case 'gt': return cellNumber > filterNumber;
            case 'gte': return cellNumber >= filterNumber;
            case 'inrange': return cellNumber >= filterNumber && cellNumber <= filterNumber2;

            default: return true;
        }
    }

    getModel(): any {
        return { value: this.text };
    }

    setModel(model: any): void {
        this.text = model ? model.value : '';
    }

    afterGuiAttached(params: IAfterGuiAttachedParams): void {
        this.input.element.nativeElement.focus();
    }

    componentMethod(message: string): void {
        alert(`Alert from PartialMatchFilterComponent ${message}`);
    }

    onSelectChange(newValue): void {
        if (this.operator !== newValue) {
            this.operator = newValue;
            this.params.filterChangedCallback();
        }
    }

    onChange(newValue): void {
        if (this.text !== newValue) {
            this.text = newValue;
            this.params.filterChangedCallback();
        }
    }

    onChange2(newValue): void {
        if (this.text2 !== newValue) {
            this.text2 = newValue;
            this.params.filterChangedCallback();
        }
    }
}

我像这样添加到我的专栏中:

let column = {
  headerName: column.header,
  field: column.id,
  cellRendererFramework: DynamicComponent,
  filterFramework: GridNumberFilterComponent
}
于 2017-06-16T15:03:03.757 回答