React final form - Validation return key & value instead of string - reactjs

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

How can I check if the value of the inputs is the same?

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"

react-hook-form do not send PasswordConfirm

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));
};

formik rendering an element when input field is clicked in react?

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
}}

Formik form not updating fields upon edit

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

redux-form, setting a field visibility based on other field value

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>
)
}

Resources