MUI-Datatables columns config conversion - reactjs

I can't work out how to merge data differently based on what data is passed. Here is the prop data....
columns={[
{
name: "Fund Name", //Title
width: "40%", //Colum Width
options: {[
customBodyRender: (value, tableMeta, updateValue) => {
var splitValue = value.split("//");
return (
<div className="fundName">{splitValue[0]}<p>{splitValue[1]}</p></div>
);
}
]}
}, {
name: "Review Date",
width: "20%"
}, {
name: "Company Debt",
width: "20%"
}, {
name: "Alerts",
width: "10%",
options: {[
simpleBodyRender: <Options />
]}
}
}
So if it using customBodyRender I want it to do one thing and if it's doing simpleBodyRender I want it to do it slightly differently.
Here is the merging
let columns = this.props.columns.map(item => {
item.options
? ({ ...item, options: eval(item.options) })
: item
});
Basically I want it to look more like this...
let columns = this.props.columns.map(item => {
if(item.options == "customBodyRenderer"){
item.options
? ({ ...item, options: eval(item.options) })
: item
});
} else if(item.options == "simpleBodyRenderer"){
item.options
? ({ ...item, options: customBodyRender: (value, tableMeta, updateValue) => { eval(item.options) }})
: item
});
}
});
So if it's customBodyRenderer it prints everything but if it's simpleBodyRenderer it fills in the customBodyRender: (value, tableMeta, updateValue) => { for the user.
I hope that makes sense.
Thanks

Storing components in state and other structures is not a good idea at all. Doable but not recommended.
Just forget about eval ... you can only use functions that returns functions ... you can use components as parameters, render it inside other components, HOC, compose ... if you know how (more advanced react knowledge required) ... now KISS.
You can (?) use simple strings as source:
options: {
simpleBodyRender: "options"
}
... and transform it using '.map` into required format (function returning components):
let columns = this.props.columns.map(item => {
if(item.options && item.options.simpleBodyRender){
swith( item.options.simpleBodyRender ) {
case "options":
return { ...item,
options: {
customBodyRender: (value, tableMeta, updateValue) => <Options data={value} />
}
}
case "other options":
return { ...item,
options: {
customBodyRender: (value, tableMeta, updateValue) => <OtherOptions data={value} />
}
}
default: return { ...item,
options: {
customBodyRender: (value, tableMeta, updateValue) => <NotSupportedSimpleBodyRenderer />
}
}
}
}
}
}
Notece: options: { <<< single bracket, object, not {[

You can do it easily by modifying a bit your input data (columns), as follows :
const data = myInput.map((el) => { return { item: el }; });
Then you pass data as the input to your mui-datatable as follows :
<MuiThemeProvider theme={getMuiTheme()}>
<MUIDataTable data={data} columns={columns} options={options} />
</MuiThemeProvider>
In your column definition, 'name' is 'item'
So columns may look like this :
const columns = [
{
label: 'myLabel',
name: 'item',
options: {
display: true,
customBodyRender: (value) => {
return <p>{value.myData}</p>;
},
},
},
//other labels here
];

Related

How to use rowspan in react-table

Any idea how to use rowSpan in react table. for below example usernameFormatter there are multiple values.
Note: attach picture is copied but that's looks like what I wanted
const columns = [
{
accessor: "id",
show: false,
},
{
Header: "Username",
id: "username",
accessor: "username",
Cell: this.usernameFormatter,
enableRowSpan: true
}
]
<ReactTable
data={this.state.users}
filterable={true}
columns={columns}
defaultPageSize={18}
getTdProps={(state, rowInfo, column) => {
const index = rowInfo ? rowInfo.index : -1;
return {
onClick: (e, handleOriginal) => {
if (column.Header === undefined) {
handleOriginal();
} else {
if (rowInfo !== undefined) {
this.selectedRow = index;
this.onRowSelect(rowInfo.original.id);
}
}
},
};
}}
/>

Passing code block as a prop to add to an array

I have a very niche issue where I am trying to pass a block of executable code as a prop options. The prop looks like this...
columns={[
{
name: "Fund Name", //Title
width: "40%", //Colum Width
options: {[
var splitValue = value.split("//");
return (
<div className="fundName">{splitValue[0]}<p>{splitValue[1]}</p></div>
);
]}
}, {
name: "Review Date",
width: "20%"
}, {
name: "Company Debt",
width: "20%"
}, {
name: "Alerts",
width: "10%",
options: {[
return <Alerts {data: value} />
]}
}
}
So sometimes there are some variables and additional code and sometimes it may just be returning a component. Anyway. I need the code to look like this in the component...
const columns = [{
name: "Fund Name",
options: {
customBodyRender: (value, tableMeta, updateValue) => {
var splitValue = value.split("//");
return (
<div className="fundName">{splitValue[0]}<p>{splitValue[1]}</p></div>
);
}
}
}, {
name: "Review Date"
}, {
name: "Company Debt"
}, {
customBodyRender: (value, tableMeta, updateValue) => {
return <Alerts {data: value} />
}
}];
So firstly. Is this possible? can I pass variables like the splitValue, and, will it pick up that the passed in "value" variable is to be associated with the customBodyRender: (value,.... variable?
Here is my attempt but it is throwing a lot of errors. I feel I may be close if it even at all possible....
let columns = this.props.columns.map(item =>
item.options
? ({ ...item, options: { customBodyRender: (value, tableMeta, updateValue) => { eval(item.options) }} })
: item
);
Thanks
You can't use code directly in data structures because there is simply no syntax for this (in js generally) and ...
"The argument of the eval() function is a string."
Write code as strings? OK, you can. Problem here? JSX is transpiled into normal Javascript code (using bable). eval won't do that.
Is it possible to use JSX from running code with eval? Yes, you can using babel or other libs.
Of course using/storing functions is a preferred (safer) way for this kind of jobs.

Convert JSX string to JSX expression with .map (React)

I need to change this data that is passed into a component
columns={[{
name: "Fund Name",
width: "40%"
}, {
name: "Review Date",
width: "20%"
}, {
name: "Company Debt",
width: "20%"
}, {
name: "Alerts",
width: "10%"
}, {
name: "Actions",
width: "10%",
options: 'customBodyRender: (value, tableMeta, updateValue) => { return (<Options />);'
}]
}
to this inside the component...
const columns = [{
name: "Fund Name",
}, {
name: "Review Date"
}, {
name: "Company Debt"
}, {
name: "Alerts",
}, {
name: "Actions",
options: {
customBodyRender: (value, tableMeta, updateValue) => {
return ( <Options /> );
}
}
}
}];
Basically I've got this far....
let columns = this.props.columns.map((item, key) =>
{ name: item.name }
);
This obviously isn't right but I'm not sure how to say that columns needs to be an array of the data in the .map function.
Please help.
Thanks
Use eval keyword to convert strings to JS expressions
let columns = this.props.columns.map(item =>
item.options
? ({ ...item, options: eval(item.options) })
: item
);
But there is one problem though. Babel cannot transpile the output of eval since it's generated in runtime. So you must convert JSX to normal JS expressions that doesn't need transpilation.
So you code must be like this
const columns = [{
name: "Actions",
options: {
customBodyRender: '(value, tableMeta, updateValue) => { return React.createElement(Options, null); }'
// or
customBodyRender: '(value, tableMeta, updateValue) => { return /*#__PURE__*/_react.default.createElement(Options, null); }'
// Depends on your babel configurations
}]

React Material - MUIDataTable - how to add content in column header

I use in my React app:
import MUIDataTable from "mui-datatables";
I'd like to add some button to my last column header (instead of the column name):
<MUIDataTable
data={data}
columns={columns}
options={options}
>
</MUIDataTable>
where columns:
export const columns = [
{
name: "name",
label: "Nazwa",
options: {
filter: true,
sort: true,
}
},
{
name: "productNumber",
label: "Numer",
options: {
filter: true,
sort: true,
}
}, (...)
How to do that? Is it possible? I can't find anything
You can define a custom body for column. You can add a column like this:
{
name: "Age",
options: {
filter: false,
customBodyRender: (value, tableMeta, updateValue) => (
<FormControlLabel
control={<TextField value={value || ''} type='number' />}
onChange={event => updateValue(event.target.value)}
/>
)
}
}
You need to use customHeadRender
const columns = [
{
name: "id",
label: "Id",
options: {
filter: false,
}
},
{
name: "subject",
label: "Subject",
options: {
filter: true,
sort: false,
}
},
{
name: "button",
options: {
customHeadRender: ({index, ...column}) => {
return (
<Button key={index}>
Click
</Button>
)
}
}
}
];

react-table keeps re-rendering unchanged cells

I am using react-table plugin, and my cells keep re-rendering while I am changing the applied searching filter even though their values aren't changed.
As seen in the video, name and debt TDs keep updating, even though their values are static.
https://i.imgur.com/2KkNs9f.mp4
I imagine, that may impact performance on larger tables.
Is there any fix? Or am I doing anything wrong?
Thanks.
Edit:
Code has been requested. Not much to show, basically everything done as in documentation.
Rendering part:
render(){
const columns = [
{
Header: "Name",
accessor: "name",
className: css.cell,
headerClassName: css.cell,
filterMethod: (filter, row) => {
return row[filter.id]
.toLowerCase()
.includes(filter.value.toLowerCase());
},
Cell: props => {
return <span>{props.value}</span>;
}
},
{
Header: "Tc",
accessor: d => {
const date = d.lastChange;
if (date.length) {
const s = date.split(" ");
const s2 = s[0].split("/");
const mdy = [s2[1], s2[0], s2[2]].join("/");
const his = s[1];
return Date.parse(mdy + " " + his);
}
return "";
},
id: "lastChange",
Cell: props => {
return <ArrowTime lastChange={props.value}></ArrowTime>;
},
headerClassName: css.cell,
className: css.cell
},
{
Header: "Debt",
accessor: d => Number(d.lastDebt),
id: "lastDebt",
headerClassName: css.cell,
className: css.cell,
Cell: props => {
return <span className="number">{props.value}</span>;
},
getProps: (state, rowInfo, column) => {
return {
style: {
background: rowInfo ? this.getColor(rowInfo.row.lastDebt) : null
}
};
}
}
];
return (
<ReactTable
data={this.props.table}
columns={columns}
minRows={0}
showPagination={false}
NoDataComponent={CustomNoDataComponent}
className={css.table}
resizable={false}
filtered={[{ id: "name", value: this.props.filter }]}
getTrProps={(state, rowInfo) => {
return {
className: rowInfo ? css.subRow : ""
};
}}
getTrGroupProps={(state, rowInfo) => {
return {
className: rowInfo ? css.row : ""
};
}}
getTbodyProps={props => {
return {
className: props ? css.tbody : ""
};
}}
getTheadProps={props => {
return {
className: props ? css.thead : ""
};
}}
defaultSorted={[
{
id: "lastDebt",
desc: true
}
]}
/>
);
}

Resources