ReactSelect - closeOnMenuSelect closes the menu on select even when set to false - javascript

I have a react-select component field. I have provided react-select with the following props closeOnMenuSelect={false} && isMulti. Which, theoretically should make the select component not close the menu on selecting an item, but for some reason it does close.
Very weird thing is, everywhere else, I have used that same config for the select component I get it working just fine.
Here is the react-select config:
<Field
name={`${keyField}.${index}.permissions`}
render={({ field: { value, name }, form: { setFieldValue, setFieldTouched } }) => (
<div>
<label htmlFor="namespace-permissions">
Permissions in Namespace <span className="text-danger">*</span>
</label>
<Select
isMulti
closeMenuOnSelect={false}
id="namespace-permissions"
defaultValue={convertNamespaceToDefaultValue(
dependencies.namespacePermissions,
value
)}
options={convertNamespaceToSelect(dependencies.namespacePermissions)}
onChangeCallback={values => {
setFieldValue(name, convertSelectToNamespacesData(values));
setFieldTouched(name, true);
}}
/>
<ErrorMessage name={name} component={FormErrorMessage} />
</div>
)}
/>
Why is it NOT working? And why is the exact same config on another react-select works perfectly without a hitch?
I have update the Description, to show that the react-select is wrapped in a Formik Field. As I said, this is a technique I have used in other parts of my code, but this one, isn't working.

Related

React-hook-form working with multiple array data and conditional fields within a map array

