How to disable sort in React table? - reactjs

Disable sorting for a particular column is not working, I have used the method from documentation
https://react-table.tanstack.com/docs/api/useSortBy
export const COLUMNS = [
{
Header: 'Avatar',
accessor: 'avatar',
maxWidth: 50,
minWidth: 50,
Cell: ({ cell: { value } }) => (
<img
src={value}
width={60}
/>
)
},
{
Header: 'Name',
accessor: 'name',
Filter:ColumnFilter,
disableSortBy:'true'
}
]

You are using string value:
disableSortBy: 'true'
You should use boolean value instead:
disableSortBy: true

With TanStack v8, you have enableSorting: false, now in the columnHelper.accessor that does the job

Related

MUI Datagrid, how to do conditional cellrender based on checkboxSelection

I am trying to make a conditional cellRender in a datagrid, if the row checkbox has been checked.
In my picture below, I want to remove the number counter component on that row when the checkbox is clicked.
Is there a way to do this with params? How else could I achieve this
const columns: GridColDef[] = [
{ field: 'id', headerName: 'LIO', flex: 1, minWidth: 80, maxWidth: 100 },
{ field: 'article', headerName: 'Artikel', flex: 1, minWidth: 100, maxWidth: 380 },
{ field: 'currentStock', headerName: 'Saldo', type: 'number', flex: 0.5, minWidth: 70 },
{
field: "inventedStock",
headerName: "Inventerat Antal",
flex: 0.5,
minWidth: 130,
type: 'number',
renderCell: params => {
if( params.row.checkboxSelection) {
return (
<ChooseNumber updateArticle={updateField} scannedArticle={{
article: {
compartments: undefined, units: [], price: 0, supplier: '', supplierArticleNr: '', name: '', alternativeNames: [], lioNr: '', alternativeProducts: [], Z41: false
},
unit: '', quantity: 2,
nr: 3,
}} ></ChooseNumber>
);
} else {
return(2);
}
}
},
I have tried to find a property in the datagrid params interface, but I can't figure it out. Any help much appreciated!
To my knowledge it is not possible to do it only using the params since they don't contain any information about the status of the checkbox.
However the selection of the DataGrid component can be controlled. This can help us track the checked ids which we can use to conditionally render our columns.
To track the checked rows we need to add an new state like so
const [selectedIds, setSelectedIds] = useState([]);
In the renderCell method we check if the id is in the selectedIds if so render the custom input, else render the other thing.
{
field: "inventedStock",
headerName: "Inventerat Antal",
flex: 0.5,
minWidth: 130,
type: "number",
renderCell: (params) => {
console.log(params);
if (selectedIds.includes(params.id) === false) {
return (
<ChooseNumber
updateArticle={updateField}
scannedArticle={{
article: {
compartments: undefined, units: [], price: 0, supplier: "", supplierArticleNr: "", name: "", alternativeNames: [], lioNr: "", alternativeProducts: [], Z41: false,
},
unit: "",
quantity: 2,
nr: 3,
}}
></ChooseNumber>
);
}
return "2";
},
}
The DataGrid component with your rows, columns and added selectionModel functionality
<DataGrid
rows={rows}
columns={columns}
...
selectionModel={selectedIds}
onSelectionModelChange={(newModel) => {
setSelectedIds(newModel);
}}
/>
I hope this helps with your project!

Maximum call stack exceeded in Mui DataGrid React

I have multiple DataGrid tables in my project, but I cannot figure out what is wrong with this one.
I have created a codesandbox example of my problem. If anyone could help I would appreciate it very much.
It is probably a dumb mistake
codesandbox example
You have declared a field with name license 2 times.
Changing to e.g.
{
field: "licence",
headerName: "Licence start",
flex: 1,
valueGetter: (params) =>
`${moment(params.row.licence.startsAt).format("DD.MM.YYYY") || ""}`
},
{
field: "licence2",
headerName: "Licence ends at",
flex: 1,
valueGetter: (params) =>
`${moment(params.row.licence.endsAt).format("DD.MM.YYYY") || ""}`
},
will solve the problem
You can use the params.id to look for that particular element in the valueGetter function and then return it. I've answered a similar question here.
const columns = React.useMemo(
() => [
..., // all the other elements
// No changes needed here since this is the first occurrence of 'details'
{
field: 'details',
headerName: 'Ready By',
type: 'datetime',
valueGetter: ({ value }) => value.ready_by && new Date(value.ready_by),
width: 250,
},
// Here we're basically searching for the item of interest since we do get `id` as a param arg.
{
field: 'details2',
headerName: 'Name',
valueGetter: ({ id }) => {
const item = data.find(item => item.id === id);
return item.name;
},
width: 250,
},
],
[data]
)
I am resolved with this solution:
{ field: 'id', headerName: 'No', flex: 0.3, minWidth: 50 },
{
field: 'displayName',
headerName: 'Name',
flex: 1.2,
minWidth: 160,
renderCell: ({ id }) => {
const item = users.find(item => item.id === id);
return (
<>
<Avatar alt="avatar" src={item.avatarUrl} />
<span className="list-user-name" onClick={handleShowDetailUser}>
{item.displayName}
</span>
</>
);
},
},
so the error is because you’re having those bothe fileds at the time (same name),
{
field: "licence",
headerName: "Licence start",
flex: 1,
valueGetter: (params) =>
`${moment(params.row.licence.startsAt).format("DD.MM.YYYY") || ""}`
},
{
field: "licence",
headerName: "Licence ends at",
flex: 1,
valueGetter: (params) =>
`${moment(params.row.licence.endsAt).format("DD.MM.YYYY") || ""}`
},
removing one of them will solve your issue , you need to make sure how to access the date in other way

How to add a dropdown or checkbox to the filter in Material-UI dataGrid/XGrid

I am trying to add a checkbox or dropdown to one of the column filter. I have tried using type="boolean" to the columns, it is creating the dropdown but not it not creating the list as I expect. I am expecting the dropdown with two option like "Reachable" and "Unreachable" but it is creating "true" or "false".
Is their any prop name to create the names for the Filter types? I am expecting like this
or
But I am getting like this
My code looks like this
let rows = list.map((obj, index) => {
return (rows = {
id: index,
"Device ID": obj.device_ID,
Status: obj.device_status,
"Last Reading": obj.device_time
});
});
const columns = [
{
field: "Device ID",
flex: 1,
renderHeader: () => <FormattedMessage id={"device.param.deviceMrid"} />
},
{
field: "Status",
flex: 1,
type: "boolean",
renderHeader: () => <FormattedMessage id={"history.param.deviceStatus"} />
},
{
field: "Last Reading",
flex: 1,
type: "dateTime",
renderHeader: () => (
<FormattedMessage id={"history.param.deviceStatusDate"} />
)
}
];
<div style={{ height: "90%", width: "100%" }}>
<XGrid
pageSize={50}
rowsPerPageOptions={[25, 50, 100]}
rows={rows}
columns={columns}
pagination={true}
/>
</div>;
Thank you!!
You need to add these 2 rows in your column const:
type: "singleSelect",
valueOptions: ["select1","select2",.....]
from {
field: 'brand',
headerName: 'Brand',
width: 150,
editable: false,
},
to
{
field: 'brand',
headerName: 'Brand',
width: 150,
editable: false,
type: "singleSelect",
valueOptions: ["select1","select2",.....]
},

How to add a button to every row in MUI DataGrid

I cant add a button into every row of MUI DataGrid.
I have a MUI DataGrid which I render like this:
<DataGrid rows={rows} columns={columns} pageSize={5} checkboxSelection />
I have added into the columns variable 'actions' column where the button should be. rows are just a a data object I get from the props. how can I add a button into every row (for editing the row)? I have tried mapping the data array but it is not possible to add JSX button into every object of data.
You can add your custom component by overriding GridColDef.renderCell method and return whatever element you want.
The example below displays an action column that renders a single button in each row. When clicking the button, it alerts the current row data in json string:
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", width: 70 },
{
field: "action",
headerName: "Action",
sortable: false,
renderCell: (params) => {
const onClick = (e) => {
e.stopPropagation(); // don't select this row after clicking
const api: GridApi = params.api;
const thisRow: Record<string, GridCellValue> = {};
api
.getAllColumns()
.filter((c) => c.field !== "__check__" && !!c)
.forEach(
(c) => (thisRow[c.field] = params.getValue(params.id, c.field))
);
return alert(JSON.stringify(thisRow, null, 4));
};
return <Button onClick={onClick}>Click</Button>;
}
},
];
Just came across this.
What you need to do is include a renderCell method in your columns array.
const columns = [
{
field: 'col1',
headerName: 'Name 1',
width: 150,
disableClickEventBubbling: true,
},
{
field: 'col2',
headerName: 'Name 2',
width: 300,
disableClickEventBubbling: true,
},
{
field: 'col3',
headerName: 'Name 3',
width: 300,
disableClickEventBubbling: true,
},
{
field: 'col4',
headerName: 'Name 4',
width: 100,
disableClickEventBubbling: true,
},
{
field: 'col5',
headerName: 'Name 5',
width: 150,
***renderCell: renderSummaryDownloadButton,***
disableClickEventBubbling: true,
},
{
field: 'col6',
headerName: 'Name 6',
width: 150,
***renderCell: renderDetailsButton,***
disableClickEventBubbling: true,
},
]
In the above I am rendering a Button inside columns 5 and 6 which will appear on every populated row.
Above that you can have a function which creates and returns a Button from Material-ui.
const renderDetailsButton = (params) => {
return (
<strong>
<Button
variant="contained"
color="primary"
size="small"
style={{ marginLeft: 16 }}
onClick={() => {
parseName(params.row.col6)
}}
>
More Info
</Button>
</strong>
)
}
While #NearHuscarl's response answers the question perfectly, I'd like to post a TypeScript example:
const onClick = () => {
const api: GridApi = params.api;
const fields = api
.getAllColumns()
.map((c) => c.field)
.filter((c) => c !== "__check__" && !!c);
const thisRow: any = {};
fields.forEach((f) => {
thisRow[f] = params.getValue(params.id, f);
});
return alert(JSON.stringify(thisRow, null, 4));
};
return <Button onClick={onClick}>Click</Button>;
Also note, I changed the getValue call. (included the row id)
According to MUI v5 params.getValue method is deprecated and will be removed in the next major version, Instead, you can access the current row data from params.row.
{
field: 'action',
headerName: 'Action',
width: 180,
sortable: false,
disableClickEventBubbling: true,
renderCell: (params) => {
const onClick = (e) => {
const currentRow = params.row;
return alert(JSON.stringify(currentRow, null, 4));
};
return (
<Stack direction="row" spacing={2}>
<Button variant="outlined" color="warning" size="small" onClick={onClick}>Edit</Button>
<Button variant="outlined" color="error" size="small" onClick={onClick}>Delete</Button>
</Stack>
);
},
}
The currently top voted answer is outdated as of v5, because the new GridRowParams interface contains the actual row as a parameter, making the manual filtering from the GridApi unnecessary and unpractical.
Using this with renderCell can be as simple as
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", width: 70 },
{
field: "action",
headerName: "Action",
sortable: false,
renderCell: ({ row }: Partial<GridRowParams>) =>
<Button onClick={() => yourActionFunction(row)}>
Action
</Button>,
},
]
in TypeScript or
const columns = [
{ field: "id", headerName: "ID", width: 70 },
{
field: "action",
headerName: "Action",
sortable: false,
renderCell: ({ row }) =>
<Button onClick={() => yourActionFunction(row)}>
Action
</Button>,
},
]
in plain JavaScript.

react-table render component inside data

I'm attempting to add a component inside the data using react-table package (https://www.npmjs.com/package/react-table#example)
Using the example from the package readme, I'm trying to use a fancy component to add an image to a cell:
using ** to jump out in the code...
I have also tried:
imageUrl:{<PlaceholderImage width={60} textColor="#fff" text="Image"/>}
example:
import ReactTable from 'react-table'
import 'react-table/react-table.css'
**import { PlaceholderImage } from 'react-placeholder-image'**
render() {
const data = [{
name: 'Tanner Linsley',
age: 26,
**imageUrl:<PlaceholderImage width={60} textColor="#fff" text="Image"/>,**
friend: {
name: 'Jason Maurer',
age: 23,
}
},{
...
}]
const columns = [{
Header: 'Name',
accessor: 'name' // String-based value accessors!
}, {
Header: 'Age',
accessor: 'age',
Cell: props => <span className='number'>{props.value}</span> // Custom cell components!
}, {
Header: ' ',
accessor: 'imageUrl', // String-based value accessors!
maxWidth: 70,
minWidth:70,
},{
id: 'friendName', // Required because our accessor is not a string
Header: 'Friend Name',
accessor: d => d.friend.name // Custom value accessors!
}, {
Header: props => <span>Friend Age</span>, // Custom header components!
accessor: 'friend.age'
}]
return <ReactTable
data={data}
columns={columns}
/>
}
You're passing a react component to a data field that expects a string. Try customising your cell via Cell props:
const columns = [
{
Header: "Image",
accessor: "imageUrl",
maxWidth: 70,
minWidth: 70,
Cell: props => <PlaceholderImage width={60} textColor="#fff" text="Image" />
}
];
In addition to #Clarity's answer, there's also a possibility to access the cell's value at the Cell's property level:
const columns = [
{
Header: "Image",
accessor: "imageUrl",
maxWidth: 70,
minWidth: 70,
Cell: ({ cell: { value } }) => (
<img
src={value}
width={60}
/>
)
}
];

Resources