Last active
September 23, 2022 19:34
-
-
Save tad3j/4194cf54b118c347eb40c673764599ed to your computer and use it in GitHub Desktop.
Reusable ag-grid component for React which provides support for URL query filters and sorting
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
export const DEFAULT_COLUMN_DEFINITIONS = { | |
sortable: true, | |
filter: true, | |
resizable: true, | |
} | |
export const gridInit = (gridApi) => { | |
gridApi.sizeColumnsToFit() | |
gridApi.setDomLayout('autoHeight') | |
} |
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 React, { useEffect, useState } from 'react' | |
import { AgGridReact } from '@ag-grid-community/react' | |
import { AllCommunityModules } from '@ag-grid-community/all-modules' | |
import { DEFAULT_COLUMN_DEFINITIONS, gridInit } from '../../helpers/agGrid' | |
import { | |
cleanUpQuery, | |
GridFilterService, | |
} from '../../../services/ag-grid/GridFilterService' | |
import PropTypes from 'prop-types' | |
import { useHistory } from 'react-router' | |
let gridApi //we set it global so we can interact with grid (like getting selected values) | |
const filterService = new GridFilterService() | |
const getFiltersFromQueryString = filterService.getFiltersFromQueryString | |
const BaseAgGrid = ({ columnDefs, rowData, onRowSelected, ...rest }) => { | |
const history = useHistory() | |
const [oldQuery, setOldQuery] = useState('') | |
useEffect(() => { | |
const stopListenToHistory = history.listen((location) => { | |
const { filters, sort } = getFiltersFromQueryString(location.search) | |
const query = cleanUpQuery(location.search) | |
if (oldQuery !== query) { | |
setOldQuery(query) | |
gridApi.setFilterModel(filters) | |
gridApi.setSortModel(sort) | |
} | |
}) | |
return () => stopListenToHistory() | |
}) | |
const onGridReadyHandler = (params) => { | |
//get api so we can interact with grid (like getting selected values) | |
gridApi = params.api | |
gridInit(gridApi) | |
//init filters | |
const query = cleanUpQuery(history.location.search) | |
const { filters, sort } = getFiltersFromQueryString(query) | |
gridApi.setFilterModel(filters) | |
gridApi.setSortModel(sort) | |
//set old query to prevent extra navigation push | |
setOldQuery(query) | |
} | |
const onModelUpdate = (event) => { | |
const query = filterService.getQueryParamsFromObjects( | |
event.api.getFilterModel(), | |
event.api.getSortModel() | |
) | |
if (oldQuery !== query) { | |
//set old query to prevent extra navigation push | |
setOldQuery(query) | |
history.push({ | |
pathname: history.location.pathname, | |
search: query.length > 0 ? query : null, | |
}) | |
} | |
} | |
return ( | |
<AgGridReact | |
//CONFIG | |
modules={AllCommunityModules} //using all modules | |
defaultColDef={DEFAULT_COLUMN_DEFINITIONS} | |
//Delta Row Updates (ensures only updated rows will be re-rendered inside the grid) | |
// https://www.ag-grid.com/react-redux-integration-pt1/ | |
immutableData | |
//DATA | |
columnDefs={columnDefs} | |
rowData={rowData} | |
//CALLBACKS | |
onGridReady={onGridReadyHandler} | |
onModelUpdated={onModelUpdate} | |
//we need to pass gridApi so it's possible to get selected row(s) from parent component | |
onRowSelected={onRowSelected ? onRowSelected(gridApi) : null} | |
//REST of props | |
{...rest} | |
/> | |
) | |
} | |
BaseAgGrid.propTypes = { | |
columnDefs: PropTypes.array.isRequired, | |
rowData: PropTypes.array.isRequired, | |
onRowSelected: PropTypes.func, | |
} | |
export default BaseAgGrid |
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 qs from 'qs' | |
export const cleanUpQuery = (str) => | |
str.charAt(0) === '?' ? str.substr(1) : str | |
export class GridFilterService { | |
getFiltersFromQueryString(queryString) { | |
if (!queryString) { | |
return {} | |
} | |
//remove question mark | |
const cleanQueryString = cleanUpQuery(queryString) | |
if (!cleanQueryString) { | |
return {} | |
} | |
const allQueryParams = qs.parse(cleanQueryString) | |
const sort = allQueryParams.sort | |
delete allQueryParams.sort | |
return { filters: allQueryParams, sort } | |
} | |
/** | |
* Returns query params string created from objected (nesting supported) | |
* @param {any} filters | |
* @param {any} sort | |
* @return {string} | |
*/ | |
getQueryParamsFromObjects(filters, sort) { | |
const sortQueryParamsObj = {} | |
sort.forEach((sortItem, index) => (sortQueryParamsObj[index] = sortItem)) | |
//filter type should always be the same as on init, so we remove filterType from all filter models | |
Object.keys(filters).forEach((filerName) => { | |
delete filters[filerName].filterType | |
}) | |
if (Object.keys(filters) < 0 && Object.keys(sort) < 0) { | |
return '' | |
} | |
return qs.stringify({ ...filters, sort: sortQueryParamsObj }) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment