AG-Grid 的日期时间过滤器 - 单击按钮时清除输入文本 DTPicker.jsxApp.jsx

问题描述

基于 this proposed solution in the AG-Grid Github issues,我正在尝试在我的 jQuery DateTime Picker/React 项目中实现一个 AG_Grid 作为过滤器。

我目前已设置好我的表格,以便我可以通过单击按钮清除已应用于我的表格的过滤器。所需的行为是,一旦单击“重置过滤器”按钮,过滤器AND 过滤器输入内的文本应被清除。按照现在的设置,过滤器正在根据需要从表中清除,但是当我重新打开过滤器输入时,上一个过滤器中的文本仍然存在。


我有一个 Code Sandbox set up here,其中包含我当前设置的简化版本。

重新创建的步骤:

  • 为事件时间戳列打开过滤器
  • 将过滤器应用于事件时间戳列 (2020/01/31 00:00 - 2020/06/31 00:00)
  • 点击表格顶部的“重置过滤器”
  • 为事件时间戳列打开过滤器
  • 请注意,来自上一个过滤器的文本仍会填充输入
const App = () => {
  const [gridApi,setGridApi] = useState([]);
  const [gridColumnApi,setGridColumnApi] = useState([]);
  const [rowData,setRowData] = useState([]);

  useEffect(() => {
    const formattedDates = dataSet.map((data) => {
      return {
        id: data.id,eventTimestamp: new Date(data.eventTimestamp)
      };
    });
    setRowData(formattedDates);
  },[]);

  // ***************************************************
  // The Handle Click logic for the reset filters button:
  // ***************************************************
  const resetAppliedFilters = () => {
    gridApi.setFilterModel(null);
    CustomDateComponent.prototype.setDate(null);
  };

  const cols = [
    {
      field: "id",headerName: "ID",minWidth: 100,maxWidth: 150
    },{
      field: "eventTimestamp",headerName: "Event Timestamp",minWidth: 225,filter: "agDateColumnFilter",filterParams: {
        defaultOption: "inRange",// ***************************************************
        // Comparator function for datetime picker:
        // ***************************************************
        comparator: function (filterLocalDate,cellValue) {
          filterLocalDate.setMilliseconds(0);
          cellValue.setMilliseconds(0);
          let filterBy = filterLocalDate.getTime();
          let filterMe = cellValue.getTime();
          if (filterBy === filterMe) {
            return 0;
          }

          if (filterMe < filterBy) {
            return -1;
          }

          if (filterMe > filterBy) {
            return 1;
          }
        }
      }
    }
  ];

  const onGridReady = (params) => {
    setGridApi(params.api);
    setGridColumnApi(params.columnApi);
    // ***************************************************
    // Table event listener:
    // ***************************************************
    params.api.addGlobalListener((type,event) => {
      switch (type) {
        case "filterChanged":
          console.log(event);
          return;
        default:
          return null;
      }
    });
  };

  return (
    <div className="App">
      <Button onClick={resetAppliedFilters} variant="outlined">
        Reset Filters
      </Button>
      <hr />
      <div
        className={"ag-theme-balham"}
        style={{ height: "86vh",width: "100%" }}
      >
        <AgGridReact
          onGridReady={onGridReady}
          rowData={rowData}
          rowSelection="multiple"
          defaultColDef={{
            flex: 1,resizable: true,sortable: true,filter: true
          }}
          pagination
          columnDefs={cols}
          components={{
            agDateInput: CustomDateComponent
          }}
        />
      </div>
    </div>
  );
};

// ***************************************************
// Custom datetime picker component:
// ***************************************************
function CustomDateComponent() {}

CustomDateComponent.prototype.init = function (params) {
  this.params = params;
  this.eGui = document.createElement("div");
  this.eInput = document.createElement("input");
  this.eGui.appendChild(this.eInput);
  jQuery(this.eInput).datetimepicker({
    mask: true,// '9999/19/39 29:59' - digit is the maximum possible for a cell
    onChangeDateTime: this.onDateChanged.bind(this)
  });
};

CustomDateComponent.prototype.onDateChanged = function (currentDateTime) {
  this.date = currentDateTime;
  this.params.onDateChanged();
};

CustomDateComponent.prototype.getGui = function () {
  return this.eGui;
};

CustomDateComponent.prototype.getDate = function () {
  return this.date;
};

CustomDateComponent.prototype.setDate = function (date) {
  this.date = date;
};

CustomDateComponent.prototype.destroy = function () {
  jQuery(this.eInput).datetimepicker("destroy");
};

export default App;

如果有人能帮助我或指出正确的方向,我们将不胜感激。 TIA!

解决方法

当我试图自己解决这个问题时,我发现 this Stack Overflow article 解释了为什么你应该同时使用 React 和 jQuery。这是一个很好的建议,因为您可以在上面的示例中看到,状态没有得到适当的管理以及其他问题。

在进一步阅读 AG-Grid 文档的 custom date component 部分和 this post on AG-Grid's blog 后,我能够实现使用 react-datetime-picker 作为自定义过滤器组件的解决方案。然后,您必须将其传递给表的 frameworkComponents 属性。

LIVE DEMO ON STACK BLITZ

DTPicker.jsx

import DateTimePicker from "react-datetime-picker";

export default forwardRef((props,ref) => {
  const [selectedDate,setSelectedDate] = useState(null);

  function handleDateChange(d) {
    if (d) {
      d = new Date(d);
      setSelectedDate(d);
    } else {
      setSelectedDate(null);
    }
  }

  // props.onDateChanged must be called after updating our component's internal state:
  useEffect(props.onDateChanged,[selectedDate]);

  // getDate and setDate are required by AG-Grid to sync ag-Grid's date 
  // filter value with that of our components:
  useImperativeHandle(ref,() => {
    return {
      getDate: () => {
        return selectedDate;
      },setDate: d => {
        handleDateChange(d);
      }
    };
  });

  return (
    <>
      <DateTimePicker
        onChange={handleDateChange}
        value={selectedDate}
        maxDetail="second"
        disableCalendar={true}
        disableClock={true}
      />
    </>
  );
});

App.jsx

import DTPicker from './DTPicker'

// Add your custom filter logic in your column:
const cols = [
    ...,{
      field: "eventTimestamp",headerName: "Event Timestamp",filter: "agDateColumnFilter",filterParams: {
        defaultOption: "inRange",comparator: function(filterLocalDate,cellValue) {
          let filterBy = filterLocalDate.getTime();
          let filterMe = cellValue.getTime();
          if (filterBy === filterMe) {
            return 0;
          }

          if (filterMe < filterBy) {
            return -1;
          }

          if (filterMe > filterBy) {
            return 1;
          }
        }
      }
    },...
  ];

<AgGridReact
    ...
    frameworkComponents={{
        agDateInput: DTPicker
    }}
    ...
/>