Skip to content

Commit fd8ffe8

Browse files
authored
Merge pull request #111 from BSd3v/filter-model-support
adding support for `filterModel`
2 parents a35f067 + 679ed74 commit fd8ffe8

File tree

7 files changed

+320
-54
lines changed

7 files changed

+320
-54
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ Links "DE#nnn" prior to version 2.0 point to the Dash Enterprise closed-source D
5555
- [#81](https://github.com/plotly/dash-ag-grid/pull/81)
5656
- added tests for `cellClicked` data
5757

58+
- [#111](https://github.com/plotly/dash-ag-grid/pull/111)
59+
- added `filterModel` prop in order to capture the grid's active filters
60+
61+
5862
### Updated
5963
- [Overhaul commit](https://github.com/plotly/dash-ag-grid/commit/b888d6ab4fcb4afac187492e8b6c9cf0d0f8842b)
6064
- Update AG Grid from v27.x to v29.x - see [AG Grid Changelog](https://www.ag-grid.com/changelog/) for details.
@@ -75,7 +79,7 @@ Links "DE#nnn" prior to version 2.0 point to the Dash Enterprise closed-source D
7579
- removed `cellStyle` from the grid level, allowing more flexibility in customization, and alignment with AG grid
7680
- allowed for functions, styleConditions and regular dictionaries to be passed to the `cellStyle` on all levels
7781
- added `rowId` to `cellClicked` data
78-
82+
7983
### Fixed
8084
- [Overhaul commit](https://github.com/plotly/dash-ag-grid/commit/b888d6ab4fcb4afac187492e8b6c9cf0d0f8842b)
8185
- Fix issue where conditional formatting was not applied to nested columns
@@ -89,6 +93,9 @@ Links "DE#nnn" prior to version 2.0 point to the Dash Enterprise closed-source D
8993
- [#90](https://github.com/plotly/dash-ag-grid/pull/90) Fixing `columnState` to be populated once `gridReady`
9094
- [#92](https://github.com/plotly/dash-ag-grid/pull/92) Fixing `defaultStyle` when no `styleConditions` is in `cellStyle`
9195

96+
- [#111](https://github.com/plotly/dash-ag-grid/pull/111)
97+
- fixing templates to only populate when `dangerously_allow_code=True`
98+
9299
## [1.3.2] - 2023-01-13
93100

94101
### Updated

src/lib/components/AgGrid.react.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ DashAgGrid.defaultProps = {
7373
suppressDragLeaveHidesColumns: true,
7474
dangerously_allow_code: false,
7575
rowModelType: 'clientSide',
76+
dashGridOptions: {},
77+
filterModel: {},
7678
};
7779
DashAgGrid.propTypes = {
7880
/********************************
@@ -346,6 +348,12 @@ DashAgGrid.propTypes = {
346348
failCallback: PropTypes.func,
347349
}),
348350

351+
/**
352+
* If filtering client-side rowModel, what the filter model is.
353+
* Passing a model back to this prop will apply it to the grid.
354+
*/
355+
filterModel: PropTypes.object,
356+
349357
/**
350358
* Request from Dash AgGrid when suppressCallback is disabled and a user opens a row with a detail grid
351359
*/

src/lib/fragments/AgGrid.react.js

Lines changed: 151 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
COLUMN_NESTED_OR_OBJ_OF_FUNCTIONS,
3232
PASSTHRU_PROPS,
3333
PROPS_NOT_FOR_AG_GRID,
34+
GRID_DANGEROUS_FUNCTIONS,
3435
} from '../utils/propCategories';
3536
import debounce from '../utils/debounce';
3637

@@ -296,6 +297,9 @@ export default class DashAgGrid extends Component {
296297
}
297298
return this.convertAllProps(value);
298299
}
300+
if (GRID_DANGEROUS_FUNCTIONS[target]) {
301+
return this.convertMaybeFunctionNoParams(value, {prop: target});
302+
}
299303
if (target === 'getRowId') {
300304
return this.convertFunction(value);
301305
}
@@ -329,16 +333,17 @@ export default class DashAgGrid extends Component {
329333

330334
onFilterChanged() {
331335
const {setProps, rowModelType} = this.props;
336+
const filterModel = this.state.gridApi.getFilterModel();
337+
const propsToSet = {filterModel};
332338
if (rowModelType === 'clientSide') {
333339
const virtualRowData = [];
334340
this.state.gridApi.forEachNodeAfterFilter((node) => {
335341
virtualRowData.push(node.data);
336342
});
337-
338-
const filterModel = this.state.gridApi.getFilterModel();
339-
this.setState({filterModel});
340-
setProps({virtualRowData});
343+
propsToSet.virtualRowData = virtualRowData;
341344
}
345+
346+
setProps({...propsToSet});
342347
}
343348

344349
getRowData() {
@@ -431,8 +436,9 @@ export default class DashAgGrid extends Component {
431436

432437
onRowDataUpdated() {
433438
// Handles preserving existing selections when rowData is updated in a callback
434-
const {selectedRows, setProps, rowData, rowModelType} = this.props;
435-
const {openGroups, filterModel} = this.state;
439+
const {selectedRows, setProps, rowData, rowModelType, filterModel} =
440+
this.props;
441+
const {openGroups} = this.state;
436442

437443
if (rowData && rowModelType === 'clientSide' && this.state.gridApi) {
438444
const virtualRowData = [];
@@ -517,7 +523,21 @@ export default class DashAgGrid extends Component {
517523
onGridReady(params) {
518524
// Applying Infinite Row Model
519525
// see: https://www.ag-grid.com/javascript-grid/infinite-scrolling/
520-
const {rowModelType, selectedRows} = this.props;
526+
const {
527+
rowModelType,
528+
selectedRows,
529+
resetColumnState,
530+
csvExportParams,
531+
exportDataAsCsv,
532+
selectAll,
533+
deselectAll,
534+
autoSizeAllColumns,
535+
deleteSelectedRows,
536+
filterModel,
537+
setProps,
538+
} = this.props;
539+
540+
const propsToSet = {};
521541
if (rowModelType === 'infinite') {
522542
params.api.setDatasource(this.getDatasource());
523543
}
@@ -528,6 +548,45 @@ export default class DashAgGrid extends Component {
528548
});
529549

530550
this.updateColumnWidths();
551+
552+
if (!isEmpty(filterModel)) {
553+
this.state.gridApi.setFilterModel(filterModel);
554+
}
555+
556+
if (resetColumnState) {
557+
this.resetColumnState(false);
558+
propsToSet.resetColumnState = false;
559+
}
560+
561+
if (exportDataAsCsv) {
562+
this.exportDataAsCsv(csvExportParams, false);
563+
propsToSet.exportDataAsCsv = false;
564+
}
565+
566+
if (selectAll) {
567+
this.selectAll(selectAll, false);
568+
propsToSet.selectAll = false;
569+
}
570+
571+
if (deselectAll) {
572+
this.deselectAll(false);
573+
propsToSet.deselectAll = false;
574+
}
575+
576+
if (autoSizeAllColumns) {
577+
this.autoSizeAllColumns(autoSizeAllColumns, false);
578+
propsToSet.autoSizeAllColumns = false;
579+
}
580+
581+
if (deleteSelectedRows) {
582+
this.deleteSelectedRows(false);
583+
propsToSet.deleteSelectedRows = false;
584+
}
585+
586+
if (!isEmpty(propsToSet)) {
587+
setProps(propsToSet);
588+
}
589+
531590
this.updateColumnState();
532591

533592
if (this.state.rowTransaction) {
@@ -666,44 +725,99 @@ export default class DashAgGrid extends Component {
666725
);
667726
}
668727

669-
resetColumnState() {
670-
this.state.gridColumnApi.resetColumnState();
671-
this.props.setProps({
672-
resetColumnState: false,
673-
});
728+
// Event actions that reset
729+
exportDataAsCsv(csvExportParams, reset = true) {
730+
if (!this.state.gridApi) {
731+
return;
732+
}
733+
this.state.gridApi.exportDataAsCsv(csvExportParams);
734+
if (reset) {
735+
this.props.setProps({
736+
exportDataAsCsv: false,
737+
});
738+
}
674739
}
675740

676-
exportDataAsCsv(csvExportParams) {
677-
this.state.gridApi.exportDataAsCsv(csvExportParams);
678-
this.props.setProps({
679-
exportDataAsCsv: false,
680-
});
741+
resetColumnState(reset = true) {
742+
if (!this.state.gridApi) {
743+
return;
744+
}
745+
this.state.gridColumnApi.resetColumnState();
746+
if (reset) {
747+
this.props.setProps({
748+
resetColumnState: false,
749+
});
750+
}
681751
}
682752

683-
selectAll(opts) {
753+
selectAll(opts, reset = true) {
754+
if (!this.state.gridApi) {
755+
return;
756+
}
684757
if (opts?.filtered) {
685758
this.state.gridApi.selectAllFiltered();
686759
} else {
687760
this.state.gridApi.selectAll();
688761
}
689-
this.props.setProps({
690-
selectAll: false,
691-
});
762+
if (reset) {
763+
this.props.setProps({
764+
selectAll: false,
765+
});
766+
}
692767
}
693768

694-
deselectAll() {
769+
deselectAll(reset = true) {
770+
if (!this.state.gridApi) {
771+
return;
772+
}
695773
this.state.gridApi.deselectAll();
696-
this.props.setProps({
697-
deselectAll: false,
698-
});
774+
if (reset) {
775+
this.props.setProps({
776+
deselectAll: false,
777+
});
778+
}
699779
}
700780

701-
deleteSelectedRows() {
781+
deleteSelectedRows(reset = true) {
782+
if (!this.state.gridApi) {
783+
return;
784+
}
702785
const sel = this.state.gridApi.getSelectedRows();
703786
this.state.gridApi.applyTransaction({remove: sel});
787+
if (reset) {
788+
this.props.setProps({
789+
deleteSelectedRows: false,
790+
rowData: this.getRowData(),
791+
});
792+
}
793+
}
794+
795+
autoSizeAllColumns(opts, reset = true) {
796+
if (!this.state.gridApi) {
797+
return;
798+
}
799+
const allColumnIds = this.state.gridColumnApi
800+
.getColumnState()
801+
.map((column) => column.colId);
802+
const skipHeaders = Boolean(opts?.skipHeaders);
803+
this.state.gridColumnApi.autoSizeColumns(allColumnIds, skipHeaders);
804+
if (reset) {
805+
this.props.setProps({
806+
autoSizeAllColumns: false,
807+
});
808+
}
809+
}
810+
// end event actions
811+
812+
updateColumnState() {
813+
if (!this.state.gridApi) {
814+
return;
815+
}
704816
this.props.setProps({
705-
deleteSelectedRows: false,
706-
rowData: this.getRowData(),
817+
columnState: JSON.parse(
818+
JSON.stringify(this.state.gridColumnApi.getColumnState())
819+
),
820+
updateColumnState: false,
707821
});
708822
}
709823

@@ -743,26 +857,6 @@ export default class DashAgGrid extends Component {
743857
this.syncRowData();
744858
}
745859

746-
autoSizeAllColumns(opts) {
747-
const allColumnIds = this.state.gridColumnApi
748-
.getColumnState()
749-
.map((column) => column.colId);
750-
const skipHeaders = Boolean(opts?.skipHeaders);
751-
this.state.gridColumnApi.autoSizeColumns(allColumnIds, skipHeaders);
752-
this.props.setProps({
753-
autoSizeAllColumns: false,
754-
});
755-
}
756-
757-
updateColumnState() {
758-
this.props.setProps({
759-
columnState: JSON.parse(
760-
JSON.stringify(this.state.gridColumnApi.getColumnState())
761-
),
762-
updateColumnState: false,
763-
});
764-
}
765-
766860
render() {
767861
const {
768862
id,
@@ -778,6 +872,7 @@ export default class DashAgGrid extends Component {
778872
updateColumnState,
779873
csvExportParams,
780874
dashGridOptions,
875+
filterModel,
781876
...restProps
782877
} = this.props;
783878

@@ -787,6 +882,14 @@ export default class DashAgGrid extends Component {
787882
omit(NO_CONVERT_PROPS, {...dashGridOptions, ...restProps})
788883
);
789884

885+
if (filterModel) {
886+
if (this.state.gridApi) {
887+
if (this.state.gridApi.getFilterModel() !== filterModel) {
888+
this.state.gridApi.setFilterModel(filterModel);
889+
}
890+
}
891+
}
892+
790893
if (resetColumnState) {
791894
this.resetColumnState();
792895
}

src/lib/utils/propCategories.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ export const COLUMN_DANGEROUS_FUNCTIONS = {
1515
template: 1,
1616
};
1717

18+
/**
19+
* Dangerous elements on the grid: If you pass a string,
20+
* AG Grid will execute it as raw JS. We accept these strings if
21+
* `dangerously_allow_code=true`, otherwise we require
22+
* {function: <string>} and we'll eval & exec it safely.
23+
* https://www.ag-grid.com/react-data-grid/cell-expressions/#column-definition-expressions
24+
**/
25+
export const GRID_DANGEROUS_FUNCTIONS = {
26+
overlayLoadingTemplate: 1,
27+
overlayNoRowsTemplate: 1,
28+
};
29+
1830
/**
1931
* Objects in either columns or top-level props with arbitrary keys
2032
* whose values can only be function strings, which we will eval safely

0 commit comments

Comments
 (0)