Form validation using React, EmailJS and Bootstrap - reactjs

So I'm trying to get my form validation to work using EmailJs and Bootstrap within React for a simple contact form. I got the validation to work on the UI, however, it will still send the email even if the fields are red and required. Any idea what I'm doing wrong? I followed the examples here: https://react-bootstrap.github.io/forms/validation/ and here: https://www.emailjs.com/docs/examples/reactjs/ but it does not seem to be working correctly.
Thanks in advance for any help you can provide.
EDIT
I was able to solve this by using a handleSubmit function after my sendEmail function. Please see updated code below.
I also added a way to clear the form by setting setValidated(false); e.target.reset(); within .then() method after the user submits the form...Hopefully this will help others struggling with this.
import React, { useRef, useState } from "react";
import emailjs from "#emailjs/browser";
import Button from "react-bootstrap/Button";
import PageTitle from "../components/PageTitle";
import Form from "react-bootstrap/Form";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import FloatingLabel from "react-bootstrap/FloatingLabel";
import config from "../configData.json";
import "./Contact.scss";
export const Contact = () => {
const [validated, setValidated] = useState(false);
const form = useRef();
const sendEmail = (e) => {
e.preventDefault();
emailjs
.sendForm(
config.serviceId,
config.templateId,
"#contact-form",
config.publicKey
)
.then(
() => {
alert("Your message has been sent.");
setValidated(false);
e.target.reset();
},
(error) => {
alert("There was a problem sending your message.", error);
}
);
};
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
} else {
// alert("Message was sent!");
sendEmail(event);
}
setValidated(true);
};
return (
<>
<PageTitle title="Contact" />
<div className="container my-5">
<h2 className="mb-4">Leave a Message</h2>
<Form
noValidate
ref={form}
onSubmit={handleSubmit}
validated={validated}
id="contact-form"
>
<Row>
<Form.Group as={Col} md="12" controlId="nameValidation">
<FloatingLabel
controlId="floatingInput"
label="Name"
className="mb-3"
>
<Form.Control
type="text"
placeholder="Name"
name="user_name"
size="lg"
required
/>
<Form.Control.Feedback type="invalid">
Please enter your name.
</Form.Control.Feedback>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</FloatingLabel>
</Form.Group>
<Form.Group as={Col} md="12" controlId="emailValidation">
<FloatingLabel
controlId="floatingInput"
label="Email"
className="mb-3"
>
<Form.Control
type="email"
placeholder="name#example.com"
name="user_email"
size="lg"
required
/>
<Form.Control.Feedback type="invalid">
Please enter a valid email.
</Form.Control.Feedback>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</FloatingLabel>
</Form.Group>
<Form.Group as={Col} md="12" controlId="messageValidation">
<FloatingLabel
controlId="floatingInput"
label="Message"
className="mb-3"
>
<Form.Control
placeholder="Message"
name="user_message"
size="lg"
required
as="textarea"
rows={3}
/>
<Form.Control.Feedback type="invalid">
Please enter a message.
</Form.Control.Feedback>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</FloatingLabel>
</Form.Group>
</Row>
<Button
type="submit"
value="Send"
variant="primary"
size="lg"
className="mt-3 w-100"
>
SEND
</Button>
</Form>
</div>
</>
);
};
export default Contact;

Could you please share your HTML where you are getting this info?
Even required, you can make the type='email' required so it will validade for you.
if that still a problem (which should not be), then make an IF to validade for you.
Here is an example. You can use the function below to validade if it is an email. Send the email typed by the user via parameter.
const validateEmail = (email) => {
return String(email)
.toLowerCase()
.match(
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
);
};

Related

How to Show API data on React-Select