I'm lost in the weeds on this, but I think the issues are straightforward enough, and its just my lack of understanding as to why I cant get this working right. I have a form using react-hook-form that is part of a scheduling/ documentation feature. The initial data is pulled from 1 api endpoint which sets the initial info in the parent level of the form- the standard date/time info and the subsequent conditional goal info if the event has already been interacted with- as an 'event' prop. For the child component within the form (GoalInput), the goal titles are pulled from a separate api endpoint to ensure the available goal fields match the current report. Since the first time a user will interact with any given event, the goal fields should be un-toggled and have no associated user information, however, if they are returning to an event previously interacted with, I want the previously set information (contained in the event initial data mentioned earlier) displayed as the default.
Heres the parent form
/.../
const { register, unregister, handleSubmit, watch, control, setValue, formState: { errors } } = useForm({
defaultValues: {
visitStart: event?.visitStart,
visitEnd: event?.visitEnd,
location: event?.location,
goals: [{
title: '',
marked: false,
note: ''
}]
},
shouldUnregister: true
});
const onSubmit= async (data) => {
/.../
}
return (
<div>
<Button color='primary' variant='contained' onClick={handleClickOpen}>
Edit Visit
</Button>
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Edit Visit</DialogTitle>
<DialogContent>
<DialogContentText>
Visit for {event.client.fullName}
</DialogContentText>
<form id="editVisit"
onSubmit={(e) =>
handleSubmit(onSubmit, onError)(e).catch((e) => {
console.log("e", e);
})}>
<br></br>
<section>
/... initial fields .../
</section>
{goals && goals.map((goal, index) => (
<GoalInput
key={goal._id}
goal={goal}
index={index}
register={register}
control={control}
errors={errors}
visitGoals={event.goals}
setValue={setValue}
unregister={unregister}
/>
))}
/... end of form/ action buttons .../
And the child component:
function GoalInput({ goal, index, register, unregister, setValue, control, errors, visitGoals }) {
const [toggle, setToggle] = useState(false)
console.log("goal: ", goal)
console.log("visitGoals: ", visitGoals)
const goalData = visitGoals?.filter((value)=> {
if ( value.marked === true) {
return value
}
})
console.log("goalData: ", goalData)
useEffect(() => {
if(!toggle) {
unregister(`goals.${index}.title`)
unregister(`goals.${index}.marked`)
unregister(`goals.${index}.note`)
}
}, [unregister, toggle])
return (
<>
<FormControlLabel
{...register(`goals.${index}.title`, goal.title)}
value={goal.title}
name={`goals.${index}.title`}
control={
<Switch
key={index}
{...register(`goals.${index}.marked`)}
checked={goalData.marked || toggle}
// checked={toggle}
name={`goals.${index}.marked`}
value={goalData.marked || toggle}
onClick={console.log("marked? ", goalData.marked, "toggle ", toggle)}
// value={toggle}
onChange={
() => {
setToggle(!toggle);
setValue(`goals.${index}.title`, goal.title)
}}
/>
}
label={goal.title}
/>
<br />
{toggle ? (
<>
<Controller
control={control}
name={`goals.${index}.note`}
id={`goals.${index}.note`}
render={({field}) => (
<TextField
index={index}
error={!!errors.note}
value={goalData.note || field.value}
// value={field.value}
onChange={(e)=>field.onChange(e)}
label="Progress Note"
/>
)}
/>
<br />
</>
) : <></>}
</>
)
}
The visitGoals prop is passing down the event information if it already contains existing goals. Currently the log is showing that the component is correctly filtering out if the goals had been marked: true previously, however, the actual Switch component is not registering the goalData value. I tried setting it as state and having a useEffect set the state, but I was getting just an empty array. I'm sure theres something simple I'm missing to get the input fields to recognize the values, but I cant figure it.
As an extra question if I may, I'd also like to unregister any fields if the Switch input is not toggled, so that its false, so that I'm not storing a bunch of empty objects. Following the docs and video, I thought I've set it up correctly, even trying shouldUnregister: true in the parent form, but I can't seem to navigate that either. The submission data shows the fields are being registered fine by RHF, so I figured the unregister by the same syntax should have worked.
React Hook Form's unregister docs: https://react-hook-form.com/api/useform/unregister
Any direction or guidance would be greatly appreciated.

How to auto tab between Formik Field?

I have a component for 4 digit code of phone validation. By itself it works fine and looks good as well. The only issue I am facing - I can't autotab between numbers. I have to go to each input manually and write the number. Is it possible to do with Formik Field?
This is my piece of code:
<Formik
onSubmit={values =>
VerifyGarageFunc({ code: values.code.join(''), requestId: PhoneCodeData.data }, data.showModal)
}>
{({ values, handleChange, handleSubmit }) => (
<form onSubmit={handleSubmit}>
<FieldArray
name="code"
render={arrayHelpers => (
<div className={styles.inputWrapper}>
{values.code.map((item, index) => (
<div key={index}>
<Field
name={`code.${index}`}
type="text"
component={CustomInput}
onChange={handleChange}
value={values.code[index]}
/>
</div>
))}
</div>
)}
/>
<LoginActionButton onSubmit={handleSubmit} text={'Send'} />
<FieldArray />
</form>
)}
</Formik>
I tried https://www.npmjs.com/package/react-auto-tab but it works only with <input/>, for some reason it doesn't work at all with Formik Field.
P.S. I am using Next.js with React.js
You'll likely have more luck with a hook based solution. Install https://github.com/Romr1ch/react-pin-input-hook, which just does the logic without being opinionated about display.
Create a new component called PinInput and create a new field using the formik hook primitives.
Ive setup an example codesandbox: https://codesandbox.io/s/react-pin-input-hook-custom-input-1ze5dv?file=/src/App.js, but note this doesn't use your exact components as I don't have them. The below code should match closer your exact case.
import React from 'react'
import { useField } from 'formik'
import { usePinInput } from 'react-pin-input-hook'
export const PinInput = (props) => {
const [field, meta, helpers] = useField(props)
const { fields } = usePinInput({
values: field.value,
onChange: (values) => {
helpers.setValue(values)
},
})
return fields.map((fieldProps, index) =>
<CustomInput key={index} type="text" {...fieldProps} />
)
}
Then in your main file do this (by the way if you use Form component from Formik you dont need to do any of the onSubmit binding yourself, so I changed that along the way -- the button can just be "submit" type):
<Formik
onSubmit={values =>
VerifyGarageFunc({ code: values.code.join(''), requestId: PhoneCodeData.data }, data.showModal)
}>
<Form>
<PinInput name="code" />
<LoginActionButton type="submit" text={'Send'} />
</Form>
</Formik>
Note that this lib requires your CustomComponent to attach a ref to the underlying thing that needs focusing so you'll need to use forwardRef on that component and attach it to the underlying input. It also needs to support onBlur, onFocus, onChange and onKeyDown.

Empty Material-UI textfield after submitting the form

How can I clear value from the TextField after submitting the form? All of the components in the code are functional components, not the class ones. Here is one of the TextFields, the others are similar to this one. I can make the type='search' as in the code bellow but then a user needs to press a button to clear the value and even then the error check is complaining about the field being empty.
Would it be better to try and refresh the component? This form is in a sidebar in my app.
<form onSubmit={onSubmitHandler} className={classes.root}>
<TextField
name='firstName'
inputRef={register({
required: "Please enter first name",
validate: value => isEmpty(value)
})}
label={translate('invitation.first_name')}
error={!!errors.firstName}
type='search'
autoFocus
fullWidth
/>
There is a value property that you have to pass to the TextField component. check example below:
class SomeComponent extends Component {
state = {value: ''}
resetValue = () => {
this.setState({value: ''});
}
render() {
return (
<div>
<TextField
...
value={this.state.value}
/>
<button onClick={this.resetValue}>Reset</button>
</div>
)
}
}

Running two functions on onIonChange in Ionic4 React

I have been using react hooks form but have come in situation where i need to set the state and also call onChange method to get rid of error for which i have made a validation. Here is my code
<Controller
render={({ onChange, onBlur, value }) => (
<IonSelect
placeholder="Select a State"
onIonChange={onChange}
onIonChange={(e:any)=>{
handleChange(
"selectedStateForBilling",
String(e.detail.value)
);
}}
>
{state.states.map((item) => (
<IonSelectOption value={item} key={item}>
{item}
</IonSelectOption>
))}
</IonSelect>
)}
control={control}
name="billingState"
defaultValue=""
rules={{
required: true,
}}
/>
So looking at this code you may see i want to actually run two onIonChange method one for updating a state variable and the other to update the "billingState" so that i could get rid of error required:true (which is defined in my rules={{}}) is also required to throw error as for the first if users clicks on submit leaving this value empty he sees it. So is there a way i can run onChange and handleChange both in onIonChange method?
I don't use ionic but can't you just write it like this?
onIonChange={(e: any) => {
onChange();
handleChange(
"selectedStateForBilling",
String(e.detail.value)
);
}}

Unexpected behavior with material ui Select and 'redux-form'

I have a simple 'redux form' with a Select component from newest material-ui-next.
import { TextField } from 'material-ui';
<Field
name="name"
component={TextField}
select
>
<MenuItem value={1}>Lily</MenuItem>
<MenuItem value={2}>Mark</MenuItem>
</Field>
Works fine. Hovewer, if I change the value prop from typeof number to string, e.g.
<Field
name="name"
component={TextField}
select
>
<MenuItem value="lily">Lily</MenuItem>
<MenuItem value="mark">Mark</MenuItem>
</Field>
the value changes properly, but just after one second, the value becomes 0 (as it was initially), and the selected value disappears (it's empty from now on). It had a correct value just for a moment, but somehow it's being automatically set back to 0.
Even tried with rendering the field:
const renderSelectField = ({ input, label, meta: { touched, error }, children, ...custom }) => (
<TextField
{...input}
select
onChange={(event, index, value) => input.onChange(event.target.value)}
children={children}
{...custom}
/>
)
Still, it changes the value, and just after that it returns to 0. If I console.log the form values, it shows up (after manually changing the value):
{ name: "Lily" }
{ name: 0 }
{ name: 0 }
(it happens in period of one second)
Looking forward for any help. Thank you.
Edit: This is what happens in redux dev tools, when choosing an item with string value - in this case pln.
Based on this react-select issue and this redux-form issue it seems like you need to override the default onBlur event.

Categories

Resources