How to properly use Formik's setError method? (React library) - javascript

I am using React communicating with a backend. Now trying to properly implement Formik (Form library).
Main question:
How do I properly use Formik's setError method?
Client side validation errors show properly, but now I am trying to set/show the backend validation errors, which are returned with a response with status code 400.
Link to the docs on the method I am trying to use
I am using this method in the method named handle400Error in the code below.
My React (and Formik) code:
import React, { Component } from "react";
import axios from "axios";
import { Formik } from "formik";
import * as Yup from "yup";
import styled from "styled-components";
import FormError from "../formError";
const Label = styled.label``;
class LoginForm extends Component {
initialValues = {
password: "",
username: ""
};
getErrorsFromValidationError = validationError => {
const FIRST_ERROR = 0;
return validationError.inner.reduce((errors, error) => {
return {
...errors,
[error.path]: error.errors[FIRST_ERROR]
};
}, {});
};
getValidationSchema = values => {
return Yup.object().shape({
password: Yup.string()
.min(6, "Password must be at least 6 characters long")
.required("Password is required!"),
username: Yup.string()
.min(5, "Username must be at least 5 characters long")
.max(40, "Username can not be longer than 40 characters")
.required("Username is required")
});
};
handleSubmit = async (values, { setErrors }) => {
console.log("handleSubmit");
try {
const response = await axios.post(
"http://127.0.0.1:8000/rest-auth/login/",
values
);
const loginToken = response.data["key"];
this.handleLoginSuccess(loginToken);
} catch (exception) {
// Expected: 400 status code
if (exception.response && exception.response.status === 400) {
// Display server validation errors
this.handle400Error(exception.response.data, setErrors);
}
console.log("exception", exception);
console.log("exception.response", exception.response);
}
};
handle400Error = (backendErrors, setErrors) => {
let errors = {};
for (let key in backendErrors) {
errors[key] = backendErrors[key][0]; // for now only take the first error of the array
}
console.log("errors object", errors);
setErrors({ errors });
};
handleUnexpectedError = () => {};
handleLoginSuccess = loginToken => {
console.log("handleLoginSuccess");
this.props.setGreeneryAppState({
loginToken: loginToken
});
this.props.history.replace(`/${this.props.locale}/`);
};
validate = values => {
const validationSchema = this.getValidationSchema(values);
try {
validationSchema.validateSync(values, { abortEarly: false });
return {};
} catch (error) {
return this.getErrorsFromValidationError(error);
}
};
render() {
return (
<React.Fragment>
<h1>Login</h1>
<Formik
initialValues={this.initialValues}
validate={this.validate}
validationSchema={this.validationSchema}
onSubmit={this.handleSubmit}
render={({
errors,
touched,
values,
handleBlur,
handleChange,
handleSubmit
}) => (
<form onSubmit={handleSubmit}>
{errors.non_field_errors && (
<formError>{errors.non_field_errors}</formError>
)}
<Label>Username</Label>
<input
onChange={handleChange}
onBlur={handleBlur}
value={values.username}
type="text"
name="username"
placeholder="Enter username"
/>
{touched.username &&
errors.username && <FormError>{errors.username}</FormError>}
<Label>Password</Label>
<input
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
type="password"
name="password"
placeholder="Enter password"
/>
{touched.password &&
errors.password && <FormError>{errors.password}</FormError>}
<button type="submit">Log in</button>
</form>
)}
/>
</React.Fragment>
);
}

Formik author here...
setError was deprecated in v0.8.0 and renamed to setStatus. You can use setErrors(errors) or setStatus(whateverYouWant) in your handleSubmit function to get the behavior you want here like so:
handleSubmit = async (values, { setErrors, resetForm }) => {
try {
// attempt API call
} catch(e) {
setErrors(transformMyApiErrors(e))
// or setStatus(transformMyApiErrors(e))
}
}
What's the difference use setStatus vs. setErrors?
If you use setErrors, your errors will be wiped out by Formik's next validate or validationSchema call which can be triggered by the user typing (a change event) or blurring an input (a blur event). Note: this assumed you have not manually set validateOnChange and validateOnBlur props to false (they are true by default).
IMHO setStatus is actually ideal here because it will place the error message(s) on a separate part of Formik state. You can then decide how / when you show this message to the end user like so.
// status can be whatever you want
{!!status && <FormError>{status}</FormError>}
// or mix it up, maybe transform status to mimic errors shape and then ...
{touched.email && (!!errors.email && <FormError>{errors.email}</FormError>) || (!!status && <FormError>{status.email}</FormError>) }
Be aware that the presence or value of status has no impact in preventing the next form submission. Formik only aborts the submission process if validation fails.

const formik = useFormik({
initialValues:{
email:"",password:"",username:""
},
validationSchema:validation_schema,
onSubmit:(values) => {
const {email,password,username} = values
// ......
}
});
formik.setErrors({email:"Is already taken"}) // error message for email field

I just solved my own problem.
I needed to use:
setErrors( errors )
instead of:
setErrors({ errors })

Another way to handle this situation is to assign a specific key to your api errors and use setStatus for status messages.
__handleSubmit = (values, {setStatus, setErrors}) => {
return this.props.onSubmit(values)
.then(() => {
setStatus("User was updated successfully.");
})
.catch((err) => {
setErrors({api: _.get(err, ["message"])});
});
}
Then any validation errors would appear by the fields and any api errors could appear at the bottom:
<Formik
validationSchema={LoginSchema}
initialValues={{login: ""}}
onSubmit={this.__handleSubmit}
>
{({isSubmitting, status, errors, values, setFieldValue}) => (
<Form className={classNames("form")}>
<FormGroup>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faUser} fixedWidth />
</InputGroup.Text>
<Field
name="login"
type={"text"}
placeholder="Login"
className="form-control"
/>
</InputGroup>
<ErrorMessage name="login" />
</FormGroup>
<Button type="submit" variant="primary" disabled={isSubmitting}>
Submit
</Button>
{errors && _.has(errors, ["api"]) && <div className="text-danger">{_.get(errors, ["api"])}</div>}
{status && <div className="text-success">{status}</div>}
</Form>
)}
</Formik>
Don't forget about the schema...
const LoginSchema = Yup.object().shape({
login: Yup.string()
.min(4, 'Too Short!')
.max(70, 'Too Long!')
.required('Login is required'),
});
The api error message will show until the next validation call by Formik (i.e. the user is fixing something). But the status message will stay until you clear it (with a timer or Fade).

