The code to get tables depends on how many items are selected in the left window in my image below but don't know What I need to write in the onClick function of the button to move the first selected item to the first table GMV1 and the second selected item to GMV2 and so on.
What I want to do is first check the status of contractLineItemSelectionChecked. If the status is true, check the selected items have different contract ids and push the different contract id objects to different places.
[
{
cNo: "CDH0000403",
contractLineItemSelectionChecked: true,
companyCode: "1360",
profitCenter: "DHA1",
approverId: "C7937"
},
{
cNo: "CDH0000404",
contractLineItemSelectionChecked: false,
companyCode: "1360",
profitCenter: "DHA1",
approverId: "C7937"
},
{
cNo: "CDH0000405",
contractLineItemSelectionChecked: true,
companyCode: "1360",
profitCenter: "DHA1",
approverId: "C7937"
}
];
<Field
name="transactionSelected"
component="select"
className="custom-select my-1 mr-sm-2"
id="moveContractLineItems"
onChange={e => {
setFieldValue("transactionSelected", "GMV+ /contract");
document.getElementById("creategoodsMovementsContractsTransaction").click();
getIndex();
}}
>
<option key="select" value="">
Select
</option>
<option key="GMV+ /contract" value="GMV+ /contract">
GMV+ /contract
</option>
<option key="PMT+/contract" value="PMT+/contract">
PMT+/Contract
</option>
</Field>;
<FieldArray name={`transactions["goodsMovements"].transactionItems`}>
{({ push }) => (
<input
type="button"
hidden
id="creategoodsMovementsContractsTransaction"
onClick={() => {
let myCounter = 0;
checkedCheckboxes.forEach(v =>
v.contractLineItemSelectionChecked ? myCounter++ : v
);
for (var i = 0; i < myCounter; i++) {
push({
name:
"GMV" +
(typeof values.transactions.goodsMovements.transactionItems !==
"undefined" &&
values.transactions.goodsMovements.transactionItems.length + 1),
transactionId: "",
transactionType: "1",
requestedPostingDate: null,
companyCode: "",
profitCenter: "",
attachments: [],
comments: "",
transactionLineItems: []
});
}
}}
/>
)}
</FieldArray>;
<button
type="button"
className="btn btn-primary my-1"
onClick={() => moveItems()}
>
Move
</button>;
Maybe the following will give you an idea how to do this:
const Item = React.memo(
//use React.memo to create pure component
function Item({ item, onChange, checked }) {
console.log('rendering:', item.id)
// can you gues why prop={new reference} is not a problem here
// this won't re render if props didn't
// change because it's a pure component
return (
<div>
<div>{item.name}</div>
<input
type="checkbox"
checked={checked}
onChange={() => onChange(item.id, !checked)}
/>
</div>
)
}
)
const SelectedItem = React.memo(
//use React.memo to create pure component
function SelectedItem({ item }) {
console.log('rendering selected:', item.id)
return (
<div>
<div>{item.name}</div>
</div>
)
}
)
class Parent extends React.PureComponent {
state = {
data: [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' }
],
checked: {}
}
toggle = (_id, add) => {
const newChecked = add
? {
...this.state.checked,
[_id]: true
}
: // cannot use Object.fromEntries because SO babel is too old
Object.entries(this.state.checked)
.filter(([key]) => Number(key) !== _id)
.reduce((result, [key, value]) => {
result[key] = value
return result
}, {})
this.setState({ checked: newChecked })
}
render() {
return (
<div>
<div>
<h4>items</h4>
{this.state.data.map(item => (
<Item
item={item}
onChange={this.toggle}
checked={Boolean(this.state.checked[item.id])}
key={item.id}
/>
))}
</div>
<div>
<h4>Selected items</h4>
{this.state.data
.filter(item => this.state.checked[item.id])
.map(item => (
<SelectedItem item={item} key={item.id} />
))}
</div>
</div>
)
}
}
//render app
ReactDOM.render(<Parent />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Related
This is my checkbox components for multi selection.
const MultiselectCheckbox = ({ options, onChange, limitedCount }) => {
const [data, setData] = React.useState(options);
const toggle = index => {
const newData = [...data];
newData.splice(index, 1, {
label: data[index].label,
checked: !data[index].checked
});
setData(newData);
onChange(newData.filter(x => x.checked));
};
return (
<>
{data.map((item, index) => (
<label key={item.label}>
<input
readOnly
type="checkbox"
checked={item.checked || false}
onClick={() => toggle(index)}
/>
{item.label}
</label>
))}
</>
);
};
const options = [{ label: 'Item One' }, { label: 'Item Two' }];
ReactDOM.render(
<MultiselectCheckbox
options={options}
onChange={data => {
console.log(data);
}}
/>,
document.getElementById('root')
);
I want to limit the items I can choose by putting limitedCount in my code.
props for example
limitedSelectCount = 1
Only one check box can be selected
limitedSelectCount = n
Multiple n check boxes available
You can add a condition inside the toggle function.
const handleOptionSelection = (optionKey: string, isChecked: boolean) => {
let selectedOptionKeysCopy = [...selectedOptionKeys];
if (isChecked && selectedOptionKeysCopy.length <= maxSelections) {
selectedOptionKeysCopy = unique([...selectedOptionKeysCopy, optionKey]);
} else {
selectedOptionKeysCopy = selectedOptionKeysCopy.filter(
(selectedOptionKey) => selectedOptionKey !== optionKey
);
}
onChangeSelected(selectedOptionKeysCopy);
};
Here is a sample for reference.
its very easy just put a condition in your toggle function to check if
the length of data array is not greater or equal to the limitedCount. Also
check if the limitedCount prop has been passed to the component or
not.
UPDATE
Also just you need to see if the user has checked the option or unchecked the option, so pass a check into toggle function.
const MultiselectCheckbox = ({ options, onChange, limitedCount }) => {
const [data, setData] = React.useState(options);
const toggle = (check,value) => {
// add below line to code
if(limitedCount && data.length>=limitedCount && check) return;
const newData = [...data];
newData.splice(index, 1, {
label: data[index].label,
checked: !data[index].checked
});
setData(newData);
onChange(newData.filter(x => x.checked));
};
return (
<>
{data.map((item, index) => (
<label key={item.label}>
<input
readOnly
type="checkbox"
checked={item.checked || false}
onClick={(e) => toggle(e.target.checked,index)}
/>
{item.label}
</label>
))}
</>
);
};
const options = [{ label: 'Item One' }, { label: 'Item Two' }];
ReactDOM.render(
<MultiselectCheckbox
options={options}
onChange={data => {
console.log(data);
}}
/>,
document.getElementById('root')
);
I'm displaying different cars and a button to add or remove the selections the user has made. How do I get the buttons to change state individually? As of now, it changes the state of all the buttons to one value.
const cars = [
{ name: "Benz", selected: false },
{ name: "Jeep", selected: false },
{ name: "BMW", selected: false }
];
export default function App() {
const isJeepSelected = true;
const isBenzSelected = true;
return (
<div className="App">
{cars.map((values, index) => (
<div key={index}>
<Item
isBenzSelected={isBenzSelected}
isJeepSelected={isJeepSelected}
{...values}
/>
</div>
))}
</div>
);
}
const Item = ({ name, isBenzSelected, isJeepSelected }) => {
const [toggle, setToggle] = useState(false);
const handleChange = () => {
setToggle(!toggle);
};
if (isBenzSelected) {
cars.find((val) => val.name === "Benz").selected = true;
}
console.log("cars --> ", cars);
console.log("isBenzSelected ", isBenzSelected);
console.log("isJeepSelected ", isJeepSelected);
return (
<>
<span>{name}</span>
<span>
<button onClick={handleChange}>
{!toggle && !isBenzSelected ? "Add" : "Remove"}
</button>
</span>
</>
);
};
I created a working example using Code Sandbox. Could anyone please help?
There's too much hardcoding here. What if you had 300 cars? You'd have to write 300 boolean useState hook calls, and it still wouldn't be dynamic if you had an arbitrary API payload (the usual case).
Try to think about how to generalize your logic rather than hardcoding values like "Benz" and Jeep. Those concepts are too closely-tied to the arbitrary data contents.
cars seems like it should be state since you're mutating it from React.
Here's an alternate approach:
const App = () => {
const [cars, setCars] = React.useState([
{name: "Benz", selected: false},
{name: "Jeep", selected: false},
{name: "BMW", selected: false},
]);
const handleSelect = i => {
setCars(prevCars => prevCars.map((e, j) =>
({...e, selected: i === j ? !e.selected : e.selected})
));
};
return (
<div className="App">
{cars.map((e, i) => (
<div key={e.name}>
<Item {...e} handleSelect={() => handleSelect(i)} />
</div>
))}
</div>
);
};
const Item = ({name, selected, handleSelect}) => (
<React.Fragment>
<span>{name}</span>
<span>
<button onClick={handleSelect}>
{selected ? "Remove" : "Add"}
</button>
</span>
</React.Fragment>
);
ReactDOM.createRoot(document.querySelector("#app"))
.render(<App />);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="app"></div>
Consider generating unique ids for elements rather than using indices or assuming the name is unique. crypto.randomUUID() is a handy way to do this.
The problem is that the map function does not respond to value changes, and therefore does not show the filtered products. I think I messed up with the properties
The filter used to work with type ="radio". After I tried to redo the filter (change type="radio" to ), he stopped working. This is what Filter.jsx looked like before changing to select:
{values.map((n) => (
<label>
<input
className="with-gap"
type="radio"
onChange={() => onChange(n)}
checked={value === n}
/>
<span>{statusMap.get(n)}</span>
</label>
))}
Full React code example
Main.jsx
import React from "react";
import { Products } from "../Products";
import { Filter } from "../Filter";
class Main extends React.Component {
state = {
products: [],
filteredProducts: [],
status: "all",
};
onFilterStatusChange = (status) => {
this.setState({ status });
};
componentDidMount() {
fetch("./products.json")
.then((responce) => responce.json())
.then((data) => this.setState({ products: Object.values(data) }));
}
filterProducts() {
this.setState(({ status }) => ({
filteredProducts:
status === "all"
? this.state.products
: this.state.products.filter((n) => n.prod_status?.includes(status)),
}));
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.status !== prevState.status ||
this.state.products !== prevState.products
) {
this.filterProducts();
}
}
render() {
return (
<main className="container content">
<Filter
values={[
"all",
"recommended",
"promotion",
"saleout",
"bestseller",
"new",
]}
value={this.state.status}
onChange={this.onFilterStatusChange}
/>
<Products products={this.state.filteredProducts} />
</main>
);
}
}
export { Main };
Filter.jsx
import statusMap from "../statusMap";
const Filter = ({ values, value, onChange }) => (
<div className="row filter_container">
<h3 className="filter_title">Sortować według</h3>
<div className="input-field col s12">
<select className="status_select">
{values.map((n) => (
<option onChange={() => onChange(n)} value={value === n} key={n}>
{statusMap.get(n)}
</option>
))}
</select>
</div>
</div>
);
export { Filter };
Please, help me fix this filter
There are a few issues in your code:
The onChange event is triggered on the select element, not on the option element.
value={value === n}, according to your code, value is a string which I assume that represents the default value of the select, and n is the current value inside the map function, meaning that the value property is a boolean, but you need it to be a unique value for each option.
As for the default select value - in React you can use the selected property
I also suggest you to use the index for the key property.
I made some tweaks to your code to try to fix your problem, or at least help you to find it. I can't test it as I don't have the statusMap so its on you.
import React from "react";
class App extends React.Component {
state = {
products: [],
filteredProducts: [],
status: "all",
};
onFilterStatusChange = (status) => {
this.setState({ status });
};
componentDidMount() {
fetch("./products.json")
.then((responce) => responce.json())
.then((data) => this.setState({ products: Object.values(data) }));
}
filterProducts() {
this.setState(({ status }) => ({
filteredProducts:
status === "all"
? this.state.products
: this.state.products.filter((n) => n.prod_status?.includes(status)),
}));
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.status !== prevState.status ||
this.state.products !== prevState.products
) {
this.filterProducts();
}
}
render() {
return (
<main className="container content">
<Filter
values={[
"all",
"recommended",
"promotion",
"saleout",
"bestseller",
"new",
]}
value={this.state.status}
onFilterChange={this.onFilterStatusChange}
/>
<Products products={this.state.filteredProducts} />
</main>
);
}
}
export { App };
const Filter = ({ values, currentValue, onFilterChange }) => (
<div className='row filter_container'>
<h3 className='filter_title'>Sortować według</h3>
<div className='input-field col s12'>
<select
className='status_select'
onChange={(e) => onFilterChange(e.target.value)}
selected={currentValue}
>
{values.map((val, index) => (
<option value={val} key={index}>
{statusMap.get(val)}
</option>
))}
</select>
</div>
</div>
);
It worked with radio inputs because inputs handle directly the onChange event listener, if you want to use a select, you need to move the onChange on the select and use it like this:
<select className="status_select" onChange={(e) => onChange(e.target.value)}>
{values.map((n) => (
<option value={value} key={n}>
{statusMap.get(n)}
</option>
))}
</select>
You can check an example of how to handle a select properly here: demo.
I want to disable the button which i have clicked when i choose an option in my quiz and the rest of the quiz options are enabled ...any ideas on how to do it for these options ? i know we have to use disabled={pass a function} but don't know how to cooperate that with the options
This is my quiz.js:
render() {
const { userAns, options, scores, currentQuest } = this.state;
return (
<div>
<div>
<ProgressBar animated now={this.state.currentQuest * 10} />
</div>{" "}
{this.state.questions}
<br></br> {this.state.scores}
<br></br>
<p style={{ textAlign: "center" }}>Q{this.state.currentQuest}</p>
{this.state.pictures}
<br></br>
{options.map((option, id) => (
<Button
size="lg"
block
key={id}
className={`ui floating message options
${userAns === option ? "selected" : null}
`}
onClick={() => this.checkAns(option)}
>
{option}
</Button>
))}
<div className="hrLine"></div>
<br></br>
<Button onClick={() => this.checkAns()}>CHECK</Button>
{currentQuest < Quizdata.length - 1 && (
<Button
disabled={this.state.disabled}
onClick={() => {
this.nextQuestion();
}}
>
NEXT
</Button>
)}
<br></br>
{currentQuest === Quizdata.length - 1 && (
<Button
onClick={() => {
this.finishQuiz();
}}
>
Finish
</Button>
)}
</div>
);
}
You don't need to pass a function to the disabled attribute, this is a 'boolean` value, Now you have to keep track of the options that you've been clicked.
I'm assuming that you have an array of options so first of all you need to convert that to an object of objects so you can access any option with a unique key:
const options = {
0:{
isSelected: false,
value: 'your value 0',
},
1:{
isSelected: false,
value: 'your value 1',
},
2:{
isSelected: false,
value: 'your value 2',
};
}
This way you are able to track every options and the current state.
With this change your code has to change a bit here, you need to access the option by the key of the object this way options[optionKey].
I've used Object.keysthat creates an array of the keys of the object that you pass it, then you iterate through the array and map the key with the options object here is the docs that refer to this method in case you've never used it:
Object.keys(options).map((optionKey, id) => (
<Button
size="lg"
block
disabled={ options[optionKey].isSelected }
key={optionKey}
className={`ui floating message options
${userAns === options[optionKey] ? "selected" : null}
`}
onClick={() => this.checkAns(options[optionKey])}
>
{options[optionKey].value}
</Button>
))}
import React, { Component } from "react";
import { Quizdata } from "./questions";
//import { FaHorse, FaArrowR } from "react-icons/fa";
import { Button, ProgressBar } from "react-bootstrap";
class Quiz extends Component {
constructor(props) {
super(props);
this.state = {
isMounted: false,
disabled: false,
userAns: null,
options: {},
currentQuest: 0,
scores: 0,
pictures: "",
correct: false
};
}
componentDidMount() {
this.loadQuiz();
// console.log("Quiz1 loaded"); //loads quiz 1 data in
}
componentDidUpdate(prevProps, prevState) {
const { currentQuest } = this.state;
if (this.state.currentQuest !== prevState.currentQuest) {
this.setState({
disabled: true,
questions: Quizdata[currentQuest].question,
options: Quizdata[currentQuest].options,
answer: Quizdata[currentQuest].answer,
pictures: Quizdata[currentQuest].picture
});
}
}
loadQuiz = () => {
const { currentQuest } = this.state;
//console.log("QD", Quizdata);
this.setState(() => {
return {
isMounted: true,
questions: Quizdata[currentQuest].question,
options: Quizdata[currentQuest].options,
answer: Quizdata[currentQuest].answer,
pictures: Quizdata[currentQuest].picture
};
});
// console.log(this.state.answer);
};
nextQuestion = () => {
const { scores, answer, userAns } = this.state;
if (userAns === null) {
return;
}
console.log("scores " + this.state.scores);
this.setState({
currentQuest: this.state.currentQuest + 1
});
};
checkAns = answer => {
//userans and answer switched
let newAnswers = this.state.options;
// console.log("NewAnsw", newAnswers, answer);
Object.keys(newAnswers).map(optionKey => {
newAnswers[optionKey].isSelected = false;
});
newAnswers[answer].isSelected = true;
this.setState({
userAns: newAnswers.value,
// options: newAnswers,
disabled: false
});
console.log("user clicked " + this.state.userAns);
if (this.state.userAns === answer) {
console.log("Correct");
this.setState({
scores: this.state.scores + 1
// correct: false
});
} else {
console.log("wrong");
this.setState({ scores: this.state.scores });
}
};
finishQuiz = () => {
const { scores, userAns, answer } = this.state;
if (this.state.currentQuest === Quizdata.length - 1) {
if (userAns === answer) {
console.log("Correct");
this.setState({
scores: scores + 1
// correct: false
});
} else {
console.log("wrong");
this.setState({ scores: scores });
}
console.log("scores " + this.state.scores);
}
};
render() {
const { userAns, options, scores, currentQuest } = this.state;
// console.log("Opts", options);
if (!this.state.isMounted) {
return null;
}
return (
<div>
<div>
<ProgressBar animated now={this.state.currentQuest * 10} />
</div>{" "}
{this.state.questions}
<br /> {this.state.scores}
<br />
<p style={{ textAlign: "center" }}>Q{this.state.currentQuest}</p>
{this.state.pictures}
<br />
{/* {options.map((option, id) => (
<Button
size="lg"
block
key={id}
className={`ui floating message options
${userAns === option ? "selected" : null}
`}
onClick={() => this.checkAns(option)}
>
{option}
</Button>
))}
*/}
{Object.keys(options).map((optionKey, id) => (
<Button
size="lg"
block
disabled={options[optionKey].isSelected}
key={optionKey}
className={`ui floating message options
${userAns === options[optionKey] ? "selected" : null}
`}
onClick={() => this.checkAns(optionKey)}
>
{options[optionKey].value}
</Button>
))}
<div className="hrLine" />
<br />
<Button onClick={() => this.checkAns()}>CHECK</Button>
{currentQuest < Quizdata.length - 1 && (
<Button
disabled={this.state.disabled}
onClick={() => {
this.nextQuestion();
}}
>
NEXT
</Button>
)}
<br />
{currentQuest === Quizdata.length - 1 && (
<Button
onClick={() => {
this.finishQuiz();
// this.nextQuestion();
// this.pushtoDB();
// this.props.handleDisableValue(scores); // child to parent
}}
>
Finish
</Button>
)}
</div>
);
}
}
export default Quiz;
this is what i worked on i have all working but the user answer cant be used to check if its correct...i saw your updated sandbox i see how u minimized some functions but the score doesnt work either thats the issue im facing now and i want to console the user selected answer when i console i get numbers as its going through the index
I have a bit of an issue that’s causing size and maxArrayElements on all checkboxes selected after the first checkbox to be undefined if the input boxes are untouched. They are all set to default to 1 if not touched.
So in the sandbox, pick a dataschema, selectorField, check one box, just choose the lengthType, and hit submit. The object will come back (in the console) with the default values for size and arrayElements of 1.
Now if I check another box, just choose the lengthType, and hit submit, the size and arrayElements values come back undefined if not touched. They should default to 1. I do have a placeholder value set to 1, so it might be misleading. Specifically, the value prop on the inputs value={this.state.size[lastCheckedFieldName] || 1} handle this by setting the default value to 1 if not changed. But for some reason this isn't happening
This sandbox is reproducing the issue.
import React from "react";
import ReactDOM from "react-dom";
import { Checkbox, CheckboxGroup } from "react-checkbox-group";
import axios from "axios";
import "./styles.css";
const schemas = [{ name: "Phone Data", id: "1" }];
const data = {
data: {
id: "2147483601",
name: "Phone Data",
fields: [
{
name: "Callee #"
},
{
name: "Caller #"
},
{
name: "Duration"
}
]
}
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
schemas: [],
fields: [],
size: {},
lengthType: {},
maxArrayElements: {},
fieldNames: [],
submitDisabled: true
};
this.onDataSchemaChange = this.onDataSchemaChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleCancel = this.handleCancel.bind(this);
}
componentDidMount() {
axios({
method: "get",
url: `/list/of/schemas`
})
.then(response => {
console.log(response);
this.setState({ schemas: schemas });
})
.catch(error => console.log(error.response));
}
onDataSchemaChange = event => {
const schema = this.state.schemas.find(
schema => schema.name === event.target.value
);
if (schema) {
axios({
method: "get",
url: ``
})
.then(response => {
console.log(response);
this.setState({
fields: data.data.fields,
selectedId: data.data.id
});
console.log(this.state.selectedId);
console.log(this.state.fields);
})
.catch(error => console.log(error.response));
}
};
onSizeChange = e => {
e.persist();
const { fieldNames } = this.state;
const lastCheckedFieldName = fieldNames[fieldNames.length - 1];
this.setState(
prevState => {
return {
size: {
...prevState.size,
[lastCheckedFieldName]: e.target.value
}
};
},
() => {
console.log(this.state.size);
}
);
console.log([e.target.name]);
};
onChangeMaxArrayElements = e => {
e.persist();
const { fieldNames } = this.state;
const lastCheckedFieldName = fieldNames[fieldNames.length - 1];
this.setState(
prevState => {
return {
maxArrayElements: {
...prevState.maxArrayElements,
[lastCheckedFieldName]: e.target.value
}
};
},
() => {
console.log(this.state.maxArrayElements);
}
);
console.log([e.target.name]);
};
handleSelectorFieldChange = event => {
this.setState({ selectorField: event.target.value });
};
handleCancel = event => {
event.target.reset();
};
fieldNamesChanged = newFieldNames => {
this.setState({
submitDisabled: !newFieldNames.length,
fieldNames: newFieldNames,
size: {
[newFieldNames]: 1,
...this.state.size
},
maxArrayElements: {
[newFieldNames]: 1,
...this.state.maxArrayElements
}
});
console.log(this.state.size);
console.log(this.state.maxArrayElements);
};
updateSelectorField = e => {
this.setState({ selectorField: e.target.value });
};
updateLengthType = e => {
e.persist();
const { fieldNames } = this.state;
const lastCheckedFieldName = fieldNames[fieldNames.length - 1];
console.log("e", e);
this.setState(prevState => {
const lengthType = { ...prevState.lengthType };
lengthType[lastCheckedFieldName] = e.target.value;
return {
lengthType
};
});
};
handleSubmit = event => {
event.preventDefault();
const fields = this.state.fieldNames.map(fieldName => ({
name: fieldName,
lengthType: this.state.lengthType[fieldName],
size: this.state.size[fieldName],
maxArrayElements: this.state.maxArrayElements[fieldName]
}));
console.log(fields);
};
render() {
const { schemas, fields, fieldNames, selectorField } = this.state;
const lastCheckedFieldName = fieldNames[fieldNames.length - 1];
return (
<div>
<form onSubmit={this.handleSubmit}>
<fieldset>
<legend>
<h2>QuerySchema Information</h2>
</legend>
<div className="info-boxes">
<div>
<label> Pick the dataschema to describe your data file:</label>{" "}
<select
name="schemaName"
value={this.state.value}
onChange={this.onDataSchemaChange}
>
<option value="">Choose Dataschema ...</option>
{schemas &&
schemas.length > 0 &&
schemas.map(schema => {
return <option value={schema.name}>{schema.name}</option>;
})}
</select>
</div>
</div>
</fieldset>
<fieldset>
<legend>
<h2> DataSchema Fields </h2>
</legend>
<div className="selectorField-div">
<div>
<label>Selector Field:</label>{" "}
<select
value={this.state.selectorField}
onChange={this.updateSelectorField}
required
>
<option value="">Pick Selector Field...</option>
{fields &&
fields.map(field => {
return <option value={field.name}>{field.name}</option>;
})}
</select>
</div>
{selectorField && (
<fieldset>
<div>
<legend>Choose field names</legend>
<CheckboxGroup
checkboxDepth={5}
name="fieldNames"
value={this.state.fieldNames}
onChange={this.fieldNamesChanged}
required
>
{fields &&
fields.map(field => {
return (
<li>
<Checkbox value={field.name} />
{field.name}
</li>
);
})}
</CheckboxGroup>
</div>{" "}
</fieldset>
)}
</div>
<div className="input-boxes">
{lastCheckedFieldName && (
<div>
<label>Length Type:</label>
<select
value={this.state.lengthType[lastCheckedFieldName] || ""}
onChange={this.updateLengthType}
required
>
<option value="">Select Length Type...</option>
<option value="fixed">Fixed</option>
<option value="variable">Variable</option>
</select>
</div>
)}
{lastCheckedFieldName && (
<div>
<label>Size:</label>
<input
value={this.state.size[lastCheckedFieldName] || 1}
onChange={this.onSizeChange}
type="number"
name="size"
min="1"
placeholder="1"
required
/>
</div>
)}
{lastCheckedFieldName && (
<div>
<label>MaxArray Elements:</label>
<input
value={
this.state.maxArrayElements[lastCheckedFieldName] || 1
}
onChange={this.onChangeMaxArrayElements}
type="number"
name="maxArrayElements"
placeholder="1"
min="1"
max="100"
required
/>
</div>
)}
</div>
</fieldset>
<div className="btn-group">
<span className="input-group-btn">
<button
className="btnSubmit"
handleSubmit={this.handleSubmit}
type="submit"
disabled={this.state.submitDisabled}
>
Submit{" "}
</button>
<button
className="btnReset"
handleCancel={this.handleCancel}
type="reset"
onClick={() => {
alert("Clearing current field values.");
}}
>
Reset
</button>
</span>
</div>
</form>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I have checked the output of the state at the end of your handleSubmit function, and it looks like this:
lengthType: {
"Callee #": "fixed",
"Caller #": "variable"
},
maxArrayElements: {
"Callee #,Caller #": 1,
"Callee #": 1
}
fieldNames: [
0: "Callee #"
1: "Caller #"
]
The issue here is that, the keys in both lengthType and maxArrayElements are named incorrectly. You are setting these key-value pairs onChange of the CheckboxGroup. The root of the issue is in the parameters passed to fieldNamesChanged function. CheckboxGroup always pass the Array of checked checkboxes, not just the new one. I would suggest to get only the last record from newFieldNames and add it to state.
fieldNamesChanged = newFieldNames => {
this.setState({
submitDisabled: !newFieldNames.length,
fieldNames: newFieldNames,
size: {
[newFieldNames[newFieldNames.length - 1]]: 1,
...this.state.size
},
maxArrayElements: {
[newFieldNames[newFieldNames.length - 1]]: 1,
...this.state.maxArrayElements
}
});
};