Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Links "DE#nnn" prior to version 2.0 point to the Dash Enterprise closed-source D
- [#408](https://github.com/plotly/dash-ag-grid/pull/408) fixed issue where the `columnState` would conflict with `columnDefs` updates
- fixes [#416] (https://github.com/plotly/dash-ag-grid/issues/416)
- fixes [#407](https://github.com/plotly/dash-ag-grid/issues/407)
- [#412](https://github.com/plotly/dash-ag-grid/issues/412) fix "Multi-Column Filter not properly recognized in filterParams"

## [33.3.2rc2] - 2025-09-17

Expand Down
1 change: 1 addition & 0 deletions src/lib/utils/propCategories.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ export const COLUMN_NESTED_OR_OBJ_OF_FUNCTIONS = {
export const COLUMN_ARRAY_NESTED_FUNCTIONS = {
children: 1,
filterOptions: 1,
filters: 1,
};

/**
Expand Down
38 changes: 37 additions & 1 deletion tests/assets/dashAgGridFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,41 @@ dagfuncs.startWith = ([filterValues], cellValue) => {
const name = cellValue ? cellValue.split(" ")[1] : ""
return name && name.toLowerCase().indexOf(filterValues.toLowerCase()) === 0
}

dagfuncs.dateFilterComparator = (filterLocalDateAtMidnight, cellValue) => {
const dateAsString = cellValue;

if (dateAsString == null) {
// Return -1 to show nulls "before" any date
return -1;
}

// The data from this CSV is in dd/mm/yyyy format
const dateParts = dateAsString.split("/");
if (dateParts.length !== 3) {
// Handle invalid format
return 0;
}

const day = Number(dateParts[0]);
const month = Number(dateParts[1]) - 1; // JS months are 0-indexed
const year = Number(dateParts[2]);
const cellDate = new Date(year, month, day);

// Check for invalid date (e.g., from "NaN")
if (isNaN(cellDate.getTime())) {
return 0;
}

// Now that both parameters are Date objects, we can compare
if (cellDate < filterLocalDateAtMidnight) {
return -1;
} else if (cellDate > filterLocalDateAtMidnight) {
return 1;
}
return 0;
};

// END test_custom_filter.py

// FOR test_quick_filter.py
Expand Down Expand Up @@ -502,4 +537,5 @@ dagfuncs.TestEvent = (params, setEventData) => {

dagfuncs.testToyota = (params) => {
return params.data.make == 'Toyota' ? {'color': 'blue'} : {}
}
}

97 changes: 96 additions & 1 deletion tests/test_custom_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_fi003_custom_filter(dash_duo):

grid.wait_for_cell_text(0, 0, "23")

dash_duo.find_element('.ag-header-cell[aria-colindex="3"] span[data-ref="eFilterButton"]').click()
dash_duo.find_element('.ag-floating-filter[aria-colindex="3"] button').click()

dash_duo.find_element('.ag-filter label:nth-child(2)').click()

Expand Down Expand Up @@ -236,3 +236,98 @@ def test_fi005_custom_filter(dash_duo):
# Test numberParser and numberFormatter
grid.set_filter(0, "$100,5")
grid.wait_for_cell_text(0, 0, "$200,00")

def test_fi006_custom_filter(dash_duo):
app = Dash(__name__)

df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

columnDefs = [
{"field": "athlete",
"filter": "agMultiColumnFilter",
"filterParams": {
"filters": [
{"filter": "agTextColumnFilter"},
{"filter": "agSetColumnFilter"} # Example with Set Filter
]
}},
{"field": "country"},
{
"field": "date",
"filter": "agMultiColumnFilter",
"filterParams": {
"filters": [
{
"filter": "agSetColumnFilter",
'filterParams': {'excelMode': 'windows', 'buttons': ['apply', 'reset'],
}
},
{
"filter": "agDateColumnFilter",
'filterParams': {
'excelMode': 'windows',
'buttons': ['apply', 'reset'],
'comparator': {'function': 'dateFilterComparator'},
}
},
],

},
},
]


app.layout = html.Div(
[
dag.AgGrid(
id="date-filter-example",
enableEnterpriseModules=True,
columnDefs=columnDefs,
rowData=df.to_dict("records"),
defaultColDef={"flex": 1, "minWidth": 150, "floatingFilter": True},
dashGridOptions={"animateRows": False}
),
],
)

dash_duo.start_server(app)

grid = utils.Grid(dash_duo, "date-filter-example")

grid.wait_for_cell_text(0, 0, "Michael Phelps")

# Test Set Filter - click filter button on date column
dash_duo.find_element('.ag-floating-filter[aria-colindex="3"] button').click()

# Uncheck "Select All"
dash_duo.find_element('.ag-set-filter-list .ag-set-filter-item .ag-checkbox-input').click()

# Select "24/08/2008"
set_filter_items = dash_duo.find_elements('.ag-set-filter-list .ag-virtual-list-item')
for item in set_filter_items:
if "24/08/2008" in item.text:
item.find_element_by_css_selector('.ag-checkbox-input').click()
break

# Apply
dash_duo.find_element('button[ref="applyFilterButton"]').click()
Comment on lines +304 to +315
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess is that this is executing too fast, you need to make sure that the options are actually showing before trying to click or interact.

You can use wait_until or something similar.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will try that! Thanks!

grid.wait_for_cell_text(0, 2, "24/08/2008")

# Reset
dash_duo.find_element('.ag-floating-filter[aria-colindex="3"] button').click()
dash_duo.find_element('button[ref="resetFilterButton"]').click()

# Test Date Filter - click filter button again
dash_duo.find_element('.ag-floating-filter[aria-colindex="3"] button').click()

# Switch to Date Filter tab (second tab)
dash_duo.find_elements('.ag-tabs-header .ag-tab')[1].click()

# Type date
dash_duo.find_element('.ag-date-filter input[class*="ag-input-field-input"]').send_keys("24/08/2008")

# Apply
dash_duo.find_element('button[ref="applyFilterButton"]').click()
grid.wait_for_cell_text(0, 2, "24/08/2008")
Loading