Reset values in react hook forms with fields loaded in map - reactjs

So i have a form that has dropdowns for companies and as many companies they are i want the values to be loaded in there. I know how to do it if its not in a map.
customerCompanyList.map(cList => {
return (
<Controller
name={`customerCompany-${cList.id}`}
control={control}
render={({ field }) => (
<FormControl
variant="outlined"
className="mt-16"
>
<InputLabel id="customerCompany-type-label">
Customer Company
</InputLabel>
<Select
labelId="customerCompany-type-label"
id="customerCompany"
label="Customer Company"
{...field}
fullWidth
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{companyList.map(item => {
return (
<MenuItem key={item.id} value={item.id}>
{item.name}
</MenuItem>
);
})}
</Select>
{errors?.type?.customerCompany && (
<FormHelperText>
{errors.type.customerCompany}
</FormHelperText>
)}
</FormControl>
)}
/>
);
})
What im stuck is how do i reset the values
im using useEffect to reset the values for the ones that are not in a map. but this one i cant figure out
reset({
isCustomer: customerCompanies.length > 0,
isResource: resourceCompanies.length > 0,
isStaff: roles.length > 0,
staffRoles: roles.length > 0 ? roles : null
});

Related

MUI: You have provided an out-of-range value `18:00` for the select component

I use react with Mui;
<Select
disabled={disable}
renderValue={(value) => renderValue(value as number)}
size="small"
value={object.time}
onChange={({ target }) => onChange(target.value as string)}
>
{hours.map((hour) => (
<MenuItem key={hour.id} value={hour.val1}>
<ListItemText title={hour.time} primary={hour.time} />
</MenuItem>
))}
</Select>
I tried using many solutions like add defaultValue="" or stringify the value but none helped

stopPropogation not working consistently in React

