how to put API status json in the state? - javascript

I need to put the json in the register state to use it in different parts of the project
But unfortunately, after console.log(register); from that state, it returns an empty object in inspect
import React, { useEffect, useState } from "react";
import { Formik } from "formik";
// * icons
import { FaGoogle, FaFacebookF, FaGithub } from "react-icons/fa";
// *sweet alert
import swal from "sweetalert";
const Login = () => {
const [singUp, setSignUp] = useState(0);
const [register, setRegister] = useState();
useEffect(() => {
// console.log(register);
}, [singUp]);
return (
<div
className={
singUp > 0 ? "container py-5 right-panel-active" : "container py-5"
}
id="container"
>
<div className="form-container sing-up-container">
<Formik
initialValues={{
email: "",
password: "",
name: "",
invalidClass: "",
}}
validate={(values) => {
const errors = {};
if (!values.name) {
errors.name = "Required";
errors.invalidClass = "form-control is-invalid";
}
if (!values.email) {
errors.email = "Required";
errors.invalidClass = "is-invalid";
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = "Invalid email address";
errors.invalidClass = "is-invalid";
}
if (!values.password) {
errors.password = "Required";
errors.invalidClass = "form-control is-invalid";
}
if (values.password.length < 8 && values.password.length > 0) {
errors.password = "is short";
errors.invalidClass = "form-control is-invalid";
}
if (values.password.length > 16) {
errors.password = "is Long";
errors.invalidClass = "form-control is-invalid";
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
// !text message for status here
swal(
"Signed up!",
"Created account successfully! Please Login",
"success"
);
console.log(JSON.stringify(values, null, 2));
const data = {
name: values.name,
email: values.email,
password: values.password,
};
console.log(data);
console.log(values.name);
console.log(values.email);
console.log(values.password);
fetch("https://api.freerealapi.com/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: data.name,
email: data.email,
password: data.password,
}),
})
// ! bug is here
.then((response) => response.json())
.then((json) => console.log(json))
.then((json) => setRegister(json));
// .then((response) =>
// setRegister({
// message: response.message,
// status: response.status,
// success: response.success,
// token: response.token,
// })
// );
// console.log(register);
console.log("hi");
setSubmitting(false);
}, 400);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit} className="py-3" action="">
<h1>Create Account</h1>
<div className="social-container">
<a href="" className="social">
<FaGoogle />
</a>
<a href="" className="social">
<FaFacebookF />
</a>
<a href="" className="social">
<FaGithub />
</a>
</div>
<span>Or use your email for Registration</span>
{/* // !name */}
<input
type="text"
name="name"
placeholder="Name"
className={
errors.name && touched.name && errors.name
? errors.invalidClass
: "form-control is-valid"
}
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
{errors.name && touched.name && errors.name}
{/* // !email */}
<input
type="email"
name="email"
placeholder="Email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
className={
errors.email && touched.email && errors.email
? errors.invalidClass
: "form-control is-valid"
}
/>
{errors.email && touched.email && errors.email}
{/* // !password */}
<input
className={
errors.password && touched.password && errors.password
? errors.invalidClass
: "form-control is-valid"
}
placeholder="Password"
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button type="submit" className="my-2" disabled={isSubmitting}>
Sing Up
</button>
</form>
)}
</Formik>
</div>
<div className="form-container sing-in-container">
<Formik
initialValues={{ email: "", password: "" }}
validate={(values) => {
const errors = {};
if (!values.email) {
errors.email = "Required";
errors.invalidClass = "is-invalid";
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = "Invalid email address";
errors.invalidClass = "is-invalid";
}
if (!values.password) {
errors.password = "Required";
errors.invalidClass = "form-control is-invalid";
}
if (values.password.length < 8 && values.password.length > 0) {
errors.password = "is short";
errors.invalidClass = "form-control is-invalid";
}
if (values.password.length > 16) {
errors.password = "is Long";
errors.invalidClass = "form-control is-invalid";
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
swal("Signed in!", "Login successfully! Please Wait", "success");
console.log(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
/* and other goodies */
}) => (
<form action="" onSubmit={handleSubmit}>
<h1>Sign In</h1>
<div className="social-container">
<a href="" className="social">
<FaGoogle />
</a>
<a href="" className="social">
<FaFacebookF />
</a>
<a href="" className="social">
<FaGithub />
</a>
</div>
<span>or use your account</span>
<input
type="email"
name="email"
placeholder="Email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
className={
errors.email && touched.email && errors.email
? errors.invalidClass
: "form-control is-valid"
}
/>
{errors.email && touched.email && errors.email}
<input
className={
errors.password && touched.password && errors.password
? errors.invalidClass
: "form-control is-valid"
}
placeholder="Password"
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button className="my-2" type="submit" disabled={isSubmitting}>
Sing In
</button>
</form>
)}
</Formik>
</div>
<div className="overlay-container">
<div className="overlay">
<div className="overlay-panel overlay-left">
<h1>Welcome Back!</h1>
<p>
To keep connectied with up please login with your personal info
</p>
<button
className="devingine"
onClick={() => {
setSignUp(singUp - 1);
}}
id="signIn"
>
Sign In
</button>
</div>
<div className="overlay-panel overlay-right">
<h1>Hello, Friend!</h1>
<p>Enter your parsonal details and start journey with us.</p>
<button
className="devingine"
onClick={() => {
setSignUp(singUp + 1);
}}
id="signUp"
>
Sign Up
</button>
</div>
</div>
</div>
</div>
);
};
export default Login;
sorceCode
inspect is Here