So, I'm trying to show an Amazon country API to my React-Select component and I've tried to do this in many different ways, but I would only get as result a blank page or a white list on my Select component
The code below has only the Axios method to call the API.
What Should I do so I can show the API data on the Select component?
Here's my Form.jsx component:
import { useState, useEffect } from 'react';
import '../App.css';
import Form from 'react-bootstrap/Form';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import Button from 'react-bootstrap/Button';
import Select from 'react-select';
import Axios from 'axios';
function Forms() {
const [countries, setCountry] = useState([])
Axios.get(`https://amazon-api.sellead.com/country`)
.then(res => {
const countries = res.data;
console.log(countries)
})
return (
<Form>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridEmail">
<Form.Control type="text" name = "name" placeholder="Nome" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="email" name = "email" placeholder="E-mail" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name = "cpf" placeholder="CPF" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name = "tel" placeholder="Telefone" />
</Form.Group>
<Form.Label>País</Form.Label>
<Form.Group as={Col} controlId="formGridPassword">
<Select
/>
</Form.Group>
<Form.Label>Cidade</Form.Label>
<Form.Group as={Col} controlId="formGridPassword"> <br/>
<Select
/>
</Form.Group>
<Button variant="primary" type="submit">
Enviar
</Button>
</Row>
</Form>
);
}
export default Forms;
Hey, First of all, you have to understand that you have to store that data somewhere, The data that you received from API.
Once you store it all you need is just update that in useState([]). That you created.
Now this API you are calling must be called once only so all we need is useEffect() hook with [] an empty array as a dependency so it will only call once the function that is handling API, on initial render.
Once you have data then just loop through it using the map function and render the options.
Here is code.
App.js
import "./styles.css";
import Forms from "./Forms.js";
export default function App() {
return (
<div className="App">
<Forms />
</div>
);
}
Forms.js
import { useState, useEffect } from "react";
import Form from "react-bootstrap/Form";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import Button from "react-bootstrap/Button";
import Select from "react-select";
import Axios from "axios";
function Forms() {
// creating an useState for setting country list received from api
const [countriesList, setCountriesLits] = useState([]);
//async funtion that handling api
const getCountries = async () => {
let contries = []; // to store api data
const countryRes = await Axios.get(
`https://amazon-api.sellead.com/country`
);
countryRes.data.forEach((data) => {
contries.push(data.name);
});
// updating state
setCountriesLits(contries);
};
const handleChange = (e) => {
alert(e.target.value);
};
useEffect(() => {
getCountries();
}, []);
return (
<Form>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridEmail">
<Form.Control type="text" name="name" placeholder="Nome" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="email" name="email" placeholder="E-mail" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name="cpf" placeholder="CPF" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name="tel" placeholder="Telefone" />
</Form.Group>
<Form.Label>País</Form.Label>
<Form.Group as={Col} controlId="formGridPassword">
<select onChange={handleChange}>
{/* rendering option from the state countriesList */}
{countriesList.map((data, i) => (
<option key={i} value={data}>
{data}
</option>
))}
</select>
</Form.Group>
<Form.Label>Cidade</Form.Label>
<Form.Group as={Col} controlId="formGridPassword">
{" "}
<br />
<Select />
</Form.Group>
<Button variant="primary" type="submit">
Enviar
</Button>
</Row>
</Form>
);
}
export default Forms;
You can also visit the working code here on codesandbox
Below is the output:
All you're doing is logging the data to the console (and shadowing a variable):
const countries = res.data;
console.log(countries)
If the data needs to be set in state, set it in state (and you don't need the local variable at all):
setCountry(res.data);
You've also removed the prop from your <Select> component. Clearly you'll need that back:
<Select options={countries} />
As an aside... Names matter. There is a pluralization inconsistency here:
const [countries, setCountry] = useState([])
It's best to keep your names consistent and meaningful, otherwise you end up confusing yourself when you try to use the data. Since this is an array of values, maintain pluralization:
const [countries, setCountries] = useState([]);

React app hanging when typing on input with onChange state

When I start typing anything in the input fields, the page hangs and nothing gets typed. It was working fine before, it just started happening suddenly. I don't know what went wrong.
I have tried adding onBlur and the problem persists. I tried adding value={registerEmail} in the input fields and the problem still remains as well.
Pleae check :(
import React, {useState} from 'react'
import {
createUserWithEmailAndPassword,
onAuthStateChanged,
signInWithEmailAndPassword,
signOut
} from 'firebase/auth'
import { Form, Button, Card, Container } from 'react-bootstrap'
import {auth} from '../../services/firebase-config'
export default function SignUp() {
const [registerEmail, setRegisterEmail] = useState("")
const [registerPassword, setRegisterPassword] = useState("")
const [registerConfirmedPassword, setRegisterConfirmedPassword] = useState("")
const [user, setUser] = useState({})
onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser)
})
const register = async (event) => {
event.preventDefault();
try {
const user = await createUserWithEmailAndPassword(auth, registerEmail, registerPassword)
console.log(user)
}
catch(error) {
//accounts that don't exist
console.log(error.message)
}
}
const login = async(event) => {
event.preventDefault();
try {
const user = await signInWithEmailAndPassword(auth, registerEmail, registerPassword)
console.log(user)
}
catch(error) {
//accounts that don't exist
console.log(error.message)
}
}
const logout = async(event) => {
try {
await signOut(auth)
}
catch(error) {
console.log(error.message)
}
}
return (
<Container className="d-flex align-items-center justify-content-center w-100">
<Card className='p-3' style={{maxWidth:"400px"}}>
<Card.Body>
<h2 className='text-center mb-4'>Sign Up</h2>
<Form>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" onChange={e => setRegisterEmail(e.target.value)} required />
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" onChange={e => setRegisterPassword(e.target.value)} required />
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control type="password" onChange={e => setRegisterConfirmedPassword(e.target.value)} required />
</Form.Group>
{ <Button className='w-100' onClick={(e) => register(e)}>Sign Up</Button>}
</Form>
</Card.Body>
<div className='w-100 text-center mt-2'>
Already have an account? <Button className='w-100' onClick={(e) => login(e)}>Login</Button>
</div>
<Button onClick={(e) => logout(e)}>Logout</Button>
</Card>
</Container>
)
}
Value attr and Initial state was missing in the form.control
<Form>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control value={registerEmail} type="email" onChange={e => setRegisterEmail(e.target.value)} required />
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" value={registerPassword} onChange={e => setRegisterPassword(e.target.value)} required />
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control type="password" onChange={e => setRegisterConfirmedPassword(e.target.value)} required />
</Form.Group>
{ <Button className='w-100' onClick={(e) => register(e)}>Sign Up</Button>}
</Form>
Example - codesandbox

