Reputation: 31
I am using React, Formik and yup to submit data to a REST API.
My React component is as follows:
import React from "react";
import { render } from "react-dom";
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const ContactUsFormSchema = Yup.object().shape({
givenName: Yup.string()
.required("First name is required")
.max(50, "Your first name must be 2 to 50 characters")
.min(2, "Your first name must be 2 to 50 characters"),
surname: Yup.string()
.required("Your last name is required")
.max(50, "Your last name must be 2 to 50 characters")
.min(2, "Your last name must be 2 to 50 characters"),
email: Yup.string()
.email()
.required("EMail address is required")
.max(100, "Your email address can't be longer than 100 characters")
});
class Register extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<button
id="home"
onClick={() => this.loadHome()}
className="square-button"
>
Home
</button>
<h1>SpringBoot/React OAuth2 Registration Page</h1>
<Formik
initialValues={{
givenName: this.props.user.givenName,
surname: this.props.user.surname,
email: this.props.user.email,
mobile: this.props.user.mobile
}}
validationSchema={ContactUsFormSchema}
// on submit Formik will call this passing the values and actions; call the doSubmit method passing them and the form itself
// Passing the form itself allows an action to be performed after the API call returns
onSubmit={(values, actions) => this.doSubmit(values, actions, this)}
// the render method returns the actual form; note each field has a corresponding error field
render={({ errors, touched, isSubmitting }) => (
<Form>
First Name:
<Field type="text" name="givenName" />
<ErrorMessage name="givenName">
{errorMessage => <div className="error">{errorMessage}</div>}
</ErrorMessage>
Last Name:
<Field type="text" name="surname" />
<ErrorMessage name="surname">
{errorMessage => <div className="error">{errorMessage}</div>}
</ErrorMessage>
Email Address:
<Field type="text" name="email" />
<ErrorMessage name="email">
{errorMessage => <div className="error">{errorMessage}</div>}
</ErrorMessage>
Mobile:
<Field type="text" name="mobile" />
<ErrorMessage name="mobile">
{errorMessage => <div className="error">{errorMessage}</div>}
</ErrorMessage>
<p />
{this.props.result}
<button type="submit" disabled={isSubmitting}>
Register
</button>
</Form>
)}
/>
</div>
);
}
doSubmit = (values, actions, form) => {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "http://localhost:8080/register", true);
xmlhttp.setRequestHeader("Accept", "application/json");
xmlhttp.setRequestHeader("Authorization", window.sessionStorage.jwt);
xmlhttp.setRequestHeader("Content-type", "application/json");
xmlhttp.onreadystatechange = function() {
// Function called when the state changes.
if (xmlhttp.readyState === 4) {
actions.setSubmitting(false);
if (xmlhttp.status === 200) {
render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
} else if (xmlhttp.status === 400) {
actions.setErrors(JSON.parse(xmlhttp.responseText).errors);
}
}
};
xmlhttp.send(JSON.stringify(values));
};
}
export default Register;
The JSON data returned by the API is
{
"errorCode": "Validation failed",
"errors": [
{
"errorMessage": "Phone numbers must consist of digits and spaces only with an optional + sign at the front",
"field": "mobile"
}
]
}
I'm really, really new to JavaScript let alone React etc. so I'm totally confused about why the errors aren't being populated as I would expect and would appreciate any help anyone would care to give.
Upvotes: 3
Views: 4210
Reputation: 1165
Your errors
array (returned from the API) doesn't fit Formik's error
model. The object you want to pass should have the field name as key and some string as value. For example:
{
givenName: 'First name is required',
email: "Your email address can't be longer than 100 characters"
}
In your case, you can transform your array of errors to object in the following way: https://jsfiddle.net/Lg87jwpb/2/ (commented imperative way
is given as an alternative for better understanding of how it's done).
Upvotes: 3