The problem is in the second then statement in promises chain where console.log returns undefined value:
/* ... */
.then((response) => response.json())
.then((json) => console.log(json)) // <- console.log() returns undefined
.then((json) => setRegister(json));
/* ... */
When you chain promises you have to remember that value which is returned from promise is passed as and argument to callback of next promise in a chain.
You can do:
/* ... */
.then((response) => response.json())
.then((json) => {
console.log(json);
return json;
})
.then((json) => setRegister(json));
/* ... */

Related

How to prepopulate a react formik form

I have a table tha stores Students with an edit buttom tha opens a formik form.
const EditStudentFrom = (props) => (
<Formik
initialValues={{studentId:"", firstName: "", lastName: "", email: "", gender: "" }}
validate={(values) => {
const errors = {};
if (!values.firstName) {
errors.firstName = "First name required";
}
if (!values.lastName) {
errors.lastName = "Last name required";
}
if (!values.email) {
errors.email = " Email required";
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = "Invalid Email address";
}
if (!values.gender) {
errors.gender = "Gender required";
} else if (
!["MALE ", "male", "female", "FEMALE"].includes(values.gender)
) {
errors.gender = "Gender most be ( MALE , male , FEMALE, female )";
}
return errors;
}}
onSubmit={(student, { setSubmitting }) => {
editStudent(student.studentId,student).then(() => {
props.onSuccess();
setSubmitting(false);
});
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
submitForm,
isValid,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit}>
<Input
style={inputMargin}
name="firstName"
onChange={handleChange}
onBlur={handleBlur}
value={values.firstName}
placeholder="First name"
/>
{errors.firstName && touched.firstName && (
<Tag style={tagStyle}>{errors.firstName}</Tag>
)}
<Input
style={inputMargin}
name="lastName"
onChange={handleChange}
onBlur={handleBlur}
value={values.lastName}
placeholder="Last name"
/>
{errors.lastName && touched.lastName && (
<Tag style={tagStyle}>{errors.lastName}</Tag>
)}
<Input
style={inputMargin}
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
placeholder="Email"
/>
{errors.email && touched.email && (
<Tag style={tagStyle}>{errors.email}</Tag>
)}
<Input
style={inputMargin}
name="gender"
onChange={handleChange}
onBlur={handleBlur}
value={values.gender}
placeholder="Gender"
/>
{errors.gender && touched.gender && (
<Tag style={tagStyle}>{errors.gender}</Tag>
)}
<Button
onClick={() => submitForm()}
type="submit"
disabled={isSubmitting | (touched && !isValid)}
>
Submit
</Button>
</form>
)}
</Formik>
);
export default EditStudentFrom;
the eddit buttom on my table sets the visible property on a Modal to true to open the form
{
title:"",
Key:"buttom",
render:(value, student)=>(<Button onClick={this.openEditStudentModal}
>Edit</Button>)
}
how do i set the initialValues of the form to be the values for the student in the same row as the edit buttom i really need the studentId so i can pass it to the back end like this
export const editStudent= (studentId,student)=>
fetch(`http://localhost:1020/api/students/${studentId}`, {
method: "PUT",
body: JSON.stringify(student),
headers: {
"Content-Type": "application/json",
},
});
In order to use the form for editing the students objects, you need to pass the student object as initialValues of the <Formik>component. Note that you'll probably have to set the enableReinitialize prop to true, so Formik can reset the form when the initialValues prop changes.

