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

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
}]

Related

how i set only one table row dropdown in reactjs

I am using reacts to develop a website. I need to put a dropdown in only one column.
const tableConfigs = [
{
name: "return or not",
column: {
args: { dataIndex: ["product", "uuid"] },
},
},
{
name: "productid",
column: {
args: { dataIndex: ["product", "uuid"] },
},
},
];
const AllDetails = () => {
return (
<Records
apis={UserOrderItemAPI}
configs={{
modal: modalConfigs,
other: otherConfigs,
table: tableConfigs,
}}
title="all_Details"
/>
);
}
export default AllDetails;
I have this type of code. I want to add dropdown in a one column like this code:
{
name: "image",
column: {
args: {
dataIndex: ["product", "image"],
render: (src) => (
<Image src={src} height="40px" referrerPolicy="no-referrer" />
),
},
},
},
You can use this code for creating a select options. I hope it's use full for you.
import { Select } from 'antd';
const { Option } = Select;
const handleChange = (value) => {
console.log(value); // { value: "no", key: "no", label: "NO" }
};
{
name: "return or not",
column: {
args: { dataIndex: ["product", "uuid"],
rander: (select) => (
<Select labelInValue defaultValue={{value: 'no', label: 'NO',}}style={{width: 120,}} onChange={handleChange}>
<Option value="no">NO</Option>
<Option value="yes">YES</Option>
</Select>
)
}
},
},

conditional editable on cellEdit in material-table

when i use editable attribute in schema
editable: (row, rowData) => {
return rowData.town === "scaraborough";
},
it works fine but when i use celEdit editable property of field just working with boolean
const tableRef = React.useRef();
const [columns, setColumns] = useState<Column<schema>[]>([
{
title: "Name",
field: "name",
editable: "always",
type: "string",
resizable: true,
emptyValue: <div style={{ visibility: "hidden" }}>empty</div>,
},
{
title: "Town",
field: "town",
editable: (row, rowData) => {
return rowData.town === "scaraborough";
},
type: "string",
},
{
title: "Digits",
field: "digits",
type: "numeric",
lookup: { 63: "212", 212: "1212" },
},
{ title: "status", field: "status", editable: "always", type: "boolean" },
]);
const [data, setData] = useState<schema[]>([
{
name: "",
town: "sample input data",
digits: 63,
status: false,
},
{ name: "jimmy", town: "scaraborough", digits: 63, status: false },
{ name: "sdsdd", town: "china", digits: 212, status: false },
]);
const options = { filtering: true, selection: true };
return (
<MaterialTable
tableRef={tableRef}
columns={columns}
data={data}
options={options}
// editable={{
// onRowUpdate: (newData, oldData) =>
// new Promise((resolve, reject) => {
// const dataUpdate = [...data];
// resolve(data);
// }),
// }}
cellEditable={{
onCellEditApproved: (newValue, oldValue, rowData: any, columnDef) => {
return new Promise((resolve, reject) => {
resolve();
});
},
}}
/>
);
"material-table": "^1.69.3",

MUI-Datatables columns config conversion

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
];

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.

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>
)
}
}
}
];

Resources