I am using React and Formik. I have initial values set.
initialValues={{
Department: "",
Category: "",
}}
Department and Category are material ui menus dependent on each other. If user selects a value from Department then Related categories will get updated.
New we get new initial values from api like this
initialValues={{
Department: "IT",
Category: "Forgot Password",
}}
Values are being set for both menus. but Category is not being filled as its data is being populated on change of Department. How to trigger change so that Categories will get values and i can set the data which i got from api.
Formik code
<Formik
enableReinitialize={true}
initialValues={{
Department: "IT",
Category: "Forgot Password",
}}
innerRef={formRef}
validateOnChange={true}
validateOnBlur={false}
validate={values => { }}
>
{({ values, touched, errors, handleChange, handleBlur, isValid, setFieldValue }) => (
<Form noValidate autoComplete="off" >
<Grid container spacing={3}>
<Grid item lg={4} xs={12}>
<FormControl className={classes.fullWidth} error={Boolean(errors.Department && touched.Department)}>
<InputLabel id="Department">Department</InputLabel>
<Select
name="Department"
labelId="Department"
id="Department"
onChange={(e, value) => {
setFieldValue('Department', value === null ? "" : value.props.value);
setFieldValue('Category', "");
departmentChange(value.props.value);
}}
fullWidth
value={values.Department}
>
{departmentList && departmentList.map((department, index) => {
return (
<MenuItem key={index} value={department.Department}>{department.Department}</MenuItem>
)
})}
</Select>
<FormHelperText className={classes.error}>{(errors.Department && touched.Department) && errors.Department}</FormHelperText>
</FormControl>
</Grid>
<Grid item lg={4} xs={12}>
<FormControl className={classes.fullWidth} error={Boolean(errors.Category && touched.Category)}>
<InputLabel id="Category">Category</InputLabel>
<Select
name="Category"
labelId="Category"
id="Category"
onChange={handleChange}
fullWidth
value={values.Category}
>
{categoryList && categoryList.map((category, index) => {
return (
<MenuItem key={index} value={category.Category}>{category.Category}</MenuItem>
)
})}
</Select>
<FormHelperText className={classes.error}>{(errors.Category && touched.Category) && errors.Category}</FormHelperText>
</FormControl>
</Grid>
<Grid item lg={12} xs={12} align="right">
<div className={classes.wrapper}>
<Button
className={classes.button}
type="submit"
color="primary"
variant="contained"
disabled={showButtonLoader}
>
submit
</Button>
{showButtonLoader && <CircularProgress size={24} className={classes.buttonProgress} />}
</div>
</Grid>
</Grid>
</Form>)}
</Formik>
Related
I am designing a form in react in which I have two categories of dropdown. one is named as "What include" and the other is "What is not include". Now I want that if the user to select any option from the menu of "What Include", then that option(item) will be disabled in the other drop-down named "What not Include".
Here is the code for handle change and UI:
const [personwhatIncludeItems, setPersonwhatIncludeItems] = React.useState(
[]
);
const [personnotIncludeItems, setPersonnotIncludeItems] = React.useState([]);
const handlenotIncludeItemsChange = (event) => {
const {
target: { value },
} = event;
setPersonnotIncludeItems(
// On autofill we get a stringified value.
typeof value === "string" ? value.split(",") : value
);
};
const handlewhatIncludeItemsChange = (event) => {
const {
target: { value },
} = event;
setPersonwhatIncludeItems(
// On autofill we get a stringified value.
typeof value === "string" ? value.split(",") : value
);
};
<div className="col-6 mt-2 mb-2">
<FormControl fullWidth>
<InputLabel id="multiple-include-label">
{" "}
Includes
</InputLabel>
<Select
labelId="whatInclude-multiple-checkbox-label"
id="whatInclude-multiple-checkbox"
multiple
value={personwhatIncludeItems}
onChange={handlewhatIncludeItemsChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.join(", ")}
MenuProps={MenuProps}
>
{whatIncludeArr.map((whatIncludeItems) => (
<MenuItem
key={whatIncludeItems}
value={whatIncludeItems}
>
<Checkbox
checked={
personwhatIncludeItems.indexOf(
whatIncludeItems
) > -1
}
/>
<ListItemText primary={whatIncludeItems} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
<div className="col-6 mt-2 mb-2">
<FormControl fullWidth>
<InputLabel id="multiple-not-include-label">
{" "}
Not Includes
</InputLabel>
<Select
labelId="whatnotInclude-multiple-checkbox-label"
id="whatnotInclude-multiple-checkbox"
multiple
value={personnotIncludeItems}
onChange={handlenotIncludeItemsChange}
input={<OutlinedInput label="Not Include" />}
renderValue={(selected) => selected.join(", ")}
MenuProps={MenuProps}
>
{WhatNotIncludeArr.map((notIncludeItems) => (
<MenuItem
key={notIncludeItems}
value={notIncludeItems}
>
<Checkbox
checked={
personnotIncludeItems.indexOf(notIncludeItems) >
-1
}
/>
<ListItemText primary={notIncludeItems} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
Not sure if I fully understand the logic, but if the goal is to disable the options if selected else where, perhaps consider to add conditional disabled for each mapped option (if the other selected state already has the value, disable the option), perhaps such as:
Minimized demo of below example: stackblitz
Although not tagged as it, the posted code looks like MUI so the example will use MUI components, but otherwise the approach could still work with other libraries provided that a disabled property is supported.
"What Include" select:
<div className="col-6 mt-2 mb-2">
<FormControl fullWidth>
<InputLabel id="multiple-include-label"> Includes</InputLabel>
<Select
labelId="whatInclude-multiple-checkbox-label"
id="whatInclude-multiple-checkbox"
multiple
value={personwhatIncludeItems}
onChange={handlewhatIncludeItemsChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.join(", ")}
MenuProps={MenuProps}
>
{whatIncludeArr.map((whatIncludeItems) => (
<MenuItem
key={whatIncludeItems}
value={whatIncludeItems}
// 👇 Added disable condition here
disabled={personnotIncludeItems.includes(whatIncludeItems)}
>
<Checkbox
checked={personwhatIncludeItems.indexOf(whatIncludeItems) > -1}
// 👇 Added disable condition here
disabled={personnotIncludeItems.includes(whatIncludeItems)}
/>
<ListItemText primary={whatIncludeItems} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
"What is not include" select:
<div className="col-6 mt-2 mb-2">
<FormControl fullWidth>
<InputLabel id="multiple-not-include-label"> Not Includes</InputLabel>
<Select
labelId="whatnotInclude-multiple-checkbox-label"
id="whatnotInclude-multiple-checkbox"
multiple
value={personnotIncludeItems}
onChange={handlenotIncludeItemsChange}
input={<OutlinedInput label="Not Include" />}
renderValue={(selected) => selected.join(", ")}
MenuProps={MenuProps}
>
{WhatNotIncludeArr.map((notIncludeItems) => (
<MenuItem
key={notIncludeItems}
value={notIncludeItems}
// 👇 Added disable condition here
disabled={personwhatIncludeItems.includes(notIncludeItems)}
>
<Checkbox
checked={personnotIncludeItems.indexOf(notIncludeItems) > -1}
// 👇 Added disable condition here
disabled={personwhatIncludeItems.includes(notIncludeItems)}
/>
<ListItemText primary={notIncludeItems} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
I am trying to change the second select dropdown field based on the first select dropdown field, is there any kind of possibility to do this along with the second auto select data store on my database when I post it.
How I do now
I manually select the Order Quantity and Style No. belongs to MON.
How I want to do
I only want that if I select MON, then Order Quantity and Style No. automatically selected.
MUI Select Drop Down code:
Here is the code which I written, please help me out to solve it.
{/* MON */}
<FormControl sx={{ m: 0.5 }} variant="standard">
<InputLabel
style={{ fontSize: "15px" }}
id="demo-customized-select-label"
>
MON
</InputLabel>
<Select
required
style={{
fontSize: "12px",
}}
labelId="demo-customized-select-label"
id="demo-customized-select"
value={plandata.MON}
onChange={(e) => {
setPlanData((prev) => ({
...prev,
MON: e.target.value,
}));
}}
input={<BootstrapInput />}
>
{rawData
?.filter(
(data) =>
data.c_n
.toString()
.includes(plandata.customer.toString()) &&
data.type.includes(plandata.division) &&
data.Item_description.toString().includes(
plandata.styleName.toString()
)
)
.map((value, i) => (
<MenuItem key={i} value={value.mon.toString()}>
{value.mon.toString()}
</MenuItem>
))}
</Select>
</FormControl>
{/* Order Quantity */}
<FormControl sx={{ m: 0.5 }} variant="standard">
<InputLabel
style={{ fontSize: "15px" }}
id="demo-customized-select-label"
>
Order Quantity
</InputLabel>
<Select
required
style={{
fontSize: "12px",
width: "85px",
}}
labelId="demo-customized-select-label"
id="demo-customized-select"
value={plandata.orderQuantity}
onChange={(e) => {
setPlanData((prev) => ({
...prev,
orderQuantity: e.target.value,
}));
}}
input={<BootstrapInput />}
>
{rawData
?.filter(
(data) =>
data.c_n
.toString()
.includes(plandata.customer.toString()) &&
data.type.includes(plandata.division) &&
data.Item_description.toString().includes(
plandata.styleName.toString()
) &&
data.mon.toString().includes(plandata.MON.toString())
)
.map((value, i) => (
<MenuItem key={i} value={value.oq.toString()}>
{value.oq.toString()}
</MenuItem>
))}
</Select>
</FormControl>
{/* Style No */}
<FormControl sx={{ m: 0.5 }} variant="standard">
<InputLabel
style={{ fontSize: "15px" }}
id="demo-customized-select-label"
>
Style No
</InputLabel>
<Select
required
style={{
fontSize: "12px",
width: "85px",
}}
labelId="demo-customized-select-label"
id="demo-customized-select"
value={plandata.finishcode}
onChange={(e) => {
setPlanData((prev) => ({
...prev,
finishcode: e.target.value,
}));
}}
input={<BootstrapInput />}
>
{rawData
?.filter(
(data) =>
data.c_n
.toString()
.includes(plandata.customer.toString()) &&
data.type.includes(plandata.division) &&
data.Item_description.toString().includes(
plandata.styleName.toString()
) &&
data.mon.toString().includes(plandata.MON.toString())
)
.map((value, i) => (
<MenuItem key={i} value={value.style_no.toString()}>
{value.style_no.toString()}
</MenuItem>
))}
</Select>
</FormControl>
Additionally
Moreover, if data is change by other select field then, when I add my data to my Database the changed data should be posted.
getting error in console MUI: children must be passed when using the TextField component with select.
<TextField
select
id="outlined-basic"
label="User Name"
name="user"
size="small"
{...teamForm.getFieldProps("user")}
error={teamForm.touched.user && teamForm.errors.user}
helpertext={teamForm.touched.user && teamForm.errors.user}
>
{list?.map((option) => (
<MenuItem key={option.username} value={option.name}>
{option.name}
</MenuItem>
))}
</TextField>
Adding some other content when no list provided might help for this:
<TextField
select
id="outlined-basic"
label="User Name"
name="user"
size="small"
{...teamForm.getFieldProps("user")}
error={teamForm.touched.user && teamForm.errors.user}
helpertext={teamForm.touched.user && teamForm.errors.user}
>
{list ? list.map((option) => (
<MenuItem key={option.username} value={option.name}>
{option.name}
</MenuItem>
)) : <div></div>}
</TextField>
I have a multi select dropdown input and I am saving all the selected items in an (useState) array when user click add icon.
I want to render input field when "Other" option is selected in dropdown.
and also want that the value entered in other should be added in the array.
handle change :-
const handleCareerChoice = (event) => {
setValues({ ...values, careerChoice: event.target.value });
};
const handleChange = (input) => (event) => {
setValues({ ...values, error: false, [input]:event.target.value});
};
const [otherState, setOtherState] = useState(false);
dropdown
<Grid container className={classes.grid} style={{ marginBottom: "10px" }}>
<Grid item xs={11} sm={5} lg={11} sx={{ m: 1 }}>
<FormControl variant="outlined" fullWidth sx={{ mt: 1 }}>
<InputLabel id="demo-mutiple-checkbox-label">
Top Career Choice
</InputLabel>
<Select
label="Top Career Choice"
id="demo-mutiple-checkbox"
multiple
value={values.careerChoice}
onChange={handleChange("careerChoice")}
renderValue={(selected) => selected.join(", ")}
>
<TextField variant="outlined" style={{ width: "100%" }} />
{careerChoice.map((name) => (
<MenuItem key={name} value={name}>
<Checkbox checked={values.careerChoice.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
<MenuItem >
<Checkbox onClick={setOtherCareerChoice(!otherCareerChoice)} />
<ListItemText primary={"Others"} />
</MenuItem>
</Select>
</FormControl>
</Grid>
{ otherCareerChoice && (
<Grid item xs={11} sm={5} lg={11} sx={{ m: 1 }}>
<FormControl variant="outlined" fullWidth sx={{ mt: 1 }}>
<InputLabel htmlFor="outlined-adornment-password">
Other Career Choice
</InputLabel>
<OutlinedInput
id="careerChoice"
name="careerChoice"
label="Additional Career Choice"
fullWidth
autoComplete="careerChoice"
// value={values.careerChoice}
onChange={handleCareerChoice}
endAdornment={
<InputAdornment position="end">
<IconButton
edge="end"
>
<Add/>
</IconButton>
</InputAdornment>
}
/>
</FormControl>
</Grid>
)}
currently, input is looking like
this but on clicking other text field, I see a blank screen with error
TypeError: selected.join is not a function
Please suggest me a good approach to do this
Here's a codesandbox for the full code
First you want to render the "Other Career Text" input box when it is selected from the dropdown. For that, add an onClick for Others in the dropdown
<MenuItem onClick={() => setOtherCareerChoice(!otherCareerChoice)}>
<Checkbox />
<ListItemText primary={"Others"} />
</MenuItem>
Now that the input field is rendered, at a value and onChange attribute to let the user type a text
<OutlinedInput
value={otherCareerText}
onChange={(event) => setOtherCareerText(event.target.value)}
Finally when the user clicks the "+" button, push this text to your state in an onClick
<IconButton
onClick={() => {
setValues({
...values,
careerChoice: [...values.careerChoice, otherCareerText]
});
setOtherCareerChoice(false);
setOtherCareerText("");
}}
>
I want to update a js object in a parent component from child component which contain a form
the function in my parent component.
getnewDataFirstGroup = (labelValue, typeValue, viewNameValue,todayMeasureValue, seasonLevelValue, numPosInSeasonValue, numSeasonsInYearValue) => {
this.setState({
newDatafirstG: {
label: labelValue,
type: typeValue,
viewName: viewNameValue,
todayMeasure: todayMeasureValue,
seasonLevel: seasonLevelValue,
numPosInSeason: numPosInSeasonValue,
numSeasonsInYear:numSeasonsInYearValue,
chartDefaultLevel:seasonLevelValue
}
})
}
getStepContent(steps) {
switch (steps) {
case 0:
return <FirstGroup folder={this.props.folder} onDataChange={this.getnewDataFirstGroup} />
case 1:
return <SecondGroup folder={this.props.folder} change={this.getnewDataSecondGroup} />;
case 2:
return <PreviewFile content={<ReactJson src={this.state.file} />} />;
default:
throw new Error('Unknown step');
};
}
as u see here i am trying to update newdatafirstG from the component First Group.
code of the first group component :
if (this.state.profileLabel && this.state.season && this.state.viewname && this.state.todayMeasure && this.state.seasonlevel && this.state.numPosSeason && this.state.numPosYear) {
this.props.onDataChange(this.state.profileLabel,this.state.season,this.state.viewname,this.state.todayMeasure,this.state.seasonlevel,this.state.numPosSeason,this.state.numPosYear )
}
}
the render of child component
render() {
const { classes } = this.props;
const vienwnameArray = this.listWorsheetsForm();
const seasonsLevel = this.ListSeasonLevel();
return (
<React.Fragment>
<div>
<Typography variant="h6" gutterBottom>
First Group
</Typography>
</div>
<Grid container spacing={3}>
<Grid item xs={10} sm={11}>
<TextField
required
id="label"
name="profileLabel"
label="Profile Label"
value={this.state.profileLabel}
onChange={this.handleChangeLabel}
fullWidth
autoComplete="given-name"
/>
</Grid>
<Grid item xs={12} sm={6} >
<FormControl required className={classes.formControl} >
<InputLabel id="profileType">Profile Type</InputLabel>
<Select
labelId="Type"
id="profileType"
onClose={this.handleCloseselect}
onOpen={this.handleOpenselect}
value={this.state.season}
onChange={this.handleChangeSeason}
>
<MenuItem value={'Pre-Season'}>Pre-Season</MenuItem>
<MenuItem value={'In-Season'} >In-Season</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl required className={classes.formControl} >
<InputLabel id="viewname">View Name</InputLabel>
<Select
labelId="viewname"
id="vienwname"
onClose={this.handleCloseselect}
onOpen={this.handleOpenselect}
value={this.state.viewname}
onChange={this.handleChangeViewname}
>
{vienwnameArray.map((element, index) => (<MenuItem key={`${index}`} value={element}>{element}</MenuItem>))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl required className={classes.formControl} >
<InputLabel id="measure">Today Measure</InputLabel>
<Select
labelId="measure"
id="measure"
onClose={this.handleCloseselect}
onOpen={this.handleOpenselect}
value={this.state.measure}
onChange={this.handleChangeMeasure}
>
{this.state.measuresArray.map((element, index) => (<MenuItem key={`${index}`} value={element}>{element}</MenuItem>))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl required className={classes.formControl} >
<InputLabel id="season">Season Level</InputLabel>
<Select
labelId="season"
id="seasonlevel"
onClose={this.handleCloseselect}
onOpen={this.handleOpenselect}
value={this.state.seasonlevel}
onChange={this.handleChangeSeasonlevel}
>
{seasonsLevel.map((element, index) => (<MenuItem key={`${index}`} value={element}>{element}</MenuItem>))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl required className={classes.formControl} >
<InputLabel id="numPS">Num Position in Season</InputLabel>
<Select
labelId="numPS"
id="PosSeason"
onClose={this.handleCloseselect}
onOpen={this.handleOpenselect}
value={this.state.numPosSeason}
onChange={this.handleChangePosSeason}
>
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24].map((element, index) => (<MenuItem key={`${index}`} value={element}>{element}</MenuItem>))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl required className={classes.formControl} >
<InputLabel id="numPY">Num Position in Year</InputLabel>
<Select
labelId="numPY"
id="seasonlevel"
onClose={this.handleCloseselect}
onOpen={this.handleOpenselect}
value={this.state.numPosYear}
onChange={this.handleChangePosYear}
>
{[1, 2, 3, 4].map((element, index) => (<MenuItem key={`${index}`} value={element}>{element}</MenuItem>))}
</Select>
</FormControl>
</Grid>
</Grid>
{this.sendFirstGroupData()}
</React.Fragment>
);
};
How can i update my state in the parent component forom form which exist in the child component ?
From my experience, to update the parent component from the child component you would have to create a function in parent updateParent() lets say.
You would then pass this function into the child as a prop.
The child would call this function then: this.props.updateParent(..values)
I hope this helps. If you need more, I can update later with an example!