How to pass a custom callback function onSubmit in Formik with React

I am trying to pass a custom callback function after a succesfull form is completed. When I try to pass my callback function, handleCount to onSubmit, Formik doesn't seem to pass this to my parent React component.
Note:
My previous approach that worked was to add onSubmit to the button: <button onSubmit={handleCount}>...</button>, but this will pass handleCount when the form still has errors.
Here is my code and architecture:
// Join.js
export default function Join({handleCount} {
<Formik
...
onSubmit={async (values, { setSubmitting }) => {
handleCount
await new Promise((r) => setTimeout(r, 500));
setSubmitting(false);
}}
}
<button type="submit">CREATE ACCOUNT</button>
//Signup.js
import Join from "../components/SignUpFlow/1-SignUp/Join";
<Join handleCount={handleCount}
/>
I was able to get it work by passing the setSubmitting function as a function instead of part of an object. The following code worked for me:
// Join.js
export default function Join({ handleCount }) {
return (
<Formik
initialValues={{ email: "", password: "" }}
validate={(values) => {
const errors = {};
if (!values.email) {
errors.email = "Required";
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = "Invalid email address";
}
return errors;
}}
onSubmit={async (values, { setSubmitting }) => {
setTimeout(() => {
console.log("called");
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
isSubmitting,
}) => (
<form
onSubmit={async (values, setSubmitting) => {
handleCount();
await new Promise((response) => setTimeout(response, 500));
setSubmitting(false);
}}
>
<input
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<input
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button type="submit" disabled={isSubmitting}>
CREATE ACCOUNT
</button>
</form>
)}
</Formik>
);
}
// Signup.js
function App() {
function handleCount() {
console.log("function handleCount called.");
}
return <Join handleCount={handleCount} />;
}

Check user name availability from firebase in react

I am currently stuck on checking unique username in the sign up(on firebase) in react. My goal is that
1. when the user input the username, the function checkNameAvalaible go to the firebase database and check if the name exists.
2.if the name exists set the state of usernameavalaible to false, and set it to true if name works
3.disable the submit button of the sign up if the usernameavalaible is false.
4.If the username is taken, use helper text in textfield to alert the current user.
I am stuck with the if statement, I tried a few times and it is not working here is my code
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { auth } from "../firebase";
import { db} from "../firebase";
import "./auth.css";
import * as routes from "../constants/routes";
import { SignInLink } from "./SignIn";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
const SignUpPage = ({ history }) => (
<div align="center" className="SignUpBox">
<h1>SignUp</h1>
<SignUpForm history={history} />
<SignInLink />
</div>
);
const INITIAL_STATE = {
username: "",
name: "",
email: "",
passwordOne: "",
passwordTwo: "",
error: null
};
const byPropKey = (propertyName, value) => () => ({
[propertyName]: value
});
class SignUpForm extends Component {
state = { ...INITIAL_STATE };
// checkPassword() {
// if(!this.state.passwordOne || this.state.passwordOne !== this.state.passwordTwo){
// this.setState({error:"passwords do not match"});
// }
// else {
// this.setState({error:null});
// }
// }
onSubmit = event => {
event.preventDefault();
const { email, passwordOne, name, username } = this.state;
auth
.doCreateUserWithEmailAndPassword(
email,
passwordOne,
name,
username
)
.then(authUser => {
this.setState(() => ({ ...INITIAL_STATE }));
this.props.history.push(routes.HOME);
})
.catch(error => {
this.setState(byPropKey("error", error));
});
};
render() {
var usernameAvalaible
const {
username,
name,
email,
passwordOne,
passwordTwo,
error
} = this.state;
checkNameAvalaible(){
if (db.doc(`/users/${username}`).get().exists){
this.setState{usernameAvalaible:false};
}
else{
this.setState{usernameAvalaible:true};
}
};
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === "" ||
email === "" ||
name === "" ||
username === ""|| usernameAvalaible===false;
return (
<form onSubmit={this.onSubmit}>
<TextField
name="Username"
id="standard-secondary"
label="User name"
color="primary"
value={username}
onChange={event =>
this.setState(byPropKey("username", event.target.value))
}
type="text"
/>
<TextField
name="name"
value={name}
id="standard-secondary"
label="Full name"
color="primary"
onChange={event =>
this.setState(byPropKey("name", event.target.value))
}
type="text"
/>
<TextField
name="email"
value={email}
id="standard-secondary"
label="Email Address"
color="primary"
onChange={event =>
this.setState(byPropKey("email", event.target.value))
}
type="email"
/>
<TextField
name="password"
value={passwordOne}
id="standard-secondary"
label="Password"
color="primary"
onChange={event =>
this.setState(byPropKey("passwordOne", event.target.value))
}
type="password"
/>
<TextField
name="ConfirmPassword"
value={passwordTwo}
id="standard-secondary"
label="Comfirm Password"
color="primary"
onChange={event =>
this.setState(byPropKey("passwordTwo", event.target.value))
}
type="password"
/>
<br />
<br />
<Button
type="submit"
disabled={isInvalid}
variant="contained"
color="primary"
>
Sign Up
</Button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</form>
);
}
}
const SignUpLink = () => (
<p>
Don't have an account? <Link to={routes.SIGN_UP}>Sign Up</Link>
</p>
);
export default SignUpPage;
export { SignUpForm, SignUpLink };

Why isn't Formik.setStatus updating the Status state in my form?

I'm using Formik to create a generic contact form in react. I am getting data from my api and attempting to call Formik's setStatus to generate a message to show that the form has been submitted successfully.
For whatever reason the Status state never gets updated to reflect what I put in setStatus.
Here's my code:
import { Formik, Form, useField } from "formik";
import * as Yup from "yup";
import axios from "axios";
import Button from "components/shared/button";
import "styles/contact/form.scss";
const handleSubmit = (values, actions) => {
axios.post("http://localhost:5000/sendemail/", values).then(res => {
actions.setSubmitting(false);
actions.setStatus = {
message: res.data.message
};
setTimeout(() => {
actions.resetForm();
}, 3000);
});
};
const FormField = ({ label, tagName, ...props }) => {
const [field, meta] = useField(props);
const errorClass = meta.touched && meta.error ? "error" : "";
const TagName = tagName;
return (
<>
<label htmlFor={props.id || props.name}>
{label}
{meta.touched && meta.error ? (
<span className="error">{meta.error}</span>
) : null}
</label>
<TagName
className={`form-control ${errorClass}`}
{...field}
{...props}
/>
</>
);
};
const ContactForm = () => (
<Formik
initialValues={{ name: "", email: "", msg: "" }}
validationSchema={Yup.object({
name: Yup.string().required("Required"),
email: Yup.string()
.email("Invalid email address")
.required("Required"),
msg: Yup.string().required("Required")
})}
onSubmit={handleSubmit}>
{({ isSubmitting, status }) => (
<Form className="contact-form">
<div className="row form-group">
<div className="col">
<FormField
label="Name"
name="name"
type="text"
tagName="input"
/>
</div>
<div className="col">
<FormField
label="Email"
name="email"
type="text"
tagName="input"
/>
</div>
</div>
<div className="form-group">
<FormField label="Message" name="msg" tagName="textarea" />
</div>
{status && status.message && (
<div className="message">{status.message}</div>
)}
<Button
id="formSubmit"
text="Send Message"
type="submit"
isSubmitting={isSubmitting}
/>
</Form>
)}
</Formik>
);
export default ContactForm;
Just before my submit button, it should show the <div class="message">Success message</div> after submitting the form. When I try to debug the value of Status is always "undefined".
Any one have a clue what I'm doing wrong here?
The reason it wasn't working is because I tried to set the value of setStatus equal to an object. What I should have done was used it as a method and pass the object as a parameter.
Like so:
actions.setStatus({message: res.data.message});
I feel silly for missing this simple mistake for so long.

Add a react-bootstrap alert to handleSubmit in Formik

I'm trying to add a react-bootstrap alert to my Formik form so that the handleSubmit includes an alert to the user that the form has submitted.
I have used the react-bootstrap documented form of Alert, however I had to change the last line because that seems not to work (the error says that I haven't exported anything if I use the react-bootstrap documented form of alert.
My alert is:
import React from 'react';
import {
Alert,
Button,
} from "react-bootstrap";
class AlertDismissible extends React.Component {
constructor(props) {
super(props);
this.state = { show: true };
}
render() {
const handleHide = () => this.setState({ show: false });
const handleShow = () => this.setState({ show: true });
return (
<>
<Alert show={this.state.show} variant="light">
<Alert.Heading>Thanks for your interest </Alert.Heading>
<p>
We'll be in touch with login details shortly.
</p>
<hr />
<div className="d-flex justify-content-end">
<Button onClick={handleHide} variant="outline-success">
Close
</Button>
</div>
</Alert>
{!this.state.show && <Button onClick={handleShow}>Show Alert</Button>}
</>
);
}
}
export default AlertDismissible;
The documentation shows a final line as:
render(<AlertDismissible />);
If I try to use that, an error message saying that render is not defined, and that nothing has been exported appears. So - I replaced that line with my final line.
Then, in my form I have:
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("register")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then => {<AlertDismissible />}
.catch(error => {
console.error("Error adding document: ", error);
});
}
I don't actually know how to get the alert to work (the then statement above is a guess - I can't find any examples. This guess gives an error that says:
Parsing error: Unexpected token, expected ";"
I've tried adding ";" in every place I can think to put one, but it keeps generating errors.
If I try it like this:
.then(<AlertDismissible />)
I get no errors and the form submits, but the alert is not displayed.
Does anyone know how to call a react-bootstrap alert in the handle submit function?
Submit button has:
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}>
Register
</Button>
The onSubmit has:
onSubmit={
this.handleSubmit
}
My entire form looks like this:
import React from 'react';
import { Link } from "react-router-dom";
import { Formik, Form, Field, ErrorMessage, withFormik } from "formik";
import * as Yup from "yup";
import Select from "react-select";
import { fsDB, firebase, settings } from "../../firebase";
import Temporarynav from '../navigation/Temporarynav.jsx';
import Demo from '../landing/Demo.jsx';
import Footer from '../footer/Footer.jsx';
import "./preregister/Form.css";
import AlertDismissible from '../auth/preregister/Alert';
import {
Badge,
Button,
Col,
ComponentClass,
Feedback,
FormControl,
FormGroup,
Table,
Row,
Container
} from "react-bootstrap";
import Alert from 'react-bootstrap/Alert';
const style1 = {
width: "60%",
margin: "auto"
};
const style2 = {
paddingTop: "2em"
};
const style3 = {
marginRight: "2em"
};
const initialValues = {
firstName: "",
lastName: "",
email: "",
role: "",
consent: false,
createdAt: ''
}
class PreregForm extends React.Component {
// constructor(props) {
// super(props);
// // the flag isFormDone will control where you will show the Alert component
// this.state = {
// isFormDone: false
// };
// }
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("preregistrations")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(() => {
// Here is where you flag your form completion and allow the alert to be shown.
// this.setState((prevState) => {...prevState, isFormDone: true});
.catch(error => {
console.error("Error adding document: ", error);
});
}
render() {
const options = [
{ value: "academic", label: "Academic Researcher" },
{ value: "student", label: "Student (inc PhD)" },
]
// const {isFormDone} = this.state;
return(
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape({
firstName: Yup.string().required("First Name is required"),
lastName: Yup.string().required("Last Name is required"),
email: Yup.string()
.email("Email is invalid")
.required("Email is required"),
role: Yup.string().nullable().required(
"It will help us get started if we know a little about your background"
),
consent: Yup.boolean().oneOf(
[true],
"You must accept the Terms of Use and Privacy Policy"
)
})}
onSubmit={
this.handleSubmit
}
render={({
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
<Temporarynav />
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<p>
We're almost ready to open this up to the research community. By
registering now, you'll be first in line when the doors open.
</p>
<div className="form-group">
<label htmlFor="firstName">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">
<label htmlFor="lastName">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 className="form-group">
<label htmlFor="email">Email</label>
<Field
name="email"
type="text"
placeholder="Please use your work email address"
className={
"form-control" +
(errors.email && touched.email ? " is-invalid" : "")
}
/>
<ErrorMessage
name="email"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="role">
Which role best describes yours?
</label>
<Select
key={`my_unique_select_keyrole`}
name="role"
className={
"react-select-container" +
(errors.role && touched.role ? " is-invalid" : "")
}
classNamePrefix="react-select"
value={values.role}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue("role", selectedOptions)}
}
onBlur={setFieldTouched}
options={options}
/>
{errors.role && touched.role &&
<ErrorMessage
name="role"
component="div"
className="invalid-feedback d-block"
/>}
</div>
<div className="form-group">
<div className="checkbox-wrapper">
<Field
name="consent"
type="checkbox"
checked={values.consent}
className={
"checkbox" +
(errors.consent && touched.consent ? " is-invalid" : "")
}
/>
<label htmlFor="consent" className="checkbox_label_wrapper">
You must accept the{" "}
<Link className="links" to={"/Terms"}>
Terms of Use
</Link>{" "}
and{" "}
<Link className="links" to={"/Privacy"}>
Privacy Policy
</Link>
</label>
</div>
{errors.consent && touched.consent &&
<ErrorMessage
name="consent"
component="div"
className="invalid-feedback d-block"
/>
}
</div>
<div className="form-group">
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}
>
Register
</Button>
</div>
</Form>
<Demo />
<Footer />
</div>
);
}
}
/>
)
}
}
export default PreregForm;
Next attempt
When I try Julius solution, the alert appears, but as a footer beneath the form - not as a popup alert.
Use state and conditional rendering. Instead of returning a component set state to a variable, in your render use conditional rendering to check if the value is true.
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
};
console.log('formvalues', payload);
fsDB
.collection('register')
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(e => this.setState({ alert: true }))
.catch(error => {
console.error('Error adding document: ', error);
});
};
In your render
render() {
...
return(
....
{this.state.alert && <AlertDismissible />}
...
)
}
Example Demo
Complete form
import React from 'react';
import { Link } from 'react-router-dom';
import { Formik, Form, Field, ErrorMessage, withFormik } from 'formik';
import * as Yup from 'yup';
import Select from 'react-select';
import { fsDB, firebase, settings } from '../../firebase';
import Temporarynav from '../navigation/Temporarynav.jsx';
import Demo from '../landing/Demo.jsx';
import Footer from '../footer/Footer.jsx';
import './preregister/Form.css';
import AlertDismissible from '../auth/preregister/Alert';
import {
Badge,
Button,
Col,
ComponentClass,
Feedback,
FormControl,
FormGroup,
Table,
Row,
Container
} from 'react-bootstrap';
import Alert from 'react-bootstrap/Alert';
const style1 = {
width: '60%',
margin: 'auto'
};
const style2 = {
paddingTop: '2em'
};
const style3 = {
marginRight: '2em'
};
const initialValues = {
firstName: '',
lastName: '',
email: '',
role: '',
consent: false,
createdAt: ''
};
class PreregForm extends React.Component {
constructor(props) {
super(props);
// the flag isFormDone will control where you will show the Alert component
this.state = {
showAlert: false
};
}
handleSubmit = (formState, { resetForm }) => {
// Now, you're getting form state here!
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
};
console.log('formvalues', payload);
fsDB
.collection('preregistrations')
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(e => this.setState({ showAlert: true }))
.catch(error => {
console.error('Error adding document: ', error);
});
};
render() {
const options = [
{ value: 'academic', label: 'Academic Researcher' },
{ value: 'student', label: 'Student (inc PhD)' }
];
// const {isFormDone} = this.state;
return (
<div>
{!this.state.showAlert ? (
<div>
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape({
firstName: Yup.string().required('First Name is required'),
lastName: Yup.string().required('Last Name is required'),
email: Yup.string()
.email('Email is invalid')
.required('Email is required'),
role: Yup.string()
.nullable()
.required(
'It will help us get started if we know a little about your background'
),
consent: Yup.boolean().oneOf(
[true],
'You must accept the Terms of Use and Privacy Policy'
)
})}
onSubmit={this.handleSubmit}
render={({
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
<Temporarynav />
<Form style={style1}>
<h1 style={style2}>Get Started</h1>
<p>
We're almost ready to open this up to the research
community. By registering now, you'll be first in line
when the doors open.
</p>
<div className="form-group">
<label htmlFor="firstName">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">
<label htmlFor="lastName">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 className="form-group">
<label htmlFor="email">Email</label>
<Field
name="email"
type="text"
placeholder="Please use your work email address"
className={
'form-control' +
(errors.email && touched.email ? ' is-invalid' : '')
}
/>
<ErrorMessage
name="email"
component="div"
className="invalid-feedback"
/>
</div>
<div className="form-group">
<label htmlFor="role">
Which role best describes yours?
</label>
<Select
key={`my_unique_select_keyrole`}
name="role"
className={
'react-select-container' +
(errors.role && touched.role ? ' is-invalid' : '')
}
classNamePrefix="react-select"
value={values.role}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue('role', selectedOptions);
}}
onBlur={setFieldTouched}
options={options}
/>
{errors.role && touched.role && (
<ErrorMessage
name="role"
component="div"
className="invalid-feedback d-block"
/>
)}
</div>
<div className="form-group">
<div className="checkbox-wrapper">
<Field
name="consent"
type="checkbox"
checked={values.consent}
className={
'checkbox' +
(errors.consent && touched.consent
? ' is-invalid'
: '')
}
/>
<label
htmlFor="consent"
className="checkbox_label_wrapper"
>
You must accept the{' '}
<Link className="links" to={'/Terms'}>
Terms of Use
</Link>{' '}
and{' '}
<Link className="links" to={'/Privacy'}>
Privacy Policy
</Link>
</label>
</div>
{errors.consent && touched.consent && (
<ErrorMessage
name="consent"
component="div"
className="invalid-feedback d-block"
/>
)}
</div>
<div className="form-group">
<Button
variant="outline-primary"
type="submit"
style={style3}
id="submitRegistration"
onClick={handleSubmit}
disabled={!dirty || isSubmitting}
>
Register
</Button>
</div>
</Form>
<Demo />
<Footer />
</div>
);
}}
/>
</div>
) : (
<AlertDismissible />
)}
</div>
);
}
}
export default PreregForm;
You can't return a component like that within the then function.
You should manage a state flag that shows the alert based on the form completion.
Maybe you could share your whole component where you are handling the submit shown here so we can give you more help (will update the answer if you update the question).
But I think it would be something along the following lines:
class MyFormComponent extends React.Component {
constructor(props) {
super(props);
// the flag isFormDone will control where you will show the Alert component
this.state = {
isFormDone: false
};
}
/** Here your form handling as you posted */
handleSubmit = (formState, { resetForm }) => {
const payload = {
...formState,
role: formState.role.value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
fsDB
.collection("register")
.add(payload)
.then(docRef => {
resetForm(initialValues);
})
.then(() => {
// Here is where you flag your form completion and allow the alert to be shown.
this.setState((prevState) => ({...prevState, isFormDone: true}));
})
.catch(error => {
console.error("Error adding document: ", error);
});
}
render() {
const {isFormDone} = this.state;
// this will only render the Alert when you complete your form submission
const alert = isFormDone ? <AlertDismissible/> : null;
return(
{/* syntax sugar for React Fragment */}
<>
{/* if it is null, it won't render anything */}
{alert}
{/* Your Form here with your handler */}
{/* ... */}
</>
);
}
}

Categories

Resources