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

Datetime filter for AG-Grid - Clear input text on button click

基于 this proposed solution in the AG-Grid Github issues, I am trying to implement a jQuery DateTime Picker as a filter in my React/AG_Grid 项目。

我目前设置了 table,这样我就可以通过单击按钮清除已应用于我的 table 的过滤器。期望的行为是单击“重置过滤器”按钮后,应清除过滤器 AND 过滤器输入中的文本。正如现在的设置,过滤器正在根据需要从 table 中清除,但是当我重新打开过滤器输入时,前一个过滤器的文本仍然存在。


我有一个 Code Sandbox set up here 和我当前设置的简化版本。

重建步骤:

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,
            minWidth: 100,
            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!

当我试图自己解决这个问题时,我遇到了 这解释了为什么你应该 NOT 一起使用 React 和 jQuery。这是一个很好的建议,因为您可以在上面的示例中看到,除其他问题外,状态没有得到妥善管理。

进一步阅读 AG-Grid 文档后,custom date component section and this post on AG-Grid's blog, I was able to implement a solution that uses react-datetime-picker 作为自定义过滤器组件。然后你必须将它传递给 table 的 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
    }}
    ...
/>