Skip to content

Instantly share code, notes, and snippets.

@tad3j
Last active September 23, 2022 19:34
Show Gist options
  • Save tad3j/4194cf54b118c347eb40c673764599ed to your computer and use it in GitHub Desktop.
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
export const DEFAULT_COLUMN_DEFINITIONS = {
sortable: true,
filter: true,
resizable: true,
}
export const gridInit = (gridApi) => {
gridApi.sizeColumnsToFit()
gridApi.setDomLayout('autoHeight')
}
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
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