This what you're looking
setErrors({ username: 'This is a dummy procedure error' });

<Formik
validationSchema={schema}
initialValues={{ email: '', pswrd: '' }}
onSubmit={(values, actions) => {
// initialise error status <---- 1
actions.setStatus(undefined);
setTimeout(() => {
// setting error status <---- 2
actions.setStatus({
email: 'This is email already exists.',
pswrd: 'This is password is incorrect',
});
}, 500);
}}
// destructuring status <---- 3
render={({ handleSubmit, handleChange, handleBlur, values, errors, status }) => (
<form onSubmit={handleSubmit}>
<input
type="text"
name="email"
value={values['email']}
onChange={handleChange}
onBlur={handleBlur}
/>
<input
type="text"
name="pswrd"
value={values['pswrd']}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
// using error status <---- 4
{status && status.email ? (
<div>API Error: {status.email}</div>
) : (
errors.email && <div>Validation Error: {errors.email}</div>
)}
{status && status.pswrd ? (
<div>API Error: {status.pswrd}</div>
) : (
errors.pswrd && <div>Validation Error: {errors.pswrd}</div>
)}
</form>
)}
/>

Related

How can I check by React Hook Form if password contains a number?

How can I check by React Hook Form and Yup if password contains a numbers, capital letters and special signs? I tried something like this below, using validate function but it doesn't work correctly. I have an error 'Cannot read property 'reduce' of undefined'.
const Register = ({ setRegisterView }) => {
const validationSchema = Yup.object().shape({
email: Yup.string()
.required("It is required.")
.email("Email is wrong"),
password: Yup.string()
.required("It is required.")
.min(8, "Password need to has 8 signs.")
.validate((value) => {
return (
[/[a-z]/, /[A-Z]/, /[0-9]/, /[^a-zA-Z0-9]/].every((pattern) =>
pattern.test(value)
) ||
"Information"
);
}),
});
const {
register: validate,
formState: { errors },
handleSubmit,
} = useForm({ mode: "onSubmit", resolver: yupResolver(validationSchema) });
return (
<Wrapper>
<Form onSubmit={handleSubmit(registerProcess)}>
<FieldType>Email</FieldType>
<StyledInput
name="email"
type="email"
error={errors.email}
{...validate("email")}
/>
{errors.email && <Error>{errors.email.message}</Error>}
<FieldType>Password</FieldType>
<StyledInput
name="password"
type="password"
error={errors.password}
{...validate("password")}
/>
{errors.password && <Error>{errors.password.message}</Error>}
<LoginButton type="submit">SIGN UP</LoginButton>
</Form>
</Wrapper>
);
};
export default Register;
I think the problem is that you're using validate which expects a Promise as the return value -> Docs. You should instead use test here.
const validationSchema = Yup.object().shape({
email: Yup.string().required("It is required.").email("Email is wrong"),
password: Yup.string()
.required("It is required.")
.min(8, "Password need to has 8 signs.")
.test("passwordRequirements", "Information", (value) =>
[/[a-z]/, /[A-Z]/, /[0-9]/, /[^a-zA-Z0-9]/].every((pattern) =>
pattern.test(value)
)
)
});
Try this in your inputs
<Input type="email"
error={errors.email}
{...register("email")}
/>
And note that the builtin validation doesn't work with external validation, so required won't do anything here.

