I am trying to send data to contact form 7 using Formik but i get the error of fields that are empty. Can you please guide what is the problem with it. If i remove required fields from contact form 7, the form send an email with empty fields.
import * as React from 'react';
import * as Yup from 'yup';
import axios from 'axios';
import { Formik } from 'formik';
const URL = 'YOUR SITE URL';
const CF7_ID = 'YOUR CONTACT FORM ID';
const formSchema = Yup.object().shape({
formName: Yup.string().required('Required'),
formEmail: Yup.string()
.email('Invalid email')
.required('Required'),
});
/*
function convertJsontoUrlencoded(obj) {
let str = [];
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
str.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
}
return str.join('&');
}
*/
const CF7 = () => {
const [state, setState] = React.useState(null || '');
return (
<>
<Formik
initialValues={{
formSubject: 'Your message',
formName: 'SAM ',
formEmail: 'salman#gmail.com',
formMessage: 'thisisisibdiad iuasdhasiud aidsuahdsiuahsd',
}}
validationSchema={formSchema}
onSubmit={(values, { setSubmitting }) => {
const submitData = async () => {
try {
const result = await axios({
//body: JSON.stringify(values),
url: `${URL}/wp-json/contact-form-7/v1/contact-forms/${CF7_ID}/feedback`,
headers: {
//Authorization: `Basic ${TOKEN}`,
'content-Type': 'application/json; charset=UTF-8',
//'content-type': 'multipart/form-data'
},
method: 'POST',
data: JSON.stringify(values),
});
setState(result.data.message);
setSubmitting(false);
} catch (error) {
setState('Something Went Wrong');
}
};
submitData();
}}
>
{({ values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="">
Subject
<input
type="text"
name="formSubject"
onChange={handleChange}
onBlur={handleBlur}
value={values.formSubject}
/>
{errors.formSubject && touched.formSubject ? <div>{errors.formSubject}</div> : null}
</label>
</div>
<div>
<label htmlFor="">
Name *
<input
type="text"
name="formName"
onChange={handleChange}
onBlur={handleBlur}
value={values.formName}
/>
{errors.formName && touched.formName ? <div>{errors.formName}</div> : null}
</label>
</div>
<div>
<label htmlFor="">
Email *
<input
type="email"
name="formEmail"
onChange={handleChange}
onBlur={handleBlur}
value={values.formEmail}
/>
{errors.formEmail && touched.formEmail ? <div>{errors.formEmail}</div> : null}
</label>
</div>
<div>
<label htmlFor="">
Message
<input
type="text"
name="formMessage"
onChange={handleChange}
onBlur={handleBlur}
value={values.formMessage}
/>
{errors.formMessage && touched.formMessage ? <div>{errors.formMessage}</div> : null}
</label>
</div>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
)}
</Formik>
{state ? <p>{state}</p> : null}
</>
);
};
export default CF7;
ERROR:
into: "#"
invalid_fields: [{into: "span.wpcf7-form-control-wrap.formName", message: "The field is required.", idref: null,…},…]
message: "One or more fields have an error. Please check and try again."
posted_data_hash: ""
status: "validation_failed"
Related
How can I solve the Axios Error in my code using the try/catch method . Am building a chat application with react js and stream API, when I try to signup using my signup form I get the Axios error which I don't know how I can debug it. You can help me out by editing my attached code so that i can continue with my project. Thanks in advance.
// below is my code//
import React, { useState } from 'react';
import Cookies from 'universal-cookie';
import axios from 'axios';
import signinImage from '../assets/signup.jpg';
const cookies = new Cookies();
const initialState = {
fullName: '',
username: '',
password: '',
confirmPassword: '',
phoneNumber: '',
avatarURL: '',
}
const Auth = () => {
const [form, setForm] = useState(initialState);
const [isSignup, setIsSignup] = useState(true);
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
}
const handleSubmit = async (e) => {
e.preventDefault();
const { username, password, phoneNumber, avatarURL } = form;
const URL = 'https://localhost:5000/auth';
// const URL = 'https://medical-pager.herokuapp.com/auth';
const { data: { token, userId, hashedPassword, fullName } } = await axios.post(`${URL}/${isSignup ? 'signup' : 'login'}`, {
username, password, fullName: form.fullName, phoneNumber, avatarURL,
});
cookies.set('token', token);
cookies.set('username', username);
cookies.set('fullName', fullName);
cookies.set('userId', userId);
if(isSignup) {
cookies.set('phoneNumber', phoneNumber);
cookies.set('avatarURL', avatarURL);
cookies.set('hashedPassword', hashedPassword);
}
window.location.reload();
}
const switchMode = () => {
setIsSignup((prevIsSignup) => !prevIsSignup);
}
return (
<div className="auth__form-container">
<div className="auth__form-container_fields">
<div className="auth__form-container_fields-content">
<p>{isSignup ? 'Sign Up' : 'Sign In'}</p>
<form onSubmit={handleSubmit}>
{isSignup && (
<div className="auth__form-container_fields-content_input">
<label htmlFor="fullName">Full Name</label>
<input
name="fullName"
type="text"
placeholder="Full Name"
onChange={handleChange}
required
/>
</div>
)}
<div className="auth__form-container_fields-content_input">
<label htmlFor="username">Username</label>
<input
name="username"
type="text"
placeholder="Username"
onChange={handleChange}
required
/>
</div>
{isSignup && (
<div className="auth__form-container_fields-content_input">
<label htmlFor="phoneNumber">Phone Number</label>
<input
name="phoneNumber"
type="text"
placeholder="Phone Number"
onChange={handleChange}
required
/>
</div>
)}
{isSignup && (
<div className="auth__form-container_fields-content_input">
<label htmlFor="avatarURL">Avatar URL</label>
<input
name="avatarURL"
type="text"
placeholder="Avatar URL"
onChange={handleChange}
required
/>
</div>
)}
<div className="auth__form-container_fields-content_input">
<label htmlFor="password">Password</label>
<input
name="password"
type="password"
placeholder="Password"
onChange={handleChange}
required
/>
</div>
{isSignup && (
<div className="auth__form-container_fields-content_input">
<label htmlFor="confirmPassword">Confirm Password</label>
<input
name="confirmPassword"
type="password"
placeholder="Confirm Password"
onChange={handleChange}
required
/>
</div>
)}
<div className="auth__form-container_fields-content_button">
<button>{isSignup ? "Sign Up" : "Sign In"}</button>
</div>
</form>
<div className="auth__form-container_fields-account">
<p>
{isSignup
? "Already have an account?"
: "Don't have an account?"
}
<span onClick={switchMode}>
{isSignup ? 'Sign In' : 'Sign Up'}
</span>
</p>
</div>
</div>
</div>
<div className="auth__form-container_image">
<img src={signinImage} alt="sign in" />
</div>
</div>
)
}
export default Auth
const handleSubmit = async (e) => {
e.preventDefault();
try {
const { username, password, phoneNumber, avatarURL } = form;
const URL = 'https://localhost:5000/auth';
// const URL = 'https://medical-pager.herokuapp.com/auth';
const { data: { token, userId, hashedPassword, fullName } } = await axios.post(`${URL}/${isSignup ? 'signup' : 'login'}`, {
username, password, fullName: form.fullName, phoneNumber, avatarURL,
});
cookies.set('token', token);
cookies.set('username', username);
cookies.set('fullName', fullName);
cookies.set('userId', userId);
if(isSignup) {
cookies.set('phoneNumber', phoneNumber);
cookies.set('avatarURL', avatarURL);
cookies.set('hashedPassword', hashedPassword);
}
window.location.reload();
} catch(error) {
console.log(error.response);
}
}
I'm having troubles with React-Final-Form library. From the onSubmit function, I return a validation error, but it is not displayed on the form itself. Here you can see my code:
My form:
<Form
onSubmit={this.onSubmit}
initialValues={{}}
validate={
values => {
const errors = {}
if (!values.username) {
errors.username = "This field is required"
}
if (!values.password) {
errors.password = "This field is required"
}
return errors
}
}
render={({submitError, handleSubmit, submitting, values}) => (
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>First Name</label>
<Field name="username">
{({input, meta}) => (
<>
<input {...input} type="text" placeholder="Username"
className={"form-control" + ((meta.error || meta.submitError) && meta.touched ? " is-invalid" : "")}/>
{(meta.error || meta.submitError) && meta.touched ?
<div
className="invalid-feedback">{meta.error || meta.submitError}</div> : null
}
</>
)}
</Field>
{submitError && (
<div>{submitError}</div>
)}
</div>
<div className="form-group">
<label>Password</label>
<Field name="password">
{({input, meta}) => (
<>
<input {...input} type="password"
placeholder="Password"
className={"form-control" + ((meta.error || meta.submitError) && meta.touched ? " is-invalid" : "")}/>
{(meta.error || meta.submitError) && meta.touched ?
<div
className="invalid-feedback">{meta.error || meta.submitError}</div> : null
}
</>
)}
</Field>
</div>
<button type="submit" disabled={submitting}
className="btn btn-block btn-outline-secondary">Log In
</button>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
My onSubmit function:
onSubmit = async values => {
const errors = {}
let loginData = {
username: values.username,
password: values.password
}
usersAPI.getCSRF().then((response) => {
usersAPI.login(loginData)
.then(response => {
if (response.data.login_status === "Incorrect data") {
console.log("Invalid data")
errors.username = "Invalid login or password"
errors.password = "Invalid login or password"
return errors
} else {
localStorage.setItem('token', response.data.token)
this.props.setAuthState(true)
console.log("Logged in successfully")
}
})
.catch(err => console.log(err))
})
}
The problem is in axios request. If my back-end server sends the response that credentials are invalid, then console.log("Invalid data") will appear in console but nothing will happen with form. If I comment my axios request and just leave this code:
onSubmit = async values => {
return {username: "Invalid data"}
}
So, in this case everything works correct. Who can tell me How can I optimize my axios request so after that my form will get submission errors that returned from
errors.username = "Invalid login or password"
errors.password = "Invalid login or password"
return errors
I found mistake. Mistake was in my return function. It just returns this value to usersAPI.getCSRF() function, not to global onSubmit function. I made some changes so my final code looks like this:
onSubmit = values => {
let loginData = {
username: values.username,
password: values.password
}
let success = false;
usersAPI.getCSRF().then((response) => {
usersAPI.login(loginData)
.then(response => {
if (response.data.login_status !== "Incorrect data") {
success = true
localStorage.setItem('token', response.data.token)
}
})
.catch(err => console.log(err))
})
if (success) this.props.setAuthState(true)
else return {username: "Incorrect username or password", password: "Incorrect username or password"}
}
I spent 2 days on the same issue (submission errors not displaying) and wanted to post my solution here in case anyone else ran into my issue because I could not find it online.
Basically I have a form set up like so:
const onSubmit = (values) => {
...
return {username: 'required'} // errors object
}
<Form
onSubmit={onSubmit}
>
{({values}) => (
<form>
<a onClick={() => onSubmit(values)}>save</a>
...restOfForm
</form>
)}
</Form>
The issue above is that I am calling my "onSubmit" function directly, so the returned submission errors go nowhere. I needed to call the "handleSubmit" function passed into the render function to populate the errors like so:
<Form
onSubmit={onSubmit}
>
{({values, handleSubmit}) => (
<form>
<a onClick={() => handleSubmit(values)}>save</a>
...restOfForm
</form>
)}
</Form>
I'm new to formik and i am trying to populate an edit page where users can edit existing fields with formik. I keep getting React Hook "useEffect" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks error. I used the react useEffect hook to try and get the data from the backend.
function Edit({ history, match }) {
const { id } = match.params;
const isAdd = !id;
const initialValues = {
firstName: '',
lastName: '',
};
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.required('First Name is required'),
lastName: Yup.string()
.required('Last Name is required'),
});
return (
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={()={}}>
{({ errors, touched, isSubmitting, setFieldValue }) => {
useEffect(() => {
if (!isAdd) {
getById(id).then(user => {
const fields = ['firstName', 'lastName'];
fields.forEach(field => setFieldValue(field, user[field], false));
});
}
}, []);
return (
<Form>
<div className="form-group col-5">
<label>First Name</label>
<Field name="firstName" type="text" className={'form-control' +
(errors.firstName && touched.firstName ? ' is-invalid' : '')} />
<ErrorMessage name="firstName" component="div" className="invalid-
feedback" />
</div>
<div className="form-group col-5">
<label>Last Name</label>
<Field name="lastName" type="text" className={'form-control' +
(errors.lastName && touched.lastName ? ' is-invalid' : '')} />
<ErrorMessage name="lastName" component="div" className="invalid-
feedback" />
</div>
</div>
</Form>
);
}}
</Formik
)}
export { Edit };
I'm trying to create a login form using formik. I'm confused as to how to fire handleSubmit function to call the login api for a user to login. I kept calling handleSubmit inside onSubmit but it doesn't recognize the values and handleSubmit inside the onSubmit method in line 10 and 11 in my codesandbox in the ValidatedLoginForm.js file. Where do I exactly call the handleSubmit and let the user log in to my website?
my codesandbox
my code looks something like this:
import React, { useState } from "react";
import { Formik } from "formik";
import TextField from "#material-ui/core/TextField";
import * as Yup from "yup";
const ValidatedLoginForm = props => (
<Formik
initialValues={{ email: "", password: "" }}
onSubmit={values => {
const handleSubmit = async event => {
event.preventDefault();
var body = {
password: password,
email: email
};
console.log(body);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options);
const text = await response.text();
if (text === "redirect") {
props.history.push(`/editor`);
} else if (text === "verifyemail") {
props.history.push(`/verifyOtp/${this.state.email}`);
} else {
console.log("login failed");
window.alert("login failed");
}
} catch (error) {
console.error(error);
}
};
}}
//********Using Yup for validation********/
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 (
<>
<form onSubmit={handleSubmit} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
value={values.email}
label="Email Address"
name="email"
autoComplete="email"
autoFocus
onChange={handleChange}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
value={values.password}
label="Password"
type="password"
id="password"
onBlur={handleBlur}
autoComplete="current-password"
className={errors.password && touched.password && "error"}
onChange={handleChange}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
<button type="submit" disabled={isSubmitting}>
Login
</button>
</form>
</>
);
}}
</Formik>
);
export default ValidatedLoginForm;
You're currently creating a new function in your onSubmit code that never gets called. The function values => { ... } is called when the form is submitted, but in that function you create handleSubmit and never call it.
If you move the creation of handleSubmit a bit up it all gets easier to read. This will become something like
import React, { useState } from "react";
import { Formik } from "formik";
import TextField from "#material-ui/core/TextField";
import * as EmailValidator from "email-validator";
import * as Yup from "yup";
const ValidatedLoginForm = props => {
// The function that handles the logic when submitting the form
const handleSubmit = async values => {
// This function received the values from the form
// The line below extract the two fields from the values object.
const { email, password } = values;
var body = {
password: password,
email: email
};
console.log(body);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
};
const url = "/api/authenticate";
try {
const response = await fetch(url, options);
const text = await response.text();
if (text === "redirect") {
props.history.push(`/editor`);
} else if (text === "verifyemail") {
props.history.push(`/verifyOtp/${this.state.email}`);
} else {
console.log("login failed");
window.alert("login failed");
}
} catch (error) {
console.error(error);
}
};
// Returning the part that should be rendered
// Just set handleSubmit as the handler for the onSubmit call.
return (
<Formik
initialValues={{ email: "", password: "" }}
onSubmit={handleSubmit}
//********Using Yup for validation********/
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 (
<>
<form onSubmit={handleSubmit} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
value={values.email}
label="Email Address"
name="email"
autoComplete="email"
autoFocus
onChange={handleChange}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
value={values.password}
label="Password"
type="password"
id="password"
onBlur={handleBlur}
autoComplete="current-password"
className={errors.password && touched.password && "error"}
onChange={handleChange}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
<button type="submit" disabled={isSubmitting}>
Login
</button>
</form>
</>
);
}}
</Formik>
);
};
export default ValidatedLoginForm;
I would also move the validationSchema out of your component. Makes it easier to read/understand and it doesn't have to be recreated every time.
I'm working to enable server-side validation with redux-form, where when a user submits the SignUp form, if the server responds with an error, the form shows the error... In this case the error has a status of 422 from the server and is responding w {"errors":{"email":["has already been taken"]}}
While the form is submitting fine, I can't get the SubmissionError to display on the form. I'm getting the following error in the JS console:
Unhandled rejection SubmissionError: Submit Validation Failed
What am I doing wrong with redux-form submit validation handling? Thanks
SignUpForm
const ensureValid = response => {
if (response.status === 422) {
return response.json().then(({errors}) => {
throw new SubmissionError({
email: 'Already in Use',
_error: 'failed!',
});
});
}
return response;
};
class SignUp extends React.Component {
handleSubmit(data) {
const request = new Request('http://localhost:4400/auth/', {
method: 'POST',
headers: new Headers({
'Accept' : 'application/json',
'Content-Type' : 'application/json',
}),
body: JSON.stringify({ user: data })
});
fetch(request).then(ensureValid).then(response => {
return tryLogin(response, this.props.dispatch);
});
}
render() {
const { error, handleSubmit, pristine, reset, submitting } = this.props;
return (
<div className="container">
<div className="row justify-content-md-center">
<div className="col-6">
<h1>Sign Up - it's free.</h1>
<form onSubmit={this.props.handleSubmit(this.handleSubmit.bind(this))}>
<Field
name="first_name"
type="text"
component={renderField}
label="First Name"
/>
<Field
name="last_name"
type="text"
component={renderField}
label="Last Name"
/>
<Field
name="email"
type="text"
component={renderField}
label="Email"
/>
<Field
name="password"
type="password"
component={renderField}
label="Password"
/>
<button type="submit" disabled={submitting}>Submit</button>
{error && <strong>{error}</strong>}
</form>
</div>
</div>
</div>
);
}
}
// Decorate the form component
SignUp = reduxForm({
form: 'SignUp' // a unique name for this form
})(SignUp);
const mapStateToProps = state => {
return {
};
};
const mapDispatchToProps = (dispatch) => bindActionCreators({
dispatch
}, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(SignUp);
Turns out I needed to update:
BEFORE:
fetch(request)...
AFTER:
return fetch(request) ...