Check React useState() with console.log doesn't work properly

I'm trying to get data from 2 text boxes using react useState. But when I check the console.log, it takes text letters one by one as an array.
create.js
import React, {useState} from 'react'
import { Form, Button, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
export default function Create() {
const[firstName, setFirstName] = useState('');
const[lastName, setLasttName] = useState('');
console.log(firstName);
console.log(lastName);
return (
<div>
<div>create</div>
<div>
<Form>
<Form.Group className="mb-3" >
<Form.Label>First Name</Form.Label>
<Form.Control type="text" name='fName'
onChange={(e)=> setFirstName(e.target.value)}
placeholder="Enter first name" />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Last Name</Form.Label>
<Form.Control type="text" name='lName'
onChange={(e)=> setLasttName(e.target.value)}
placeholder="Enter last name" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</div>
</div>
)
}
App.js
import './App.css';
import Create from './Components/create';
function App() {
return (
<div className="App">
<h2>Hello</h2>
<Create/>
</div>
);
}
export default App;
This is how the console looks like.
Console should be as shown below
The onChange function gets triggered every time the input changes. If you want it to trigger only once, when you are done typing, you can use onBlur this will assign the values only when the input field gets blurred.
Here's a sandbox for you to play with. Make sure you check the console to see when firstName gets updated https://codesandbox.io/s/pedantic-tharp-rfnxqg?file=/src/App.js
I would highly suggest that you check out React Hook Forms
import React, {useState} from 'react'
import { Form, Button, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
export default function Create() {
const[firstName, setFirstName] = useState('');
const[lastName, setLasttName] = useState('');
const submitForm =(e)=>{
console.log(firstName)
console.log(lastName)
e.preventDefault()
}
return (
<div>
<div>create</div>
<div>
<Form onSubmit={(e)=>submitForm(e)}>
<Form.Group className="mb-3" >
<Form.Label>First Name</Form.Label>
<Form.Control type="text" name='fName'
onChange={(e)=> setFirstName(e.target.value)}
placeholder="Enter first name" />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Last Name</Form.Label>
<Form.Control type="text" name='lName'
onChange={(e)=> setLasttName(e.target.value)}
placeholder="Enter last name" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</div>
</div>
)
}

I want to use email value in resetPass function. How can I do that?

I want to sent an email when reset password button is clicked. For that I have created a function named resetPass .I want to get email value in the function. How can I do that?
const Problem = () => {
const [
signInWithEmailAndPassword,
user,
loading,
error,
] = useSignInWithEmailAndPassword(auth, { sendEmailVerification: true });
//reset pass
const [sendPasswordResetEmail] = useSendPasswordResetEmail(
auth
);
//login button
//login button
const handleLogin = event => {
event.preventDefault();
const email = event?.target?.email?.value;
const password = event?.target?.password?.value;
signInWithEmailAndPassword(email, password)
}
//password reset
//password reset
const resetPass = () => {
//email: how to set email ???
sendPasswordResetEmail(auth, email)
.then(console.log('Email sent'))
}
return (
<div>
<Form onSubmit={handleLogin} className='w-50 mx-auto border p-5 m-5 bg-orange-200'>
<h2>Login</h2>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" name='email' placeholder="Enter email" required />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" name='password' required />
</Form.Group>
<h6>Forgot password? <button onClick={resetPass}>Reset Password</button></h6>
<Button variant="primary" type="submit">
Submit
</Button> <br />
<div>
<SocialLogin></SocialLogin>
</div>
</Form>
</div>
);
};
export default Problem;

How to reset form input filed after submit in react js

I want to clear input fields after clicking the submit button. I have used event.target.reset(); But it's not working. I have used React bootstrap form to get input values. Does any solution please? Check below my code.
const addItem = (event) => {
event.preventDefault();
const email = emailRef.current.value;
const name = nameRef.current.value;
const price = priceRef.current.value;
const data = {email, name, price, quantity, description, supplier_name, img }
const url = (`http://localhost:5000/myitems`);
axios.post(url, data)
.then(response =>{
const {data} = response;
if(data.insertedId){
toast('Your Item Added!');
event.target.reset();
}
})
}
return (
<div className='container mx-auto w-50'>
<h2 className='text-center my-3'>Add New Items</h2>
<div className=''>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Control ref={emailRef} type="email" value={user?.email} placeholder="Enter email" disabled/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Control ref={nameRef} type="text" placeholder="Product Title" required/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Control ref={priceRef} type="number" placeholder="Price" required/>
</Form.Group>
<Button onClick={addItem} variant="primary" type="submit">
Add Item
</Button>
</Form>
</div>
</div>
);
};
export default AddItem;
Give the form an id. Then get the id of the form and run the reset() method.
document.getElementById("form-id").reset()
Also, you can give the form a ref. Then call the method current.reset()
const formRef = useRef(null);
<!-- your form -->
<form ref={formRef}>
...
</form>
Finally in your addItem() method, you can call the form ref to clear the form values.
formRef.current.reset()

Resources