Created
March 5, 2020 21:06
-
-
Save nite/36627e2b0359ddff8d50255da05238d1 to your computer and use it in GitHub Desktop.
ag-grid wrapper with persistence of grid column & filter state in localStorage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {ColDef, ColGroupDef, ColumnApi, GridApi} from 'ag-grid-community'; | |
import {AgGridReact} from 'ag-grid-react'; | |
import {AgGridReactProps} from 'ag-grid-react/lib/agGridReact'; | |
import {functions, isEqual, omit} from 'lodash'; | |
import log from 'loglevel'; | |
import React, {useState} from 'react'; | |
import useDeepCompareEffect from 'use-deep-compare-effect' | |
const gridStateChangeEvents = ['model', 'displayedColumnsChanged']; | |
export function getFromStorage<T>(storageKey, defaultItem?: T) { | |
const itemJson = localStorage.getItem(storageKey); | |
return itemJson ? JSON.parse(itemJson) : defaultItem; | |
} | |
export function storeItem<T>(storageKey, item: Nullable<T> = undefined) { | |
if (item) { | |
localStorage.setItem(storageKey, JSON.stringify(item)); | |
} else { | |
localStorage.removeItem(storageKey); | |
} | |
} | |
function arePropsEqual(props, nextProps) { | |
return isEqual(omit(nextProps, functions(nextProps)), omit(props, functions(props))); | |
} | |
interface AgGridWrapperProps extends AgGridReactProps { | |
name: string; | |
} | |
function getColIds(columnDefs) { | |
const colIds = [ | |
...columnDefs.filter(({colId}: ColDef) => !!colId) | |
.map(({colId}: ColDef) => colId), | |
// @ts-ignore | |
...columnDefs.filter(({children}: ColGroupDef) => children) | |
.map(({children}: ColGroupDef) => children.map(({colId}: ColDef) => colId)) | |
.flat(), | |
]; | |
return colIds; | |
} | |
export const AgGridWrapper: React.FC<AgGridWrapperProps> = React.memo((props) => { | |
let { | |
rowData, | |
gridOptions, | |
columnDefs, | |
name, | |
} = props; | |
const storageKey = `grid-state:${name}`; | |
rowData = gridOptions && !rowData ? gridOptions.rowData : rowData; | |
columnDefs = gridOptions && !columnDefs ? gridOptions.columnDefs : columnDefs; | |
const [gridApi, setGridApi] = useState<GridApi>(); | |
const [columnApi, setColumnApi] = useState<ColumnApi>(); | |
useDeepCompareEffect(() => { | |
if (gridApi && columnApi && rowData) { | |
gridApi.setRowData(rowData); | |
} | |
}, [rowData]); | |
useDeepCompareEffect(() => { | |
if (gridApi && columnApi && columnDefs) { | |
gridApi.setColumnDefs(columnDefs); | |
const gridState = getFromStorage(storageKey, undefined); | |
if (!gridState) { | |
columnApi.autoSizeAllColumns(); | |
} | |
} | |
}, [columnDefs]); | |
async function onGridReady({api, columnApi}) { | |
setGridApi(api); | |
setColumnApi(columnApi); | |
if (!columnDefs) { | |
return; | |
} | |
const gridState = getFromStorage(storageKey, undefined); | |
if (gridState) { | |
let { | |
filter: filterState, | |
sort: sortState, | |
column: columnState, | |
} = gridState; | |
api.setFilterModel(filterState); | |
api.setSortModel(sortState); | |
const colIds = getColIds(columnDefs); | |
columnState = columnState.filter(({colId}) => colIds.includes(colId)); | |
if (columnState.length) { | |
columnApi.setColumnState(columnState); | |
} | |
} else { | |
columnApi.autoSizeAllColumns(); | |
} | |
function persist(type) { | |
if (gridStateChangeEvents.find(t => type.includes(t))) { | |
const filter = api.getFilterModel(); | |
const sort = api.getSortModel(); | |
const column = columnApi.getColumnState(); | |
const newState = { | |
filter, | |
sort, | |
column, | |
}; | |
log.debug('gridStateChange', type, newState); | |
storeItem(storageKey, newState); | |
} | |
} | |
api.addGlobalListener(persist); | |
} | |
return <AgGridReact {...props} | |
onGridReady={onGridReady}/> | |
}, arePropsEqual); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment