How to Disable Row in Antd Table - reactjs

so I worked on a project using react js with umi js and antd as additional dependencies,
I had a problem when I got the task to disable each row in the antd table,
I tried to read the documentation antd but got nothing,
is it possible that you can do that? or there is another possible way to doing that
Thank you for the help
here's my code :
/* eslint-disable */
import React, { useState, useEffect, useRef } from 'react';
import { Modal, Button, Select, message, Radio, Table, Alert } from 'antd';
import _ from 'lodash';
import axios from 'axios';
import cookies from 'js-cookie';
import {_getCurrentBusiness} from '../../../utils/utils_business';
import {formatMessage } from 'umi-plugin-locale';
function DeleteConfirm (props) {
const user_auth = cookies.getJSON('ckmsbp');
const business = _getCurrentBusiness();
const [radio, setRadio] = useState('all');
const [role, setRole] = useState(null);
const [chRole, setChrole] = useState(null); //changerole
const [btn, setBtn] = useState(false);
const isMounted = useRef(null);
const roleRef = useRef(null);
const spanAmount = {fontSize: '1rem', fontWeight: 500,marginLeft: '1rem'}
useEffect( () => {
isMounted.current = true;
return () => isMounted.current = false;
}, [])
useEffect( () => {
if(!_.isNil(props.roles)) {
const updateRole = _.filter(props.roles, r => !_.eq(r.id, props.role.id) );
setRole(updateRole); //tampil di select
}
}, [props.roles]);
const handleSubmit = async () => {
let accountMeta = {}
const body = {status: 'deleted'}
const params = { _id: props.role.id}
console.log('radio', radio);
if(_.eq(radio, 'all')){
if(_.isNil(chRole)) {
message.error('data can not empty')
props.chVisible(null); //close modal
}
_.forEach(props.account, async acc => {
let bus = [];
if( !_.isNil(acc.business) && _.isString(acc.business) ) bus = JSON.parse(acc.business);
const find = _.findIndex(bus, b => {
return _.eq(b._id, business._id) && _.eq(b.role_capability, props.role.id)
})
bus[find].role_capability = chRole;
acc.business = JSON.stringify(bus)
accountMeta = {
value : acc.business,
key : 'business',
account_id: acc._id
}
await axios.put(`${API}/account-meta`, accountMeta, { headers: { Authorization: user_auth.token}});
})
} else if( _.eq(radio, 'manual')){
console.log('asd');
} else if (_.eq(radio, 'delete')){
_.forEach(props.account, async acc => {
let bus = [];
if( !_.isNil(acc.business) && _.isString(acc.business) ) bus = JSON.parse(acc.business);
const find = _.findIndex(bus, b => _.eq(b._id, business._id) && _.eq(b.role_capability, props.role.id) )
if(_.gt(find, -1)){
acc.business = JSON.stringify([])
accountMeta = {
value : acc.business,
key : 'business',
account_id: acc._id
}
await axios.put(`${API}/account-meta`, accountMeta, { headers: { Authorization: user_auth.token}});
}
})
}
const deleteResult = await axios.put(`${API}/master`, body, { params, headers: { Authorization: user_auth.token}});
if(!_.isNil(deleteResult) && _.isObject(deleteResult.data)){
let no = 1;
let data = []
let updateRole = _.filter(props.roles, r => !_.eq(r.id, props.role.id));
_.map(updateRole, role => {
role.no = no;
data.push(role)
no++
});
props.data(data); //tampil di select
message.success('data updated!')
props.chVisible(null); //close modal
}
}
const onChange = (data) => {
const value = data.target.value
setRadio(value);
}
const roleChange = (data) => {
setChrole(data)
}
//props column diambil dari datasource
const columns = [
{
title : 'No',
dataIndex: 'no',
key : 'no',
},
{
title : 'Account\'s Name',
dataIndex: 'name',
key : 'name',
},
{
title : 'Change Role',
dataIndex: 'id',
key : 'action',
render : (text, data) => renderButton(text, data)
},
];
const handleClick = (e, data) => {
setBtn(!btn)
console.log('e', e);
console.log('data', data);
}
const rowClassName = (record, index) => {
console.log('record', record);
console.log('index',index);
}
const renderButton = () => {
let arrayAllow = [];
arrayAllow.push(
<Select
showSearch
key = '1'
size = "small"
placeholder = "select"
ref = {roleRef}
optionFilterProp = "children"
style = {{ width: 100 }}
onChange = {(e) => roleChange(e)} //handle change role
filterOption = {(input, option) => _.toLower(option.props.children).indexOf(_.toLower(input)) >= 0}
>
{
!_.isNil(role) && _.map(role, (newVal) => {
return (<Select.Option
key = {newVal.id}
title = {newVal.title}
value = {newVal.id}>{newVal.title}
</Select.Option>)
})
}
</Select>
)
arrayAllow.push( <Button
type = {!btn ? "danger" : "primary"}
key = '2'
icon = {!btn ? "close" : "redo"}
size = "small"
onClick = {(e) => handleClick(e, props.role.id)}
/> )
return arrayAllow
}
// R E N D E R I N G
return(
<div>
<Modal
title = {`${formatMessage({id: 'ROLE_MANAGEMENT.DELETE_CONFIRM_TITLE'})} ${props.role.title}`}
visible = {props.visible}
onOk = {() => handleSubmit()}
onCancel = {() => props.cancel(null) }
width = {800}
>
<p>{formatMessage({id : 'ROLE_MANAGEMENT.DELETE_CONFIRM_STATEMENT', title: props.role.title})}</p>
<div style={{marginBottom: '1rem'}}>
<Radio.Group onChange = {(e) => onChange(e)} value={radio}>
<Radio value="all" >Changed All of people </Radio>
<Radio value="manual">Changed people manually</Radio>
<Radio value="delete">Total delete </Radio>
</Radio.Group>
</div>
{ _.eq(radio, 'all') &&
<div>
<Select
showSearch
ref = {roleRef}
size = "large"
style = {{ width: 200 }}
placeholder = {formatMessage({id: 'ACCOUNT.PLCHOLDER_ROLE'})}
optionFilterProp = "children"
onChange = {(e) => roleChange(e)} //handle change role
filterOption = {(input, option) => _.toLower(option.props.children).indexOf(_.toLower(input)) >= 0}
>
{
!_.isNil(role) && _.map(role, (newVal) => {
return ( <Select.Option
key = {newVal.id}
title = {newVal.title}
value = {newVal.id}
>{newVal.title}
</Select.Option> )
})
}
</Select>
<span style={spanAmount}>{`Total amount of people which have role ${props.role.title} : ${_.size(props.account)}`}</span>
</div>
}
{ _.eq(radio, 'manual') && <Table
dataSource = {props.account}
rowClassName = {rowClassName}
columns = {columns}
pagination = {{ pageSize: 50 }}
scroll = {{ y: 250 }}
/>
}
{ _.eq(radio, 'delete') && <Alert
message = "Attention!"
description = {formatMessage({id: 'ROLE_MANAGEMENT.DELETE_CONFIRM_DELETE'})}
type = "warning"
showIcon
/>
}
</Modal>
</div>
)
}
export default DeleteConfirm;
*the picture that I intend to disable when clicked on the danger button

In Antd there is no simple way to disable a row, so you can do it as workaround like below
So basically when you click on close button you can have state whether its been enabled or disabled as a boolean value
so each record will have that key. so based on that you can add a className and style it as disabled.
Here is a sample code snippet
App.js
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Table } from "antd";
import "./styles.css";
function App() {
const dataSource = [
{
key: "1",
name: "Mike",
age: 32,
address: "10 Downing Street",
enabled: true
},
{
key: "2",
name: "John",
age: 42,
address: "10 Downing Street",
enabled: false
}
];
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name"
},
{
title: "Age",
dataIndex: "age",
key: "age"
},
{
title: "Address",
dataIndex: "address",
key: "address"
}
];
return (
<>
<Table
dataSource={dataSource}
columns={columns}
rowClassName={record => !record.enabled && "disabled-row"}
/>
;
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
style.css
.disabled-row {
background-color: #dcdcdc;
pointer-events: none;
}
I hope this way you will have better understanding of solving the problem
Working codesandbox

Related

how to color specific keywords in slate js

Trying to get the word "hello" to appear in different color, using almost 1:1 the example from the examples, but can't get it to work.
Whenever I type "hello" the text starts to appear twice as I write.
My code:
import { Editable, Slate, withReact } from "slate-react";
import React, { useMemo, useState } from "react";
import { Text, createEditor } from "slate";
import { withHistory } from "slate-history";
const log = (x) => {
console.log(x);
return x;
};
const tokenize = (text) =>
text
.split(/(\s+)/)
.map((x) => (x === "hello" ? { content: x, type: "keyword" } : x));
const getLength = (token) =>
typeof token === "string"
? token.length
: typeof token.content === "string"
? token.content.length
: token.content.reduce((l, t) => l + getLength(t), 0);
const Leaf = ({ attributes, children, leaf }) => (
<span
style={{ color: log(leaf).keyword ? "green" : "black" }}
{...attributes}
>
{log(children)}
</span>
);
const CodeEditor = () => {
const [value, setValue] = useState([
{
type: "paragraph",
children: [
{
text: "",
},
],
},
]);
const editor = useMemo(() => withHistory(withReact(createEditor())), []);
return (
<Slate editor={editor} value={value} onChange={(value) => setValue(value)}>
<Editable
decorate={decorate}
renderLeaf={(props) => <Leaf {...props} />}
placeholder="Write some code..."
/>
</Slate>
);
};
const decorate = ([node, path]) => {
if (!Text.isText(node)) {
return [];
}
const ranges = [];
const tokens = tokenize(node.text);
let start = 0;
for (const token of tokens) {
const end = start + getLength(token);
if (typeof token !== "string") {
ranges.push({
[token.type]: true,
anchor: { path, offset: start },
focus: { path, offset: end },
});
}
start = end;
}
return ranges;
};
export default CodeEditor;
The code is fine, this was a bug in the lib fixed in https://github.com/ianstormtaylor/slate/pull/4556.

fluent ui details List implementation in Functional component

Can anybody send code on how to implement fluent UI details List in Functional Component(https://developer.microsoft.com/en-us/fluentui#/controls/web/detailslist/basic) and how to fetch data from API to details List
That's a start you will need to "refact" this code by the way this is a really good practice :
import * as React from "react";
import { Announced } from "office-ui-fabric-react/lib/Announced";
import {
TextField,
ITextFieldStyles
} from "office-ui-fabric-react/lib/TextField";
import {
DetailsList,
DetailsListLayoutMode,
Selection,
IColumn
} from "office-ui-fabric-react/lib/DetailsList";
import { MarqueeSelection } from "office-ui-fabric-react/lib/MarqueeSelection";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { mergeStyles } from "office-ui-fabric-react/lib/Styling";
import { Text } from "office-ui-fabric-react/lib/Text";
const exampleChildClass = mergeStyles({
display: "block",
marginBottom: "10px"
});
const textFieldStyles: Partial<ITextFieldStyles> = {
root: { maxWidth: "300px" }
};
export interface IDetailsListBasicExampleItem {
key: number;
name: string;
value: number;
}
export interface IDetailsListBasicExampleState {
items: IDetailsListBasicExampleItem[];
selectionDetails: string;
}
export const DetailsListBasicExampleFunction: React.FunctionComponent<
{} | IDetailsListBasicExampleState
> = () => {
const _allItems: IDetailsListBasicExampleItem[] = [];
const [selection, setSelection] = React.useState<Selection | undefined>();
function _getSelectionDetails(): string {
const selectionCount = selection ? selection.getSelectedCount() : 0;
switch (selectionCount) {
case 0:
return "No items selected";
case 1:
return (
"1 item selected: " +
(selection.getSelection()[0] as IDetailsListBasicExampleItem).name
);
default:
return `${selectionCount} items selected`;
}
}
const [state, setState] = React.useState({
items: _allItems,
selectionDetails: _getSelectionDetails()
});
React.useEffect(() => {
const _selection: Selection = new Selection({
onSelectionChanged: () =>
setState((prev) => {
return { ...prev, selectionDetails: _getSelectionDetails() };
})
});
setSelection(_selection);
for (let i = 0; i < 200; i++) {
_allItems.push({
key: i,
name: "Item " + i,
value: i
});
}
setState((prev) => {
return { ...prev, items: _allItems };
});
}, []);
const _columns: IColumn[] = [
{
key: "column1",
name: "Name",
fieldName: "name",
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: "column2",
name: "Value",
fieldName: "value",
minWidth: 100,
maxWidth: 200,
isResizable: true
}
];
// Populate with items for demos.
const _onFilter = (
ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
text: string
): void => {
console.log(text);
setState((prev) => {
return {
...prev,
items: text
? _allItems.filter((i) => i.name.toLowerCase().indexOf(text) > -1)
: _allItems
};
});
};
const _onItemInvoked = (item: IDetailsListBasicExampleItem): void => {
alert(`Item invoked: ${item.name}`);
};
return selection ? (
<Fabric>
<div className={exampleChildClass}>{state.selectionDetails}</div>
<Text>
Note: While focusing a row, pressing enter or double clicking will
execute onItemInvoked, which in this example will show an alert.
</Text>
<Announced message={state.selectionDetails} />
<TextField
className={exampleChildClass}
label="Filter by name:"
onChange={(e, t) => _onFilter(e, t ?? "")}
styles={textFieldStyles}
/>
<Announced
message={`Number of items after filter applied: ${state.items.length}.`}
/>
<MarqueeSelection selection={selection}>
<DetailsList
items={state.items}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
onItemInvoked={_onItemInvoked}
/>
</MarqueeSelection>
</Fabric>
) : (
<div>Loading</div>
);
};
UPDATE
To pass this sample of code in JSX this is pretty easy you just need to remove all type thing.
And to fetch data I use axios.
see the code below:
import * as React from "react";
import { Announced } from "office-ui-fabric-react/lib/Announced";
import { TextField } from "office-ui-fabric-react/lib/TextField";
import {
DetailsList,
DetailsListLayoutMode,
Selection
} from "office-ui-fabric-react/lib/DetailsList";
import { MarqueeSelection } from "office-ui-fabric-react/lib/MarqueeSelection";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { mergeStyles } from "office-ui-fabric-react/lib/Styling";
import { Text } from "office-ui-fabric-react/lib/Text";
import axios from "axios";
const exampleChildClass = mergeStyles({
display: "block",
marginBottom: "10px"
});
const textFieldStyles = {
root: { maxWidth: "300px" }
};
export const DetailsListBasicExampleFunction = () => {
const _allItems = [];
const [selection, setSelection] = React.useState();
function _getSelectionDetails() {
const selectionCount = selection ? selection.getSelectedCount() : 0;
switch (selectionCount) {
case 0:
return "No items selected";
case 1:
return "1 item selected: " + selection.getSelection()[0].name;
default:
return `${selectionCount} items selected`;
}
}
const [state, setState] = React.useState({
items: _allItems,
selectionDetails: _getSelectionDetails()
});
React.useEffect(() => {
const _selection = new Selection({
onSelectionChanged: () =>
setState((prev) => {
return { ...prev, selectionDetails: _getSelectionDetails() };
})
});
setSelection(_selection);
//********************** */fetch data from api***************************************
axios
.get("/data.json") //pass your url in param
.then((res) =>
setState((prev) => {
return { ...prev, items: res.data };
})
); //pass data in setState
}, []);
const _columns = [
{
key: "column1",
name: "Name",
fieldName: "name",
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: "column2",
name: "Value",
fieldName: "value",
minWidth: 100,
maxWidth: 200,
isResizable: true
}
];
// Populate with items for demos.
const _onFilter = (ev, text) => {
console.log(text);
setState((prev) => {
return {
...prev,
items: text
? _allItems.filter((i) => i.name.toLowerCase().indexOf(text) > -1)
: _allItems
};
});
};
const _onItemInvoked = (item) => {
alert(`Item invoked: ${item.name}`);
};
return selection ? (
<Fabric>
<div className={exampleChildClass}>{state.selectionDetails}</div>
<Text>
Note: While focusing a row, pressing enter or double clicking will
execute onItemInvoked, which in this example will show an alert.
</Text>
<Announced message={state.selectionDetails} />
<TextField
className={exampleChildClass}
label="Filter by name:"
onChange={(e, t) => _onFilter(e, t ?? "")}
styles={textFieldStyles}
/>
<Announced
message={`Number of items after filter applied: ${state.items.length}.`}
/>
<MarqueeSelection selection={selection}>
<DetailsList
items={state.items}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
onItemInvoked={_onItemInvoked}
/>
</MarqueeSelection>
</Fabric>
) : (
<div>Loading</div>
);
};

Find element has className in enzyme not found with renderoption autocompleted material

I'm testing react component use enzyme and jest test. I'm try use find method in enzyme but it not found, i'm sure this element have been render because when I print actionClass const it return value "ts-cbb-item".
I have a combobox component:
/* eslint-disable no-use-before-define */
import Autocomplete from '#material-ui/lab/Autocomplete';
import PropTypes from 'prop-types';
import React, { useState, useRef } from 'react';
import './index.scss';
import InputCombobox from './input-combobox';
const ComboBox = (props) => {
const {
loading,
options,
onDataBinding,
onChange,
customRenderItem,
placeholder,
renderStartAdornment,
closeIcon,
disabled,
customGetOptionLabel,
onInputChange,
style,
clearOnBlur = false,
defaultValue,
...rest
} = props;
const currentSearch = useRef();
const [currentOption, setOption] = useState(null);
const [isInput, setIsInput] = useState(false);
const handleInputChange = (_, value, reason) => {
const isReasonInput = reason === 'input';
if (isReasonInput) {
setIsInput(false);
if (onInputChange)
onInputChange(value);
}
currentSearch.current = value;
if (value?.length < 3) return;
if (isReasonInput) onDataBinding(value);
}
const handleChangeOpt = (opt) => {
setIsInput(true);
if (onChange) onChange(opt);
}
return (
<Autocomplete
clearOnBlur={clearOnBlur}
disabled={disabled}
closeIcon={closeIcon}
className="ts-combobox"
options={options}
loading={loading}
onInputChange={handleInputChange}
defaultValue={defaultValue}
getOptionLabel={(option) => customGetOptionLabel
? customGetOptionLabel(option)
: option.label}
getOptionSelected={option => {
if (!currentOption || !currentOption.value) return false;
return option.value === currentOption.value;
}}
style={style ? style : { width: '100%' }}
renderOption={(option, state) => {
const actionClass = state?.selected ? "ts-ccb-item active" : "ts-ccb-item";
console.log('class:', actionClass);
return <div
onClick={() => {
setOption(option);
handleChangeOpt(option);
}}
className={actionClass}>
{ customRenderItem
? customRenderItem(option, currentSearch)
: option.label }
</div>
}}
);
}
export default ComboBox;
This is my test :
let initProps = {
loading: false,
options: [],
onDataBinding: () => {},
onChange: () => {},
customRenderItem: () => {},
renderStartAdornment: () => {},
closeIcon: null,
disabled: false,
customGetOptionLabel: () => {},
onInputChange: () => {},
style: null,
clearOnBlur: false,
placeholder: '',
defaultValue: null
}
const options = [
{
label: 'Cristiano Ronaldo',
value: 'Portugal'
},
{
label : 'Leo Messi',
value : 'Argentina'
},
{
label : 'Jesse Lingard',
value : 'England'
}
]
const event = {
preventDefault() {},
}
const onInputChangeMockFn = jest.fn((value) => value);
const onDataBindingMockFn = jest.fn( (value) => value? true: false);
const renderStartAdornmentMockFn = jest.fn((option) => option ? option.value : null );
const customGetOptionLabelMockFn = jest.fn((option) => option? option.label : null)
const renderInputParams = {
id: '',
disabled: false,
fullWidth: true,
size: 'small',
InputLabelProps: {},
InputProps: {},
inputProps: {}
}
it("Test_Comobox_With_RenderInput_Active(RenderStartAdornment_Have_Value)", () => {
initProps.renderStartAdornment = renderStartAdornmentMockFn;
initProps.customGetOptionLabel = customGetOptionLabelMockFn;
initProps.options = options;
const wrapper = mount(
<ComboBox {...initProps} />
);
const autoCompleted = wrapper.find(Autocomplete);
autoCompleted.props().renderOption(options[1], autoCompletedRenderOptionState);
autoCompleted.props().renderInput(renderInputParams);
expect(autoCompleted.find('div .ts-cbb-item')).toHaveLength(1);
const inputCombobox = wrapper.find(InputCombobox);
expect(inputCombobox.props().renderStartAdornment).toBeUndefined();
})
How can I find exactly element div has ClassName 'ts-cbb-item' in this case?

React Checkbox not updating in functional component

Here is my functional component: (Link to reproduce)
import React, { useState } from "react";
import Aux from "../../../../../../hoc/Auxilary/Auxilary";
const DropDownContainer = (props) =>
{
const CheckedArray = Array(props.Data.length);
for(let i = 0; i< CheckedArray.length; i++)
CheckedArray[i] = false;
const [Selected, setSelected] = useState({
filterName: props.Name,
filterObjects: props.Data,
checked: CheckedArray.slice(),
multiSelectAllowed: false,
});
const propsStructure = props.Data.map((elem, index) => (
{
title: elem,
isSelected: false,
id: index,
key: "DropDown "+index,
checkboxStyle: {
width:"20%",
},
contentStyle: {
width: "80%",
}
}
));
const CheckBoxHandler = (index) =>
{
const newSelection = Selected;
if(!Selected.multiSelectAllowed)
{
newSelection.checked.forEach((_,ind) => (newSelection.checked[ind] = false));
}
newSelection.checked[index] = !newSelection.checked[index];
setSelected(newSelection);
console.log(Selected.checked[index]);
console.log(Selected.checked);
}
const PropDiv = propsStructure.map((elem) => {
return <div className = "CheckBoxRow" key ={elem.key}>
<input
style = {elem.checkboxStyle} type = "checkbox" checked = {Selected.checked[elem.id]}
onChange = {() => {CheckBoxHandler(elem.id)}}
/>
<div style = {elem.contentStyle}>{elem.title}</div>
</div>
});
return(
<Aux>
<div className = "Boxing">
{PropDiv}
</div>
</Aux>
);
}
export default DropDownContainer;
/*
from
props = ["a","b","c"]
to
propsStructure = [
{
title:,
isSelected:,
}
]
*/
As per my code... when I print Selected.checked the value gets updated correctly. But it doesn't reflect in checkbox of the UI. As you can see here:
Can anyone point out the way to solve this? Here is the link to reproduce. As you can see in the console, the values are updating correctly but in my checkbox, it takes the initial value which is passed at the beginning which is false in this case and so despite me trying to check it, it always remains unchecked.
i am change code .
import React, { useState } from "react";
const DropDownContainer = (props) => {
const CheckedArray = Array(props.Data.length);
for (let i = 0; i < CheckedArray.length; i++) CheckedArray[i] = false;
const [Selected, setSelected] = useState({
filterName: props.Name,
filterObjects: props.Data,
checked: CheckedArray.slice(),
multiSelectAllowed: false
});
const propsStructure = props.Data.map((elem, index) => ({
title: elem,
isSelected: false,
id: index,
key: "DropDown " + index,
checkboxStyle: {
width: "20%"
},
contentStyle: {
width: "80%"
}
}));
const CheckBoxHandler = (index) => {
let newSelection = { ...Selected };
newSelection.checked[index] = !newSelection.checked[index];
setSelected(newSelection);
console.log(Selected.checked[index]);
console.log(Selected.checked);
};
const PropDiv = propsStructure.map((elem) => {
return (
<div className="CheckBoxRow" key={elem.key}>
<input
style={elem.checkboxStyle}
type="checkbox"
checked={Selected.checked[elem.id]}
onClick={() => {
CheckBoxHandler(elem.id);
}}
/>
<div style={elem.contentStyle}>{elem.title}</div>
</div>
);
});
return (
<div>
<div className="Boxing">{PropDiv}</div>
</div>
);
};
export default DropDownContainer;
/*
from
props = ["a","b","c"]
to
propsStructure = [
{
title:,
isSelected:,
}
]
*/
**Working Demo:**

How to add form fields dynamically in react js

I want to add form fields dynamically.
I also want that on click the durationprice add dynamically and also a button to add dynamically full plan.
{ plan: [ { planname: "", description: "", cuisine: "", durationprice: [{duration: "",maximumduration: "", price: ""}]}]}
import React, {
Component,
useState
} from "react";
import DurationPrice from "./DurationandPrice";
import Rules from "./Rules";
const TOKEN = 'hello';
export function PlanForm() {
const [inputList, setInputList] = useState([{
planName: "",
description: "",
cuisine: "",
}, ]);
const handleChnage = (e, index) => {
const {
name,
value
} = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleInput = () => {
const list = [...inputList];
list.push({
planName: "",
description: "",
cuisine: ""
});
setInputList(list);
// setInputList([...inputList,{firstName:'',lastName:''}]);
};
const handleRemove = (index) => {
const list = [...inputList];
list.splice(index, 1);
setInputList(list);
};
const handleSubmit = (e) => {
e.preventDefault();
};
const handleSave = (e) => {
e.preventDefault();
console.log('button clicked');
fetch(`https://cosynest-api.herokuapp.com/api/plans/create`, {
method: 'POST',
body: JSON.stringify({
'duration': inputList.duration,
'maximumDuration': inputList.maximumDuration,
'price': inputList.price
}),
headers: new Headers({
Authorization: `Bearer ${TOKEN}`,
'content-type': 'application/json'
})
})
.then(response => response.json())
.then(console.log(inputList))
.then(localStorage.setItem('Token-CreateShop', TOKEN))
.catch(console.log('error'))
}
// debugger;
return ( <
div className = "plan-form" > {
inputList.map((item, i) => {
return ( <
form key = {
i
}
onSubmit = {
handleSubmit
} >
<
input type = "text"
name = "planName"
className = "mr-10 input "
placeholder = "Plan Name"
value = {
item.planName
}
onChange = {
(e) => handleChnage(e, i)
}
/> <
input type = "text"
name = "description"
className = "mr-10 input "
placeholder = "Description"
value = {
item.description
}
onChange = {
(e) => handleChnage(e, i)
}
/> <
input type = "cuisine"
onChange = {
(e) => handleChnage(e, i)
}
value = {
item.cuisine
}
className = "mr-10 input "
name = "cuisine"
placeholder = "Cuisine" /
>
<
h2 > Duration and Price < /h2> <
DurationPrice / >
<
br / >
<
div > {
inputList.length - 1 === i && ( <
button type = "button"
onClick = {
handleInput
}
className = "mr-10 btn"
value = "Add Plan" >
Add Plan <
/button>
)
} {
inputList.length !== 1 && ( <
button onClick = {
() => handleRemove(i)
}
className = "mr-10 btn-red"
value = "Remove Plan" >
Remove <
/button>
)
} <
/div>
<
/form>
);
})
} <
button onClick = {
handleSave
}
className = "btn-pink btn "
type = "submit" > Save PLANS < /button> {
/* <pre>
{JSON.stringify(inputList,null,3)}
</pre> */
} <
/div>
);
}
export default PlanForm;
you can use one state that will have all the formData states inside it and for the input elements you can use map to render
lets say you have to create form for these fields
let formElements = [{
label: "Name", // this is label
key: 'name' // this is unique key to be used as state name
}, {
label: "Phone number",
key: 'phone'
}, {
label: "House",
key: 'house'
}, {
label: "City",
key: 'city'
}, {
label: "State",
key: 'state'
}, {
label: "Country",
key: 'country'
}]
now you can create your component from this element something like this
export default function App() {
const [formData, setFormData] = useState({} as any);
const handleChange = (value: string, key: string) => {
setFormData({ ...formData, ...{ [key]: value } });
}
const submit = () => {
alert(JSON.stringify(formData))
}
return (
<form>
Form goes here
{formElements.map(formElement => {
return <div>
{formElement.label}
<input value={formData[formElement.key]}
onChange={(e) => { handleChange(e.target.value, formElement.key) }} />
</div>
})}
<button onClick={(e) => { e.preventDefault(); submit() }}>submit</button>
</form>
);
}
Now whenever you want to update the form fields just update your formElements Array.
in your case you can store formElements in state and update that like this
const [formElement,setFormElements] = useState([]);
useEffect(()=>{
setFormElements(formElement)
},[]);
// update your state with new element like this on button click
const updateFormElememt = (newElement)=>{
setFormElements([...formElements,...newElement])
}

Resources