Currently I am using React-Final-Form and I want to return an object or key/value instead of an error string.
This is my validation rule:
validate={values => {
const errors = {}
if (!values.username) {
errors.username = 'Required'
}
if (!values.password) {
errors.password = 'Required'
}
if (!values.confirm) {
errors.confirm = 'Required'
} else if (values.confirm !== values.password) {
errors.confirm = 'Must match'
}
return errors
}}
This prints the error:
{meta.error && meta.touched && <span>{meta.error}</span>}
Instead of seeing Required I want to be able to say: key -> 'required' and the value of this key is 'please fill in the field'. I know it is possible to change the string of 'Required' but I want to have a key value. I cannot make an object it won't allow me.
Desired result:
{meta.error && meta.touched && {meta.error.required}}
UI will show:
Please fill in the field
This playground of react-final-form can be used since it is almost the same:
https://final-form.org/docs/react-final-form/examples/record-level-validation
Well, you can do it like this:
<Form
onSubmit={onSubmit}
validate={values => {
const errors = {}
if (!values.username) {
errors.username = { required: true, text: "Please fill in the field"} // this is used as an object
}
if (!values.password) {
errors.password = 'Required'
}
if (!values.confirm) {
errors.confirm = 'Required'
} else if (values.confirm !== values.password) {
errors.confirm = 'Must match'
}
return errors
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<Field name="username">
{({ input, meta }) => {
console.log(meta) // to see the structure of your meta
return (
<div>
<label>Username</label>
<input {...input} type="text" placeholder="Username" />
{meta.error && meta.touched && <span>{meta.error.text}</span>}
// then here if you still want to use string you can put what you need
</div>
)}}
</Field>
<Field name="password">
{({ input, meta }) => (
<div>
<label>Password</label>
<input {...input} type="password" placeholder="Password" />
{meta.error && meta.touched && meta.required && <span>{meta.error}</span>}
</div>
)}
</Field>
<Field name="confirm">
{({ input, meta }) => (
<div>
<label>Confirm</label>
<input {...input} type="password" placeholder="Confirm" />
{meta.error && meta.touched && <span>{meta.error}</span>}
</div>
)}
</Field>
<div className="buttons">
<button type="submit" disabled={submitting}>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
Related
I have a form where two fields have to have the same value to be able to continue with the process, for this I have created a component that is in charge of the comparison, the problem is that it does not show me the value of the input to be able to make the comparison . this is my component.
const UIInput = ({ register, rules, name, errors, label, type, options, equals, getValues, ...props }) => {
return (
<div>
<label >{label}</label>
{type === 'select' ?
<select
{...(register && register(name, rules))}>
{options.map(o => (
<option key={o}>{o}</option>
))}
</select>
:
<input
name={name}
{...props}
placeholder={label}
/* {...(register && register(name, rules))} */
{...(register && register({validate:{
name:value=>(value === getValues().email) || console.log('are not the same')
}}))}
/>
/* register && register(name, rules)) */
}
{errors[name] && <ErrorMessaje>{errors[name]?.message}</ErrorMessaje>}
</div>
)
}
export default UIInput
And this is how I use it:
<UIInput
name="email"
register={register}
errors={errors}
label="Email"
defaultValue={dataForm.email}
type="email"
rules={{ required: 'Enter an email' }}
/>
<UIInput
name="email2"
register={register}
errors={errors}
label="Confirmar Email"
type="email"
rules={{ required: 'Has to be the same value' }}
getValues={getValues}
/>
when I run the code the error it sends me is "path.split is not a function"
Hello guys I'm using react-hook-form library
it's really awesome library for me !
but I have some problem at this time
I don't want to send pwdConfirm value, cuz this value gets me 400 erros,
so How can I send values without pwdConfirm ?
I just only want to send id , pwd , nickname !
const dispatch = useDispatch();
const { register, watch, errors, handleSubmit } = useForm();
const password = useRef();
password.current = watch('password');
const type = 'normal';
const onSubmit = (data) => {
console.log(data);
dispatch(signUpRequest(data));
};
useEffect(() => {});
return (
<>
<form
onSubmit={handleSubmit(onSubmit)}
className={styles.signup__form}
>
<label>email</label>
<input
name="email"
type="text"
ref={register({ required: true, pattern: /^\S+#\S+$/i })}
placeholder=""
/>
{errors.email && (
<p className={styles.error__message}>
incorrect email
</p>
)}
<label>password</label>
<input
name="password"
type="password"
ref={register({ required: true, minLength: 6 })}
placeholder=""
/>
{errors.password && errors.password.type === 'required' && (
<p className={styles.error__message}>
password plz
</p>
)}
{errors.password && errors.password.type === 'minLength' && (
<p className={styles.error__message}>
at least 6character
</p>
)}
<label>password confirm </label>
<input
type="password"
name="pwdConfirm"
ref={register({
required: true,
validate: (value) => value === password.current,
})}
placeholder=""
/>
{errors.pwdConfirm && errors.pwdConfirm.type === 'required' && (
<p className={styles.error__message}>
check your password
</p>
)}
{errors.pwdConfirm && errors.pwdConfirm.type === 'validate' && (
<p className={styles.error__message}>
not correct your password
</p>
)}
I have used the delete operator of javascript to remove pwdConfirm key from an existing object.
const onSubmit = (data) => {
delete data.pwdConfirm
console.log(data);
dispatch(signUpRequest(data));
};
I am trying to make a simple login form i want to render an element when an input field is clicked . I have done this in normal react form by rendering an element by changing the value of a boolean variable to true and when the input is written if the user touch somewhere else then the element disapears . kind of toggle thing . but i don't know hoe to do this in formik. my code looks like this.
import React from "react";
import { Formik } from "formik";
import * as EmailValidator from "email-validator";
import * as Yup from "yup";
const ValidatedLoginForm = () => (
<Formik
initialValues={{ email: "", password: "" }}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
console.log("hello there ");
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required"),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number.")
})}>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<div className="container">
<div className="row">
<form onSubmit={handleSubmit}>
<br />
<input
name="email"
type="text"
placeholder="Enter your email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
<br />
<br />
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<br />
<input
name="password"
type="password"
placeholder="Enter your password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={errors.password && touched.password && "error"}
/> <br />
<br />
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
<button type="submit" disabled={isSubmitting}>
Login
</button>
</form>
</div>
<div className="row">
<button className="btn btn-default">Value</button>
</div>
</div>
);
}}
Maybe this will help you. Try to add function to onBlur prop then handle handleBlur function.
onBlur={(e) => {
handleBlur(e);
// here handle component showing
}}
I've been trying to rewrite my beginner form in React to use Formik.
I've gotten to the state that the form is being rendered, however, for some reason, I can't update the fields. It's clear that I made a mistake somewhere that prevents Formik from updating the state. What am I missing?
An example form component:
export const TextBox: React.SFC<FieldProps<any> & CustomFormElementProps> = ({
field, // { name, value, onChange, onBlur }
form: { touched, errors },
loading,
...props
}) => (
<div className="row form-group" key={field.name}>
<label className="col-sm-2 control-label">
<ReactPlaceholder showLoadingAnimation ready={!loading} type="text" rows={1} className="control-label">
{props.label}
</ReactPlaceholder>
</label>
<div className="col-sm-10">
<ReactPlaceholder showLoadingAnimation ready={!loading} type="text" rows={1} className="form-control">
<input type="text"
disabled={props.disabled}
className="form-control"
id={field.name}
onChange={field.onChange}
onBlur={field.onBlur} {...props} />
{touched[field.name] && errors[field.name] && <span className="text-danger">{errors[field.name]}</span>}
</ReactPlaceholder>
</div>
</div>
);
The form is initialized in another component (which acts as a page template for the website);
renderFormElements() {
var formFields = this.props.detailsElements.map((item) => {
switch (item.type) {
case FormElementType.TextLine:
return <TextLine
name={item.name}
label={item.label}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
key={'TextBox_' + item.name}
/>
case FormElementType.TextBox:
return <Field
type="text"
name={item.name}
label={item.label}
component={InputElements.TextBox}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
key={'TextBox_' + item.name}
/>
case FormElementType.DropDown:
return <Field
name={item.name}
label={item.label}
component={InputElements.DropDown}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
options={item.options}
key={'DropDown_' + item.name}
/>
case FormElementType.RadioGroup:
return <Field
type="radio"
name={item.name}
label={item.label}
component={InputElements.RadioGroup}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
options={item.options}
key={'RadioGroup' + item.name}
/>
}
});
var initialValues:{ [k: string]: any } = {};
this.props.detailsElements.map((item) => {
initialValues[item.name] = item.defaultValue;
})
console.log(initialValues);
var formSection =
(<Formik initialValues={initialValues} onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
actions.setSubmitting(false)
}, 1000)
}}>
<Form key="mainForm">
{formFields}
</Form>
</Formik>)
return formSection;
I was assuming that the onChange event handler was taken care of by Formik, and that, if I didn't want to do special stuff, I did not need to provide anything to this.
What am I missing here?
Thanks!
your formFields function gets all of Formik props goodies.
it contains handleChange - use this handler as your on change.
Also, make sure the field "id" is the same as the values key.
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
} = this.props;
<FormControl
id="username"
required
placeholder="Enter Username"
value={values.username}
error={touched.username && errors.username}
onChange={handleChange}
onBlur={handleBlur}
/>
try putting the name attribute in the input element
name is what you got from field.name
I have a complex form, where visibility of some fields is dependent on the value of other fields.
How is setting a field's visibility based on a value of other field done in redux-form?
const renderField = ({ input, label, type, display='flex', meta: { touched, error } }) => (
<div style={ { display: display }}>
<label>{label}</label>
<div>
<input {...input} type={type} placeholder={label}/>
{touched && error && <span>{error}</span>}
</div>
</div>
)
const renderMembers = ({ fields, meta: { touched, error } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
{touched && error && <span>{error}</span>}
</li>
{fields.map((member, index) =>
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"/>
<Fields names={[ `${member}.firstName`, `${member}.lastName` ]} component={renderFields}/>
<FieldArray name={`${member}.hobbies`} component={renderHobbies}/>
</li>
)}
</ul>
)
Let's assume that you have a form with 2 fields:
const fields = [
'foo',
'bar'
]
reduxForm(
{
form: 'AwesomeForm',
fields
}
)(AwesomeForm)
To control a field visibility based on other field value in the <AwesomeForm/> component, you can set corresponding display value with inline styles. Just make a verification, that checks if other value satisfies needed conditions. Like:
export const AwesomeForm = (props) => {
return (
<form onSubmit={props.handleSubmit}>
<TextField
{...props.fields.foo}
/>
<TextField
{...props.fields.bar}
style={{
display: props.fields.name.foo === 'some value' ? 'none' : 'block',
}}
/>
<button
type='submit'
/>
</form>
)
}