Yup 'notRequired' method doesn't seem to be working in my form validation

I am using Yup to validate my form fields.
I want the user to paste their instagram URL into the input field. It is not a required field but if they do start to type, the string must match the regex. The regex works, however the 'invalid url' message still displays if the user doesn't type anything, even although the field should not be required. I have tried the following but it still doesn't work. Any suggestions?
const validationSchema = Yup.object().shape({
instagram: Yup.string()
.notRequired()
.matches(
/(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im,
'invalid url'
),
});
In this case you need to use the .nullable() method.
Try this :
const validationSchema = Yup.object().shape({
instagram: Yup.string()
.matches(
/(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im,
'invalid url'
)
.nullable(),
});
Long time no see! I'm not sure if you're using a form state manager or not, but a lot of people seem to use Formik with Yup.
Take a look at this working example using Formik with Yup:
Demo Code:
import * as React from "react";
import { Formik } from "formik";
import * as Yup from "yup";
const validationSchema = Yup.object().shape({
instagram: Yup.string()
.notRequired()
.matches(
/(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im,
"Invalid Instagram URL. Example: http(s)://instagram.com/janedoe"
)
});
const ValidatedInstagramForm = () => {
const handleFormSubmit = (values, { setSubmitting }) => {
alert(
`Validated form was submitted with:\n${JSON.stringify(values, null, 4)}`
);
setSubmitting(false);
};
return (
<Formik
initialValues={{ instagram: "" }}
onSubmit={handleFormSubmit}
validationSchema={validationSchema}
>
{({
errors,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
values,
touched
}) => (
<form className="form" onSubmit={handleSubmit}>
<div className="input-container">
<label className="label" htmlFor="instagram">
Instagram
</label>
<input
name="instagram"
type="text"
placeholder="Enter your instagram (optional)..."
value={values.instagram}
onChange={handleChange}
onBlur={handleBlur}
className="input"
style={{
background:
errors.instagram && touched.instagram
? "rgba(255, 0, 0, 0.25)"
: "",
borderColor: errors.instagram && touched.instagram ? "red" : ""
}}
/>
{errors.instagram && touched.instagram && (
<div className="error">{errors.instagram}</div>
)}
</div>
<button className="button" type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
)}
</Formik>
);
};
export default ValidatedInstagramForm;
If you're not using a form state manager, then you could always manually validate the input on form submit instead of on input change:
Demo Code:
import * as React from "react";
const ValidatedInstagramForm = () => {
const [value, setValue] = React.useState("");
const [error, setError] = React.useState("");
const handleChange = ({ target: { value } }) => {
setValue(value);
setError("");
};
const isValidInput = (value) => {
if (!value) return "";
return /(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im.test(
value
)
? ""
: "Invalid Instagram URL. Example: http(s)://instagram.com/janedoe";
};
const handleSubmit = (event) => {
event.preventDefault();
const error = isValidInput(value);
if (!error)
alert(
`Validated form was submitted with:\n${JSON.stringify(
{ instagram: value },
null,
4
)}`
);
else setError(error);
};
return (
<form className="form" onSubmit={handleSubmit}>
<div className="input-container">
<label className="label" htmlFor="instagram">
Instagram
</label>
<input
name="instagram"
type="text"
placeholder="Enter your instagram (optional)..."
value={value}
onChange={handleChange}
className="input"
style={{
background: value && error ? "rgba(255, 0, 0, 0.25)" : "",
borderColor: value && error ? "red" : ""
}}
/>
{value && error ? <div className="error">{error}</div> : null}
</div>
<button className="button" type="submit" disabled={error}>
Submit
</button>
</form>
);
};
export default ValidatedInstagramForm;
In fact, there are two definitions of .matches() method :
string.matches(regex: Regex, message?: string | function)
string.matches(regex: Regex, options: { message: string, excludeEmptyString: bool })
Both are matching the Regexp passed in argument, but the second one short circuits the test when the value is an empty string (notice that now the message should be in the options object).
So in your case, you should use the second definition. Here is the correct code (you don't need to include .notRequired method) :
const validationSchema = Yup.object().shape({
instagram: Yup.string()
.matches(
/(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im,
{
message: 'invalid url',
excludeEmptyString: true,
}
),
});
I had several problems in this matter, so this is my take, and solution. e.g. Allowed null, or if they were filled in then they had to have an min length.
taxid: Yup.string()
.nullable()
.notRequired()
.transform(x => x === '' ? undefined : x)
.min(5, 'TaxID must be at least 5 characters'),
corpname: Yup.string()
.nullable()
.notRequired()
.transform(x => x === '' ? undefined : x)
.min(2, 'Company name must be at least 2 characters'),
postno: Yup.string()
.required('Post number is required')
.min(4, 'Post number must be at least 4 characters'),

How to take values from Formik inside a hook?

I am using Formik in my app. I need to take values from Formik and use it inside my hook.
Currently I am doing it using useRef hook
Following is my custom hook code which requires Formik values
const { doRequest, errors } = useRequest({
url: "my_url",
method: "post",
body: {
mobileNumber: formikRef.current
? formikRef.current.values.mobileNumber
: "",
password: formikRef.current ? formikRef.current.values.password : "",
},
onSuccess: (response) => {
console.log("Hi" + response.msg);
Router.push("/");
},
onFailure: (response) => {
console.log("Hi2" + response.msg);
},
});
In the body, the mobile number and password is always empty even though I enter values in my textfield. I am calling the doRequest method inside onSubmit of Formik
I am asking the ref using following
<Formik
innerRef={formikRef}..
If I had used useState for all my fields It would have been extremely easy to pass those values to my custom hook but due to large form and validation , I am using Formik
You don't need to use innerRef. You can simply use formik values.
Your custom hook should return doRequest which accepts a param so that it can catch dynamic values.
write the hook in such a way that it caters to both static values and dynamic values. See the closed github issue here
working demo
Code snippet
export default () => {
const { doRequest, errors } = useRequest({
url: "my_url",
method: "post",
body: {
mobileNumber: "0000",
password: "xxxx"
},
onSuccess: response => {
console.log("Hi" + response.msg);
// Router.push("/");
},
onFailure: response => {
console.log("Hi2" + response.msg);
}
});
const handleSubmit = (values, actions) => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
doRequest(values);
};
return (
<div className="col-sm-12">
<h1>My Form</h1>
<Formik initialValues={{ mobileNumber: "" }} onSubmit={handleSubmit}>
{({ errors }) => (
<Form>
<Field name="mobileNumber" placeholder="Mobile Number" />
<Field name="password" placeholder="Password" />
<div className="messages-wrapper">
{errors.email && (
<div className="alert alert-danger">
<ErrorMessage name="mobileNumber" />
</div>
)}
{errors.password && (
<div className="alert alert-danger">
<ErrorMessage name="password" />
</div>
)}
</div>
<button className="btn btn-primary" type="submit">
Submit
</button>
</Form>
)}
</Formik>
</div>
);
};
You can get any value from the Formik bag via the useFormikContext() hook. Like so:
const { values } = useFormikContext();
const { mobileNumber } = values;
You could use the predefined useFormikContext() hook provided by Formik or you could set a ref to Formik and use its current value to fetch Formik form values.

Why I'm getting these warnings while using useEffect hook in React.js?

js and hooks, I have been getting these warnings and I just don't understand why, I did read React documentation but still I don't get it
./src/CustomerList.js
Line 32:6: React Hook useEffect has a missing dependency: 'loadData'. Either include it or remove the
dependency array react-hooks/exhaustive-deps
./src/CustomerForm.js
Line 44:9: React Hook useEffect has a missing dependency: 'setValue'. Either include it or remove the
dependency array react-hooks/exhaustive-deps
I will just paste the hole code side in case the problem is not in the useEffect itself.
const CustomerForm = ({customer, saveSuccess}) => {
const { register, handleSubmit, errors, setValue, reset } = useForm();
const onSubmit = (data, e) => {
e.preventDefault();
if (customer) {
data.id = customer.id;
axios.put(BASE_URL, {
id : data.id,
firstName : data.firstName,
lastName : data.lastName,
phoneNumber:data.phoneNumber,
email : data.email
}).then(response => {
alert("Se actualizó exitosamente.")
})
} else {
axios.post(BASE_URL, {
firstName : data.firstName,
lastName : data.lastName,
phoneNumber:data.phoneNumber,
email : data.email
}).then(response => {
alert("Se guardó exitosamente.")
})
}
saveSuccess();
};
useEffect(() => {
if (customer) {
setValue("firstName", customer.firstName);
setValue("lastName", customer.lastName);
setValue("phoneNumber", customer.phoneNumber);
setValue("email", customer.email);
}
},[customer]);
return (
<form onSubmit={handleSubmit(onSubmit)} noValidate>
<Input
name="firstName"
inputRef={register({ required: true})}
placeholder="First Name"
error={!!errors.firstName}
fullWidth
/>
<p style={{color: "red"}}>{errors.firstName && "First Name is required"}</p>
<Input
name="lastName"
// setValue = {customerForm.lastName}
inputRef={register({ required: true})}
placeholder="Last Name"
error={!!errors.lastName}
fullWidth
/>
<p style={{color: "red"}}>{errors.lastName && "Last Name is required"}</p>
<Input
name="phoneNumber"
// setValue = {customerForm.phoneNumber}
inputRef={register({ required: true})}
placeholder="Phone Number"
error={!!errors.phoneNumber}
fullWidth
/>
<p style={{color: "red"}}>{errors.phoneNumber && "Phone Number is required"}</p>
<Input
name="email"
// setValue = {customerForm.email}
inputRef={register({ required: true})}
placeholder="Email"
error={!!errors.email}
fullWidth
/>
<p style={{color: "red"}}>{errors.email && "Email is required"}</p>
<Button
variant="contained"
color="default"
onClick={() => { reset({}) }}
>
Reset
</Button>
<Button
type="submit"
variant="contained"
color="primary"
>
Save
</Button>
</form>
);
}
Are you able to link to a working example? That might help with debugging, but just by reading over your code it seems those warnings should resolve if you add those dependencies in your useEffect call. eg:
/* CustomerForm */
useEffect(() => {
if (customer) {
setValue("firstName", customer.firstName);
setValue("lastName", customer.lastName);
setValue("phoneNumber", customer.phoneNumber);
setValue("email", customer.email);
}
},[customer, loadData, setValue]);
You could add the missing dependency such as
useEffect(() => {
if (customer) {
setValue("firstName", customer.firstName);
setValue("lastName", customer.lastName);
setValue("phoneNumber", customer.phoneNumber);
setValue("email", customer.email);
}
},[customer,setValue,loadData]);
but in some cases adding a method as a dependency causes an infinite re-render so i think the best way to overcome the warning is to disable it by
useEffect(() => {
if (customer) {
setValue("firstName", customer.firstName);
setValue("lastName", customer.lastName);
setValue("phoneNumber", customer.phoneNumber);
setValue("email", customer.email);
}
//eslint-disable-next-line
},[customer]);

Why do my error messages not update when a field is filled out? (React)

This seems like a simple thing to do but after much fiddling, I can't figure out what's wrong. I'm a noob to React so forgive me.
I have a form for logging in. Like most login forms, it's asking for a username and password. Then it has a button to submit. My understanding is that a component will re-render if the state is changed. I have onchange events on each input field that updates the state. So if the field is empty, I press the button to submit, I would expect that the error will show. If I fill in a field, I would expect the error message to go away because the state changed. Am I misunderstanding?
Here is my event handler:
handleLogin(event) {
event.preventDefault();
if (this.state.username == '') {
this.setState({usernameError: "Need to enter a username"})
return;
}
if (this.state.password == '') {
this.setState({passwordError: "Need to enter a password"})
return;
}
}
And the form:
render() {
return(
<form className="login-form">
<h1 className="login-form__header"><FontAwesomeIcon icon="key" className="registration-form__icon"/><i className="fal fa-route-highway"></i>Log Into Your Account</h1>
<input type="text" name="username" placeholder="Username" className="login-form__input" onChange={(event,newValue) => this.setState({username:newValue})}/>
{this.state.usernameError &&
<p class="login-form__error"><FontAwesomeIcon icon="times-circle"/> {this.state.usernameError}</p>
}
<input type="password" name="password" placeholder="Password" className="login-form__input" onChange={(event,newValue) => this.setState({password:newValue})}/>
{this.state.passwordError &&
<p class="login-form__error"><FontAwesomeIcon icon="times-circle"/> {this.state.passwordError}</p>
}
<button className="login-form__button" onClick={this.handleLogin}>Log Into Your Account</button>
</form>
);
}
Right, but you never configured any logic to clear the errors if the field is not empty. Currently, there isnt any logic set-up to turn usernameError and passwordError back to an empty-string or null value.
You might be under the impression that the state is cleared when you re-render but that is not the case. The state-object prior to the re-render still persists, only changing the key-value pair(s) you last updated within this.setState().
Try this:
handleLogin(event) {
event.preventDefault();
const { username, password } = this.state
this.setState({
...this.state,
usernameError: username.length > 0 ? "" : "Need to enter a username",
passwordError: password.length > 0 ? "" : "Need to enter a password"
})
}
Here's a working sandbox with a sligtly modified version of your code. (I removed the FontAwesomeIcons). https://codesandbox.io/s/cool-meninsky-y9r4y
First of all, onChange={(event,newValue) => this.setState({username:newValue})} this is not a good approach, as it will create a new function on every render. So I would suggest to create a dedicated function like -
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
// Make sure the name is as per with your html username password and update the state accordingly
this.setState({
[name]: value
});
}
Do remember to reset the usernameError and passwordError properties of your state on each related onChange event. Otherwise the error message will persist on HTML.
Hi you can try the below code
function validate(email, username, password) {
// true means invalid, so our conditions got reversed
return {
username: username.length === 0, //true if username is empty
password: password.length === 0, //true if password is empty
};
}
class LoginForm extends React.Component {
constructor() {
super();
this.state = {
username: '',
password: '',
touched: {
username: false,
password: false,
},
};
}
handleUsernameChange = (evt) => {
this.setState({ username: evt.target.value });
}
handlePasswordChange = (evt) => {
this.setState({ password: evt.target.value });
}
handleBlur = (field) => (evt) => {
this.setState({
touched: { ...this.state.touched, [field]: true },
});
}
handleSubmit = (evt) => {
if (!this.canBeSubmitted()) {
evt.preventDefault();
return;
}
const { username, password } = this.state;
alert(`Logined: ${email} password: ${password}`);
}
canBeSubmitted() {
const errors = validate(this.state.username, this.state.password);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return !isDisabled;
}
render() {
const errors = validate(this.state.username, this.state.password);
const isDisabled = Object.keys(errors).some(x => errors[x]);
const shouldMarkError = (field) => {
const hasError = errors[field];
const shouldShow = this.state.touched[field];
return hasError ? shouldShow : false;
};
return (
<form className="login-form" onSubmit={this.handleSubmit}>
<h1 className="login-form__header">
<FontAwesomeIcon icon="key" className="registration-form__icon"/>
<i className="fal fa-route-highway"></i>Log Into Your Account
</h1>
<input
className={shouldMarkError('username') ? "error" : ""}
type="text" name="username" placeholder="Username"
value={this.state.username}
onBlur={this.handleBlur('username')
onChange={this.handleUsernameChange} />
<p className={shouldMarkError('username') ? "error" : "hidden"}>
<FontAwesomeIcon icon="times-circle"/> Need to enter a username
</p>
<input type="password" name="password" placeholder="Password"
className={shouldMarkError('password') ? "error" : ""}
value={this.state.password}
onChange={this.handlePasswordChange}
onBlur={this.handleBlur('password')} />
<p className={shouldMarkError('password') ? "error" : "hidden"}>
<FontAwesomeIcon icon="times-circle"/> Need to enter a password
</p>
<button disabled={isDisabled} className="login-form__button"
onClick={this.handleLogin}>Log Into Your Account</button>
</form>
)
}
}
Hope the code could helpful for you.
You can also refer the Demo Validation for Signup
As mentioned by #Satyaki onChange={(event,newValue) => this.setState({username:newValue})} is not a good option you should define separate method for this, alternatively you can change your code to as follows:
onChange={(event,newValue) => this.setState({username:newValue})}, () => {})
This will make sure to complete the lifecycle of setState.

Categories

Resources