[Python] Custom DateTime Filter For AG-Grid (in Dash) [closed]

Discussão em 'Python' iniciado por Stack, Abril 11, 2025.

  1. Stack

    Stack Membro Participativo

    I’m presently trying to use Dash AG-Grid for a use-case in my org. One of those is to have filters through DateTime format (“YYYY-MM-DD HH:mm”). Since, the pre-configured agDateColumnFilter doesn’t allow inputs through the aforementioned format, I’m now working on a custom script for the same. A snippet of it goes like this (I’m obscuring certain aspects of it to maintain confidentiality):

    ABC.py:

    # Dynamically generate columnDefs
    columnDefs = []
    for column in table_column_info:
    col_name = column["col_name"]
    data_type = column["data_type"]

    # Add the column definition
    column_def = {
    "field": col_name,
    "cellRenderer": "SpinnerCellRenderer",
    "sortable": True,
    "resizable": True,
    "headerClass": "abcd",
    "cellStyle": {"whiteSpace": "normal", "wordWrap": "break-word"},
    "floatingFilter": True,
    }

    # Determine the filter type based on the data type

    if "datetime" in data_type.lower():
    column_def["filter"] = "DateTimeFilter"

    elif data_type.lower() in ["string", "object"]:
    column_def["filter"] = "agTextColumnFilter"
    elif "int" or "float" or "double" in data_type.lower():
    column_def["filter"] = "agNumberColumnFilter"

    # if filter_type:
    # column_def["filter"] = filter_type

    columnDefs.append(column_def)

    # Render the AgGrid component
    return dag.AgGrid(
    id="table-grid-view",
    columnDefs=columnDefs,
    defaultColDef={
    "flex": 1,
    "minWidth": 150,
    "sortable": True,
    "resizable": True,
    },
    rowModelType="infinite", # Use infinite row model
    dashGridOptions={
    "rowBuffer": 0,
    "maxBlocksInCache": 2,
    "cacheBlockSize": 100,
    "cacheOverflowSize": 2,
    "maxConcurrentDatasourceRequests": 2,
    "infiniteInitialRowCount": 1,
    "pagination": True,
    "rowHeight": 30,
    },
    )


    dashAgGridComponentFunctions.js: (in assets folder)

    var dagcomponentfuncs = window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {};
    const [useImperativeHandle, useState, useEffect, forwardRef] = [
    React.useImperativeHandle,
    React.useState,
    React.useEffect,
    React.forwardRef,
    ];

    dagcomponentfuncs.DateTimeFilter = forwardRef((props, ref) => {
    const [filterType, setFilterType] = useState("equals"); // Default filter type
    const [dateFrom, setDateFrom] = useState(""); // Start date
    const [dateTo, setDateTo] = useState(""); // End date (for "inRange")

    // Expose AG Grid Filter Lifecycle callbacks
    useImperativeHandle(ref, () => ({
    doesFilterPass(params) {
    const cellValue = params.data[props.column.colId];
    if (!cellValue) return false;

    const cellDate = new Date(cellValue);
    const fromDate = dateFrom ? new Date(dateFrom) : null;
    const toDate = dateTo ? new Date(dateTo) : null;

    switch (filterType) {
    case "equals":
    return fromDate && cellDate.getTime() === fromDate.getTime();
    case "notEqual":
    return fromDate && cellDate.getTime() !== fromDate.getTime();
    case "lessThan":
    return fromDate && cellDate < fromDate;
    case "greaterThan":
    return fromDate && cellDate > fromDate;
    case "inRange":
    return fromDate && toDate && cellDate >= fromDate && cellDate <= toDate;
    default:
    return true;
    }
    },

    isFilterActive() {
    return !!dateFrom || !!dateTo;
    },

    getModel() {
    if (!this.isFilterActive()) {
    return null;
    }
    return {
    [props.column.colId]: { // Use the column ID as the key
    type: filterType,
    dateFrom: dateFrom,
    dateTo: filterType === "inRange" ? dateTo : null,
    filterType: "date",
    },
    };
    },

    setModel(model) {
    if (model && model[props.column.colId]) {
    const filterDetails = model[props.column.colId];
    setFilterType(filterDetails.type || "equals");
    setDateFrom(filterDetails.dateFrom || "");
    setDateTo(filterDetails.dateTo || "");
    } else {
    setFilterType("equals");
    setDateFrom("");
    setDateTo("");
    }
    },
    }));

    // Notify Ag-Grid when the filter changes
    useEffect(() => {
    props.filterChangedCallback();
    }, [filterType, dateFrom, dateTo]);

    // Handle changes to the filter type
    function onFilterTypeChange(event) {
    setFilterType(event.target.value);
    }

    // Handle changes to the "dateFrom" input
    function onDateFromChange(event) {
    setDateFrom(event.target.value);
    }

    // Handle changes to the "dateTo" input (only for "inRange")
    function onDateToChange(event) {
    setDateTo(event.target.value);
    }

    return React.createElement(
    "div",
    { style: { display: "flex", flexDirection: "column", padding: "5px" } },
    React.createElement(
    "select",
    {
    value: filterType,
    onChange: onFilterTypeChange,
    style: { marginBottom: "5px", padding: "5px", width: "100%" },
    },
    React.createElement("option", { value: "equals" }, "Equals"),
    React.createElement("option", { value: "notEqual" }, "Does not equal"),
    React.createElement("option", { value: "lessThan" }, "Before"),
    React.createElement("option", { value: "greaterThan" }, "After"),
    React.createElement("option", { value: "inRange" }, "Between")
    ),
    React.createElement("input", {
    type: "datetime-local", // HTML5 date-time picker
    value: dateFrom,
    onChange: onDateFromChange,
    style: { width: "100%", padding: "5px", marginBottom: "5px" },
    }),
    filterType === "inRange" &&
    React.createElement("input", {
    type: "datetime-local", // HTML5 date-time picker
    value: dateTo,
    onChange: onDateToChange,
    style: { width: "100%", padding: "5px" },
    })
    ); });


    So now I’m getting the intended UI for DateTime filter. It is also getting triggered as soon as I start typing. However, I’m not able to get data from that input. For reference, I want my data to be parsed/captured like this for my filterModel : {'XXX_YY': {'dateFrom': '2025-04-02 00:00:00', 'dateTo': None, 'filterType': 'date', 'type': 'equals'}} where ‘XXX_YY’ is the name of column on which filter is being applied. Instead, at the moment, it just returns this: {}.

    What mistake might I be committing here? Or is there an easier alternative to my need - something like extending the functionality of “agDateColumnFilter” to have date-time input (instead of only date input) and the rest UI as is?

    I’m using dash_ag_grid==31.2.0, plotly==5.23.0 & Python 3.12.4 and operating in Chrome browser.

    Continue reading...

Compartilhe esta Página