I am working with 2 dropdown menus using stopPropogation to prevent the menu shifting up and down when items are checked and unchecked.
One menu works great but the other is still jumping up and down when checking and unchecking items, although I am confident that I'm using stopPropogation in the same way for both instances. I am wondering what I am doing wrong in the faulty dropdown menu that's causing this issue.
Working dropdown menu:
return (
<div onClick={(e) => {
e.stopPropagation();
}}>
<FormControl
variant="outlined"
size="small"
className={classes.formControl}
>
<InputLabel id="demo-mutiple-checkbox-label" align="left" margin="dense">
Select Models
</InputLabel>
<Select
multiple
labelId="demo-mutiple-checkbox-label"
label="SelectModels"
value={modelIds}
onChange={handleChange}
renderValue={(selected) =>
selected
.map(
(id) =>
deviceModelData.find((model) => model.alg_id === id).alg_name
)
.join(', ')
}
MenuProps={MenuProps}
className={classes.rootSelect}
>
{deviceModelData.map((model, index) => (
<MenuItem key={model.alg_id} value={model.alg_id}>
<Checkbox checked={modelIds.includes(model.alg_id)} />
<ListItemText primary={model.alg_name} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
Problematic dropdown menu:
return (
<div
onClick={(e) => {
e.stopPropagation();
}}
>
<FormControl
variant="outlined"
size="small"
className={classes.formControl}
>
<InputLabel id="demo-mutiple-checkbox-label">Select Classes</InputLabel>
<Select
labelId="demo-mutiple-checkbox-label"
label={label}
id="demo-mutiple-checkbox"
multiple
value={classIds}
onChange={handleClassIdsChange}
renderValue={(selected) =>
selected
.map((id) => marketplaceModelClasses[id].original_label)
.join(', ')
}
MenuProps={MenuProps}
>
{allClassIds.map((classId) => {
return (
<MenuItem key={classId} value={classId}>
<Checkbox
value={classId}
checked={classIds.indexOf(classId) > -1}
/>
<ListItemText
primary={marketplaceModelClasses[classId].original_label}
/>
</MenuItem>
);
})}
</Select>
</FormControl>
</div>
);
}

Controller does not working for MUI Select and React Hook Form. TypeError: props.render is not a function

I have parent and child components. In the child component, I have a 'select' and 'textfield'. I need to configure validation for this select - "Required". Textfield works, but select does not. I could not do it and searched to solve this and saw "Controller". But when I send control (useForm) as a prop to my child component, the app does not work and my error is TypeError: props.render is not a function
Parent component:
const { register, handleSubmit, control, formState: { errors }} = useForm();
<AddProductInfo register={register} control={control} errors={errors} />
Child component:
<FormControl fullWidth>
<Typography variant={"span"} className={styles.select}>
Category
</Typography>
<Controller
as={
<Select
value={addProductData.category}
onChange={handleChange}
// {...register("category", {
// required: "Choose one of them",
// })}
// error={Boolean(errors.category)}
>
{categoriesData.map((data, key) => (
<MenuItem key={key} value={data.id}>
{data.name.az}
</MenuItem>
))}
</Select>
}
name={"category"}
control={control}
></Controller>
<FormHelperText error variant="filled">
{errors.category?.message}
</FormHelperText>
</FormControl>
I solved. The right code
from
<Controller as={
<Select>
</Select>
}
/>
to
<Controller render={({ field }) => (
<Select {...field}>
</Select>
)}
/>
Like this
<Controller
render={({ field }) => (
<Select
{...field}
>
{categoriesData.map((data, key) => (
<MenuItem key={key} value={data.id}>
{data.name.az}
</MenuItem>
))}
</Select>
)}
name={"category"}
control={control}
></Controller>

Material UI select and autocomplete box not lined up

Screenshot of misaligned drop-down boxes
Hi! I'm a beginner ReactJS engineer. I added 2 drop-down boxes from material UI, the left box is the Autocomplete from materialui/labs and the right box is the Select from materialui/core. They're both placed in the same component with the same styling applied to it, but the Autocomplete is slightly off. Is there a simple fix to this misalignment?
<AutocompleteComponent
formStyle={{ width: 200 }}
label={'Build'}
options={builds}
value={selectedBuild}
handleChange={handleFilterSelectChange('selectedBuild')} />
<SelectComponent
formStyle={{ width: 120 }}
label={'Sheet Layout'}
options={sheetLayouts}
value={selectedSheetLayout}
handleChange={handleFilterSelectChange('selectedSheetLayout')} />
For select component:
const SelectComponent = props => {
return (
<FormControl
className={className}
required={required}
error={error}
margin={margin}
style={formStyle}
>
<InputLabel>{label}</InputLabel>
<Select
inputRef={inputRef}
value={value}
style={style}
onChange={handleChange}
disabled={disabled}
onClick={onClick}
onFocus={onFocus}
onBlur={onBlur}
>
{excludeNone ? null : (
<MenuItem value="">
<em>{noneLabel ? noneLabel : "None"}</em>
</MenuItem>
)}
{optionsExist(options)}
</Select>
{helperText ? <FormHelperText>{helperText}</FormHelperText> : null}
</FormControl>
);
};
For the autocomplete component:
class AutocompleteComponent extends React.Component {
render() {
return (
<FormControl
className={className}
required={required}
error={error}
margin={margin}
style={formStyle}
>
<Autocomplete
style={style}
disabled={disabled}
onClick={onClick}
onFocus={onFocus}
onBlur={onBlur}
options={options}
getOptionLabel= {option => option.label && option.label.toString()}
id="auto-complete"
autoComplete
includeInputInList
renderInput={params => (
<TextField
{...params}
label="Builds"
margin="normal"
fullWidth
position="center"
/>
)}
renderOption={(option, { inputValue }) => {
const matches = match(option.label, inputValue);
const parts = parse(option.label, matches);
return (
<div>
{parts.map((part, index) => (
<span
key={index}
style={{ fontWeight: part.highlight ? 700 : 400 }}
>
{part.text}
</span>
))}
</div>
);
}}
/>
{helperText ? <FormHelperText>{helperText}</FormHelperText> : null}
</FormControl>
);
}
}
Thanks!

How to show an inputlabel/placeholder/label permanently?

I'm using the multi-select with checkboxes from material ui v4. The provided default settings display an array of 'SELECTED' values. renderValue={selected => selected.join(', ')}. However, I would like to remove this function and only display a permanent label. It seems that the display value is being tied to the value of the component itself. Does anybody knows how to work around this?
<FormControl className={classes.formControl}>
<InputLabel htmlFor="select-multiple-checkbox">Tag</InputLabel>
<Select
multiple
value={personName}
onChange={handleChange}
input={<Input id="select-multiple-checkbox" />}
renderValue={selected => selected.join(', ')}
MenuProps={MenuProps}
>
{names.map(name => (
<MenuItem key={name} value={name}>
<Checkbox checked={personName.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
</FormControl>
Are you saying that you don't want any indication of what the selected values are?
If so, below is one way of doing that:
<FormControl className={classes.formControl}>
<InputLabel shrink={false} htmlFor="select-multiple-checkbox">
Tag
</InputLabel>
<Select
multiple
value={personName}
onChange={handleChange}
input={<Input id="select-multiple-checkbox" />}
renderValue={() => (
<span dangerouslySetInnerHTML={{ __html: "​" }} />
)}
MenuProps={MenuProps}
>
{names.map(name => (
<MenuItem key={name} value={name}>
<Checkbox checked={personName.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
</FormControl>
<InputLabel shrink={false}
This prevents the label from shrinking and moving up when the Select is focused.
renderValue={() => (<span dangerouslySetInnerHTML={{ __html: "​" }} />)}
This causes a zero-width space to be rendered as the "selected values". This ensures that the height doesn't collapse (which is what happens if you just return empty string) while still allowing the label to be displayed.

Resources