I am using mMUI X Data Grid to show a list of article. The user can select one or multiple row/article.
I have implemented my own filter and my own search bar.
When the user select row and then filter or search he will lost the previous row selected.
How to avoid this and keep the row selected ?
I think the problem is that when a user select an article in initial rows and then filter the rows, It will reduce the rows and the selected article who are not in the filter rows will just unselect
This is my parent component where i have the initial row/article list, and the search, filter and selection component
import * as React from 'react';
import { Paper } from '@mui/material';
import { FilterArticle } from './FilterArticle';
import { SearchArticle } from './SearchArticle';
import { useDispatch } from 'react-redux';
import { setActualTitle } from 'feature/title.slice';
import { SelectionArticle } from './SelectionArticle';
export const SelectArticle = ({ control, watch, register, setValue }) => {
const list = [
{
id: 1,
name: 'Snow',
age: 35,
stack: '3',
service: '1',
asset: '1',
price: [{ SSL: 5 }, { SSB: 10 }, { SSF: 15 }],
quantity: 5,
},
{
id: 2,
name: 'Lannister',
age: 42,
stack: '3',
service: '1',
asset: '2',
price: [{ SSL: 5 }, { SSB: 10 }, { SSF: 15 }],
quantity: 5,
},
{
id: 3,
name: 'Lannister',
age: 45,
stack: '3',
service: '1',
asset: '3',
price: [{ SSL: 5 }, { SSB: 10 }, { SSF: 15 }],
quantity: 5,
},
];
const dispatch = useDispatch();
const [rows, setRows] = React.useState(list);
React.useEffect(() => {
dispatch(setActualTitle('Articles professional services'));
}, []);
return (
<div className="form">
<label className="subtitle">Select Articles</label>{' '}
<Paper className="form_group" style={{ height: 550, width: '60vw' }}>
<FilterArticle
setRows={setRows}
watch={watch}
list={list}
register={register}
/>
<SearchArticle setRows={setRows} list={list} />
<SelectionArticle
list={list}
setValue={setValue}
control={control}
rows={rows}
watch={watch}
/>
</Paper>
</div>
);
};
Here is my searchArticle component, where i put the logic of search article
import { Box, TextField } from '@mui/material';
import { RxCross2 } from 'react-icons/rx';
import React from 'react';
export const SearchArticle = ({ setRows, list }) => {
const [search, setSearch] = React.useState('');
const requestSearch = (search) => {
if (search === '') {
setRows(list);
return;
}
const filteredRows = list?.filter((row) => {
return (
row.name?.toLowerCase().includes(search?.toLowerCase()) ||
row.service?.toLowerCase().includes(search?.toLowerCase()) ||
row.asset?.toLowerCase().includes(search?.toLowerCase()) ||
(row.stack && row.stack.toString().includes(search))
);
});
setRows(filteredRows);
};
React.useEffect(() => {
requestSearch(search);
}, [search]);
const cancelSearch = () => {
setSearch('');
};
return (
<Box sx={{ m: 1, minWidth: 120, display: 'flex', alignItems: 'center' }}>
<TextField
id="standard-basic"
label="search..."
variant="standard"
className="searchBar_input"
placeholder="search..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<RxCross2 onClick={cancelSearch} />
</Box>
);
};
Here the SelectionArticle component with the DataGrid
import { DataGrid } from '@mui/x-data-grid';
import React, { useEffect, useState } from 'react';
import { Stack } from 'react-bootstrap';
import { useFieldArray } from 'react-hook-form';
export const SelectionArticle = ({ control, setValue, rows, watch }) => {
const entityConcerned = watch('OffersInfos.entityConcerned');
const articleSelected = watch('Articles');
const [selectedRows, setSelectedRows] = useState(articleSelected);
const [selectionModel, setSelectionModel] = useState(() =>
rows.filter((r) => r.id > 2).map((r) => r.id)
);
useEffect(() => {
replace(selectedRows);
}, [selectedRows]);
const columns = [
{ field: 'id', headerName: 'ID', width: 70 },
{ field: 'name', headerName: 'name', width: 130 },
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 90,
},
{
field: 'stack',
headerName: 'Stacks',
width: 90,
},
{
field: 'service',
headerName: 'service',
width: 90,
},
{
field: 'asset',
headerName: 'asset',
width: 90,
},
{
field: 'quantity',
headerName: 'quantity',
width: 90,
},
{
field: 'price',
headerName: 'price',
width: 90,
renderCell: (params) => {
const priceObj = params.row.price.find((obj) => obj[entityConcerned]);
const price = priceObj ? priceObj[entityConcerned] : '';
return <span>{price}</span>;
},
},
];
const onRowsSelectionHandler = (ids) => {
const selectedRowsData = ids.map((id) => rows.find((row) => row.id === id));
setSelectedRows(selectedRowsData);
};
const { replace } = useFieldArray({
control,
name: 'Articles',
});
function NoRowsOverlay() {
return (
<Stack height="100%" alignItems="center" justifyContent="center">
Aucun article
</Stack>
);
}
function NoResultsOverlay() {
return (
<Stack height="100%" alignItems="center" justifyContent="center">
Aucun résultat
</Stack>
);
}
useEffect(() => {
// Update the selection model based on the selected articles
const selectedArticleIds = articleSelected?.map((article) => article?.id);
const selectedRowsIds = rows
.filter((row) => selectedArticleIds?.includes(row?.id))
.map((row) => row?.id);
setSelectionModel(selectedRowsIds);
}, [articleSelected]);
return (
<DataGrid
rows={rows}
getRowId={(row) => row?.id}
columns={columns}
checkboxSelection
components={{ NoRowsOverlay, NoResultsOverlay }}
componentsProps={{
pagination: {
labelRowsPerPage: 'Articles/page',
rowsPerPageOptions: [5, 10, 20, 50, 100],
},
}}
onSelectionModelChange={(ids) => {
onRowsSelectionHandler(ids);
}}
selectionModel={selectionModel}
/>
);
};
I have tried to follow this https://github.com/mui/mui-x/issues/2842 but I really need to keep my own filter and search bar.
I have seen this post with the same problem but no solution How to keep selected checkbox row when we filter the rowData in material UI Datagrid even when its not present in the filtered rowData
Check this answer
You have to use Controlled Row Selection
with prop keepNonExistentRowsSelected
as described here
<DataGrid
checkboxSelection
keepNonExistentRowsSelected
onRowSelectionModelChange={(newRowSelectionModel) => {
setRowSelectionModel(newRowSelectionModel);
}}
rowSelectionModel={rowSelectionModel}
{...data}
/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With