diff --git a/CHANGELOG.md b/CHANGELOG.md index 381029c..f39928b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/lib/utils/propCategories.js b/src/lib/utils/propCategories.js index 2eb167b..60f819a 100644 --- a/src/lib/utils/propCategories.js +++ b/src/lib/utils/propCategories.js @@ -301,6 +301,7 @@ export const COLUMN_NESTED_OR_OBJ_OF_FUNCTIONS = { export const COLUMN_ARRAY_NESTED_FUNCTIONS = { children: 1, filterOptions: 1, + filters: 1, }; /** diff --git a/tests/assets/dashAgGridFunctions.js b/tests/assets/dashAgGridFunctions.js index eacb3e6..76d399e 100644 --- a/tests/assets/dashAgGridFunctions.js +++ b/tests/assets/dashAgGridFunctions.js @@ -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 @@ -502,4 +537,5 @@ dagfuncs.TestEvent = (params, setEventData) => { dagfuncs.testToyota = (params) => { return params.data.make == 'Toyota' ? {'color': 'blue'} : {} -} \ No newline at end of file +} + diff --git a/tests/test_custom_filter.py b/tests/test_custom_filter.py index b0e6c54..6d15950 100644 --- a/tests/test_custom_filter.py +++ b/tests/test_custom_filter.py @@ -236,3 +236,99 @@ 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") + + # Wait for grid to load + grid.wait_for_cell_text(0, 0, "Michael Phelps") + + # Test Set Filter - select a date from the checkbox list + dash_duo.find_element('.ag-header-cell[aria-colindex="3"] span[data-ref="eFilterButton"]').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 and verify + dash_duo.find_element('button[ref="applyFilterButton"]').click() + grid.wait_for_cell_text(0, 2, "24/08/2008") + + # Reset + dash_duo.find_element('.ag-header-cell[aria-colindex="3"] span[data-ref="eFilterButton"]').click() + dash_duo.find_element('button[ref="resetFilterButton"]').click() + + # Test Date Filter - type a date in the input field + dash_duo.find_element('.ag-header-cell[aria-colindex="3"] span[data-ref="eFilterButton"]').click() + + # Switch to Date Filter tab + dash_duo.find_elements('.ag-tabs-header .ag-tab')[1].click() + + # Type date and apply + dash_duo.find_element('.ag-date-filter input[class*="ag-input-field-input"]').send_keys("24/08/2008") + dash_duo.find_element('button[ref="applyFilterButton"]').click() + + # Verify + grid.wait_for_cell_text(0, 2, "24/08/2008") \ No newline at end of file