Closed Shaker-Hamdi closed 4 years ago
Perhaps the reason could be formik
expecting onChange(event)
instead of onChange(value)
.
See if something like onChange={value => field.onChange({ target: { value } })}
would work.
It actually now gives me this warning in the console ...
He's confused on which value to update. And as you can see I did provide a "name" and the name shows in the inspector!
Well, then it requires a properly constructed event it seems.
Somehow it can't figure out that field.onChange
is for field
.
You can experiment with constructing a synthetic React event of some sort.
This is an advanced topic I guess.
Or maybe not, maybe it's something else.
I didn't use formik
.
When I do it like this the warnings go away, but still can't seem to detect that the field has a value and thus won't activate the "submit" button ...
<PhoneInput
placeholder="Enter phone number"
name={field.name}
value={field.value}
onChange={value => field.onChange({ value })}
onBlur={value => field.onBlur({ value })}
/>
You'll have to ask formik
experts then.
OK, thank you for your effort, I'll try to post this on StackOverflow, and maybe someone who faced this before can give his insight.
There has also been a previous thread on Formik: https://github.com/catamphetamine/react-phone-number-input/issues/159#issuecomment-455710810 Maybe you could find something there.
If it helps, here is my phoneinput/formik control
import React, { useState } from 'react';
import PhoneInput from 'react-phone-number-input';
import PropTypes from 'prop-types';
import 'react-phone-number-input/style.css';
import { getIn } from 'formik';
const PhoneInputField = (props) => {
const {
className,
field: { name, value },
form: {
errors, handleBlur, setFieldValue, touched,
},
form,
label,
country,
onChange,
disabled,
} = props;
const [isFocused, setFocused] = useState(false);
const isError = getIn(touched, name) && getIn(errors, name);
const errorStyle = isError ? 'error' : '';
const filledStyle = (isFocused || value) ? 'filled' : '';
const disabledStyle = disabled ? 'disabled' : '';
const handleInputBlur = (e) => {
setFocused(false);
handleBlur(e);
};
const handleInputFocus = () => setFocused(true);
const onValueChange = (phoneNumber) => {
setFieldValue(name, phoneNumber);
if (onChange !== null) {
onChange(phoneNumber);
}
};
return (
<div className={`${className} ${errorStyle} ${filledStyle} ${disabledStyle} text-input-group`}>
<PhoneInput
placeholder="Enter phone number"
name={name}
value={value}
onChange={onValueChange}
country={country}
/>
<label className="transition ml-10" htmlFor={name}>
{label}
</label>
<div className="flex h-5 items-end text-red-100 text-xs">
{isError && getIn(errors, name)}
</div>
</div>
);
};
PhoneInputField.propTypes = {
className: PropTypes.string,
form: PropTypes.any.isRequired,
field: PropTypes.any.isRequired,
onChange: PropTypes.func,
label: PropTypes.string,
country: PropTypes.string,
disabled: PropTypes.bool,
};
PhoneInputField.defaultProps = {
className: '',
label: '',
onChange: null,
country: 'AU',
disabled: false,
};
export default PhoneInputField;
@AndrewStratigos That did actually work, Thanks a lot man. The trick in your code was this part ...
const onValueChange = phoneNumber => {
setFieldValue(name, phoneNumber);
if (onChange !== null) {
onChange(phoneNumber);
}
};
Again, thanks a bunch 👍
@shaker-hamdi. I'm still struggling to make this work for me. Can you take a look at my sandbox and see?
I may be late to the party but for anyone else here having issues with their onChange handler, remember this also comes with a curried option, in a regular web input formik can take the name attribute from the target it receives in the change handler, React-native generally doesn't provide a synthetic event (it does but its different) most people tend to use the onChangeText
property instead so formik needs other queues to know how to update the form's state, consider the following:
instead of calling the change (or blur) handlers like we do on web: onChange={formik.handleChange}
you call it with the attribute name: onChange={formik.handleChange('phoneNumber')}
this also works for the blur handler onBlur={formik.handleBlur('phoneNumber')}
also make sure you send the change values as string or formik won't accept it, it sometimes is a pain in the ass to work forms on RN
@jdmg94 So what does the ultimate Formik component look like then?
Where does formik.handleChange
go in this code?
import React, { useCallback } from 'react'
import PropTypes from 'prop-types'
import PhoneInput from 'react-phone-number-input`
function FormikPhoneInput(ref, { name, onChange, formik, ...rest }) {
const onChange_ = useCallback(value => onChange(value || ''), [onChange])
return (
<PhoneInput
{...rest}
ref={ref}
name={name}
onChange={onChange_}/>
)
}
FormikPhoneInput = React.forwardRef(FormikPhoneInput)
FormikPhoneInput.propTypes = {
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
formik: PropTypes.shape({
handleChange: PropTypes.func.isRequired,
handleBlur: PropTypes.func.isRequired
}).isRequired
}
export default FormikPhoneInput
Also, in v3.x of this library, onBlur
no longer sets event.target.value
, so I removed onBlur
from this code.
If you think it's still required then you could add it.
@jdmg94 So what does the ultimate Formik component look like then? Where does
formik.handleChange
go in this code?import React, { useCallback } from 'react' import PropTypes from 'prop-types' import PhoneInput from 'react-phone-number-input` function FormikPhoneInput(ref, { name, onChange, formik, ...rest }) { const onChange_ = useCallback(value => onChange(value || ''), [onChange]) return ( <PhoneInput {...rest} ref={ref} name={name} onChange={onChange_}/> ) } FormikPhoneInput = React.forwardRef(FormikPhoneInput) FormikPhoneInput.propTypes = { name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, formik: PropTypes.shape({ handleChange: PropTypes.func.isRequired, handleBlur: PropTypes.func.isRequired }).isRequired } export default FormikPhoneInput
Also, in v3.x of this library,
onBlur
no longer setsevent.target.value
, so I removedonBlur
from this code. If you think it's still required then you could add it.
remove onChange_
and just call in your jsx onChange={formik.handleChange(name)}
same with onBlur if you need validation on blur
@jdmg94 Ok. So, Formik users, if @jdmg94 's solution works for you then post your code.
@catamphetamine please find a working implementation for future reference. https://codesandbox.io/s/formik-react-phone-number-input-p5jvs
I have modified @AndrewStratigos 's version. This version works right with Formik's onBlur, allowing you to validate the field on blur.
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import PhoneInput from 'react-phone-input-2';
import block from 'bem-css-modules';
import classNames from 'classnames';
import { createRandomIdentificator } from '../../../helpers/commonHelpers';
import styles from './styles.module.scss';
const b = block(styles);
export default function MaskedInput(props) {
const {
handleChange,
handleBlur,
className,
type,
placeholder,
name,
...restProps
} = props;
const inputClassPostfix = createRandomIdentificator();
useEffect(() => {
document.querySelector(`.phone-input-${inputClassPostfix}`).setAttribute('name', name);
});
const onValueChange = (phoneNumber, country, e) => {
handleChange(e);
};
return (
<PhoneInput
{...restProps}
country="ru"
preferredCountries={['ru']}
value={null}
placeholder={placeholder}
containerClass={b('container')}
inputClass={classNames(b('input'), `phone-input-${inputClassPostfix}`)}
buttonClass={b('button')}
onChange={onValueChange}
onBlur={handleBlur}
name={name}
/>
);
}
MaskedInput.defaultProps = {
type: 'text',
placeholder: '',
name: '',
className: '',
};
MaskedInput.propTypes = {
name: PropTypes.string,
placeholder: PropTypes.string,
type: PropTypes.string,
className: PropTypes.string,
handleBlur: PropTypes.func.isRequired,
handleChange: PropTypes.func.isRequired,
};
@boriswinner Ok, what are the main issues when using this library with formik
"out of the box"?
Perhaps we could add a section in the readme on using this library with formik
or other libraries.
@boriswinner
Formik emits a
name
attribute, which has to be passed to the element. When trying to use your component, Formik logs:
name
is passed through so it's not a issue of this library
The right solution will be to add a 'name' prop to the component which will correspond to the name attribute in HTML element.
That's how it currently is.
onChange
emits the event as the third parameter. We need to write a wrapper that calls Formik's handleChange with the event as the parameter.
What? Not clear what you meant there.
In case if anyone needs help this is my current implementation. Below approach works with both onChange and onBlur events and doesn't throw error when string is given in field (disabled). Thanks to above replies:
import "react-phone-number-input/style.css";
import PhoneInput from "react-phone-number-input";
const initialValues = {
phoneNumber: "",
};
const validate = (values) => {
let errors = {};
if (!values.phoneNumber) {
errors.phoneNumber = "⋆Required";
}
return errors;
};
const onSubmit = (values, onSubmitProps) => {....}
const formik = useFormik({
initialValues,
onSubmit,
validate,
});
<PhoneInput
className='anonymous'
placeholder='Phone Number'
name='phoneNumber'
value={formik.values.phoneNumber}
onChange={e => formik.setFieldValue("phoneNumber", e)}
onBlur={formik.handleBlur("phoneNumber")}
/>
{formik.touched.phoneNumber && formik.errors.phoneNumber ? (
<div
className='text-danger text-right'
style={{ marginBottom: "-13px", fontSize: "12px" }}
>
{formik.errors.phoneNumber}
</div>
) : null}
This works fine for me, "react-hook-form": "^7.7.0"
<Controller
name="contact_number"
control={control}
rules={{ required: true }}
render={({ field }) => (
<PhoneInput
{...field}
country="us"
/>
)}
/>
@ackalhan I've updated the README with a react-hook-form
section.
https://github.com/catamphetamine/react-phone-number-input#react-hook-form
@jdmg94 So what does the ultimate Formik component look like then? Where does
formik.handleChange
go in this code?import React, { useCallback } from 'react' import PropTypes from 'prop-types' import PhoneInput from 'react-phone-number-input` function FormikPhoneInput(ref, { name, onChange, formik, ...rest }) { const onChange_ = useCallback(value => onChange(value || ''), [onChange]) return ( <PhoneInput {...rest} ref={ref} name={name} onChange={onChange_}/> ) } FormikPhoneInput = React.forwardRef(FormikPhoneInput) FormikPhoneInput.propTypes = { name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, formik: PropTypes.shape({ handleChange: PropTypes.func.isRequired, handleBlur: PropTypes.func.isRequired }).isRequired } export default FormikPhoneInput
Also, in v3.x of this library,
onBlur
no longer setsevent.target.value
, so I removedonBlur
from this code. If you think it's still required then you could add it.
What do we need to pass in onChange
prop?
If it helps, here is my phoneinput/formik control
import React, { useState } from 'react'; import PhoneInput from 'react-phone-number-input'; import PropTypes from 'prop-types'; import 'react-phone-number-input/style.css'; import { getIn } from 'formik'; const PhoneInputField = (props) => { const { className, field: { name, value }, form: { errors, handleBlur, setFieldValue, touched, }, form, label, country, onChange, disabled, } = props; const [isFocused, setFocused] = useState(false); const isError = getIn(touched, name) && getIn(errors, name); const errorStyle = isError ? 'error' : ''; const filledStyle = (isFocused || value) ? 'filled' : ''; const disabledStyle = disabled ? 'disabled' : ''; const handleInputBlur = (e) => { setFocused(false); handleBlur(e); }; const handleInputFocus = () => setFocused(true); const onValueChange = (phoneNumber) => { setFieldValue(name, phoneNumber); if (onChange !== null) { onChange(phoneNumber); } }; return ( <div className={`${className} ${errorStyle} ${filledStyle} ${disabledStyle} text-input-group`}> <PhoneInput placeholder="Enter phone number" name={name} value={value} onChange={onValueChange} country={country} /> <label className="transition ml-10" htmlFor={name}> {label} </label> <div className="flex h-5 items-end text-red-100 text-xs"> {isError && getIn(errors, name)} </div> </div> ); }; PhoneInputField.propTypes = { className: PropTypes.string, form: PropTypes.any.isRequired, field: PropTypes.any.isRequired, onChange: PropTypes.func, label: PropTypes.string, country: PropTypes.string, disabled: PropTypes.bool, }; PhoneInputField.defaultProps = { className: '', label: '', onChange: null, country: 'AU', disabled: false, }; export default PhoneInputField;
What do we need to pass in the onChange
prop?
Thanks a lot MidhaTahir Now I have finally passed the issue from react-phone-input-2😊😊
In case if anyone needs help this is my current implementation. Below approach works with both onChange and onBlur events and doesn't throw error when string is given in field (disabled). Thanks to above replies:
import "react-phone-number-input/style.css"; import PhoneInput from "react-phone-number-input"; const initialValues = { phoneNumber: "", }; const validate = (values) => { let errors = {}; if (!values.phoneNumber) { errors.phoneNumber = "⋆Required"; } return errors; }; const onSubmit = (values, onSubmitProps) => {....} const formik = useFormik({ initialValues, onSubmit, validate, }); <PhoneInput className='anonymous' placeholder='Phone Number' name='phoneNumber' value={formik.values.phoneNumber} onChange={e => formik.setFieldValue("phoneNumber", e)} onBlur={formik.handleBlur("phoneNumber")} /> {formik.touched.phoneNumber && formik.errors.phoneNumber ? ( <div className='text-danger text-right' style={{ marginBottom: "-13px", fontSize: "12px" }} > {formik.errors.phoneNumber} </div> ) : null}
Thank you so much. This helped me. Apparently, the trick was the formik.setFieldValue
method
I'm using Formik and trying to use this package, but Formik can't see the value of the input and thus doesn't validate or submit the form.
Here's the PhonInputField component that I'm using ...
And here's how I'm using it in Formik ...
What am I doing wrong here?