react-hook useFormInput() form validation not working - reactjs

Link to code sandbox https://stackblitz.com/edit/react-cdv6mx?devtoolsheight=33&file=src/ResetPassword.js
EXPLANATION: When the user enters incorrect details, the server sends 400: bad request error with a message which can be seen in the Response tab under the network's tab. The intention is to validate the form fields before submitting the form and display an error message(s) if incorrect fields are entered. Also, the intention is to disable to reset the button until the form fields match the criteria. So, that will prevent the user from accidentally submitting half-entered fields.
I have a functional component in which I have a simple form.
PROBLEM: I am calling validatForm() method on onChange. The method should first check that the newPassword and confirmPassword are the same and are as per the password rules(requirements) and if true, only then, send the data.
UPDATED CODE IS IN THE STACKBLITZ LINK ABOVE.
I am use useFormInput() like below
const email = useFormInput("");
const newPassword = useFormInput("");
const confirmPassword = useFormInput("");
and I have written a useFormInput() method
const useFormInput = (initialValue) => {
const [value, setValue] = useState(initialValue);
const handleChange = (e) => {
setValue(e.target.value);
};
return {
value,
onChange: handleChange,
};
};
and a validateForm() method and I am passing it my <button/>
/* Your password must contain at least one capital letter, one
*number and one lowercase letter, and it must contain at least 8
*characters*/
const validateForm = (event) => {
let pass = event.target.value;
let reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;
let test = reg.test(pass);
if (test) {
this.setState({ value: event.target.value });
} else {
alert("password validation unsuccessful. Please try again.");
return;
}
};
and in render()
<FormGroup row>
<Label for="Email" sm={2}>
Email
</Label>
<Col sm={4}>
<Input
type="email"
name="email"
id="Email"
{...email}
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="newPassword" sm={2}>
New Password
</Label>
<Col sm={4}>
<Input
type="password"
name="password"
id="newPassword"
{...newPassword}
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="confirmPassword" sm={2}>
Confirm Password
</Label>
<Col sm={4}>
<Input
type="password"
name="confirmPassword"
id="confirmPassword"
{...confirmPassword}
/>
</Col>
</FormGroup>
<div className="form-actions">
{error && (
<>
<small style={{ color: "red" }}>{error}</small>
<br />
</>
)}
<br />
<Col lg={{ offset: 2 }} sm={{ size: 1 }}>
<Button
className="mail-reset-btn"
block
type="submit"
value={loading ? "Loading..." : "Login"}
onClick={handleReset}
disabled={!validateForm}
>
Reset
</Button>
</Col>
</div>
</Form>

Update your validateForm to destructure the password fields from the form onSubmit event. Create an errors object to track what field errors there are. If the errors object is empty then validation passes, otherwise set error state.
const validateForm = event => {
event.preventDefault();
const { confirmPassword, newPassword } = event.target;
const errors = {};
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;
if (!regex.test(newPassword.value)) {
errors.requirementUnmet = "New password does not meet requirements.";
}
if (newPassword.value !== confirmPassword.value) {
errors.passwordMismatch = "Entered passwords do not match.";
}
if (!Object.keys(errors).length) {
alert("password validation successful.");
setError(null);
return;
}
setError(errors);
};
Attach validateForm to the form's onSubmit handle.
<Form onSubmit={validateForm}>
Ensure you've a type="submit" button in the form.
<Button
className="mail-submit-btn"
block
type="submit"
value={loading ? "Loading..." : "Login"}
>
Submit
</Button>
Updated stackblitz (though I've not an account so copying updated code below.)
Note: I simply JSON.stringify(error) the error for simplicity, but you'll want to render this more gracefully.
Entire ResetPassword.js
import React, { useState } from "react";
import {
Button,
Form,
FormGroup,
Input,
Col,
Label,
Modal,
ModalHeader,
ModalBody,
ModalFooter
} from "reactstrap";
const useFormInput = initialValue => {
const [value, setValue] = useState(initialValue);
const handleChange = e => {
setValue(e.target.value);
};
return {
value,
onChange: handleChange
};
};
const ResetPassword = props => {
// form inputs
const email = useFormInput("");
const newPassword = useFormInput("");
const confirmPassword = useFormInput("");
// using hooks
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
const validateForm = event => {
event.preventDefault();
const { confirmPassword, newPassword } = event.target;
const errors = {};
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;
if (!regex.test(newPassword.value)) {
errors.requirementUnmet = "New password does not meet requirements.";
}
if (newPassword.value !== confirmPassword.value) {
errors.passwordMismatch = "Entered passwords do not match.";
}
if (!Object.keys(errors).length) {
alert("password validation successful.");
setError(null);
return;
}
setError(errors);
};
const handleReset = e => {
e.preventDefault();
setError(null);
setLoading(true);
// some unrelated redux code
};
return (
<div className="mail-reset" id="forgotPassword">
<div className="mail-reset-content">
<Form onSubmit={validateForm}>
<h3 className="form-title">Enter Information</h3>
<FormGroup row>
<Label for="Email" sm={2}>
Email
</Label>
<Col sm={4}>
<Input
type="email"
name="email"
id="Email"
placeholder="Email"
aria-label="email address"
aria-describedby="email address"
aria-invalid="false"
{...email}
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="newPassword" sm={2}>
New Password
</Label>
<Col sm={4}>
<Input
type="password"
name="password"
id="newPassword"
placeholder="New Password"
aria-label="new password"
aria-describedby="new password"
aria-invalid="false"
{...newPassword}
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="confirmPassword" sm={2}>
Confirm Password
</Label>
<Col sm={4}>
<Input
type="password"
name="confirmPassword"
id="confirmPassword"
placeholder="Confirm Password"
aria-label="new password"
aria-describedby="new password"
aria-invalid="false"
{...confirmPassword}
/>
</Col>
</FormGroup>
<div className="modal-wrapper">
<Col sm={{ size: 4, offset: 2 }}>
<Button onClick={toggle} className="passwordReqBtn">
Password Requirements
</Button>
</Col>
<Modal isOpen={modal} toggle={toggle} className="mail-reset-modal">
<ModalHeader toggle={toggle}>Password Requirements</ModalHeader>
<ModalBody>
Your password must contain at least one capital letter, one
number and one lowercase letter, and it must contain at least 8
characters
</ModalBody>
<ModalFooter>
<Button onClick={toggle} className="btn-modal pull-right">
OK
</Button>{" "}
</ModalFooter>
</Modal>
</div>
<div className="form-actions">
{error && (
<>
<small style={{ color: "red" }}>{JSON.stringify(error)}</small>
<br />
</>
)}
<br />
<Col lg={{ offset: 2 }} sm={{ size: 1 }}>
<Button
className="mail-reset-btn"
block
type="submit"
value={loading ? "Loading..." : "Login"}
>
Submit
</Button>
<Button
className="mail-reset-btn"
block
type="reset"
value={loading ? "Loading..." : "Login"}
onClick={handleReset}
>
Reset
</Button>
</Col>
</div>
</Form>
</div>
</div>
);
};
export default ResetPassword;

Related

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

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()

How to add edit button and function in react.js

i want to share this question. So, i have a form which is designed by react-bootstrap. And also use React Hooks and React Function Component. I have a form which is add new form and delete form but i don't do edit form.
This is a return statement
return(
<Container>
<Row>
<Col>
<Form onSubmit={handleSubmit}>
<Form.Group>
<Form.Label>Name</Form.Label>
<Form.Control ref = {firstname} type="text" placeholder="Name.." />
</Form.Group>
<Form.Group>
<Form.Label>Surname</Form.Label>
<Form.Control ref = {secondname} type="text" placeholder="Surname.." />
</Form.Group>
<Form.Group>
<Form.Label>Email address</Form.Label>
<Form.Control ref = {email} type="email" placeholder="E-Mail" />
<Form.Text> Please, Enter like "asd#asd.com"</Form.Text>
</Form.Group>
<Form.Group>
<Form.Label>Comment</Form.Label>
<Form.Control ref = {comment} as="textarea" rows={3} placeholder = "Notes :)"/>
</Form.Group>
<Button className = "btn-lg" onClick={handleSubmit} variant="success" type="submit">Submit</Button>
</Form>
</Col>
</Row>
{Formss}
</Container>
)
And then, These are the function of this return
const Formss = input.map((item , index) =>
{
return(
<Lists key = {index} item = {item} index = {index} deleteFunc={handleDelete}/>
)
}
)
const handleSubmit = (event) => {
event.preventDefault();
const name = firstname.current.value
const surname = secondname.current.value
const mail = email.current.value
const mycomment = comment.current.value
const data = {id:id(),
name : name,
surname : surname,
mail : mail,
mycomment : mycomment}
if(data.name && data.surname && data.mail && data.mycomment){
setInput([...input, data])
firstname.current.value = ""
secondname.current.value = ""
email.current.value = ""
comment.current.value =""
}else{
console.log("oopss")
}
}
I use ref hook for handleSubmit. So, How to add edit button and edit function?
To be able to edit data, and to save it in state you can do it as in provided example. Then in handleSubmit function you can process your data further:
import React from "react";
import { Container, Row, Col, Form, Button } from "react-bootstrap";
const App = () => {
const handleSubmit = (e) => {
e.preventDefault();
console.log(state);
};
const initialState = {
firstname: "",
secondname: "",
email: "",
comment: "",
};
const [state, setState] = React.useState(initialState);
const handleChange = ({ target: { value, name } }) => {
setState({ ...state, [name]: value });
};
return (
<Container>
<Row>
<Col>
<Form onSubmit={handleSubmit}>
<Form.Group>
<Form.Label>Name</Form.Label>
<Form.Control
name="firstname"
value={state.firstname}
type="text"
placeholder="Name.."
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>Surname</Form.Label>
<Form.Control
name="secondname"
value={state.secondname}
type="text"
placeholder="Surname.."
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>Email address</Form.Label>
<Form.Control
value={state.email}
name="email"
type="email"
placeholder="E-Mail"
onChange={handleChange}
/>
<Form.Text> Please, Enter like "asd#asd.com"</Form.Text>
</Form.Group>
<Form.Group>
<Form.Label>Comment</Form.Label>
<Form.Control
name="comment"
value={state.comment}
as="textarea"
rows={3}
placeholder="Notes :)"
onChange={handleChange}
/>
</Form.Group>
<Button className="btn-lg" variant="success" type="submit">
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
);
};
export default App;

How Can I Get Form/Submit To Work with ReactStrap in a React functional component?

I like how Reactstrap handles Modal so I want to keep using it, but I can't figure out how to get the data out of a form and capture it in state.
const handleSubmit = (evt) => {
evt.preventDefault();
alert(`Submitting Name ${name}`);
};
With Reactstrap
<Form onSubmit={handleSubmit}>
<FormGroup>
<Label for="firstname">First Name</Label>{' '}
<Input name="speakername"></Input>
</FormGroup>
</Form>
When I use standard form and input elements, I'm able to capture what I need in handleSubmit, but I can't figure out how to do the same thing with the Form and Input tags of Reactstrap
Regular form and input elements
<form onSubmit={handleSubmit}>
<label>
First Name:
<input
type="text"
value={name}
onChange={e => setName(e.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
I was having exactly the same problem. Seemed to have fixed it as follows...
(I believe all you're missing are the value & onChange props for the Input component, and possibly the useState hooks for setName()... )
--- Set state ---
const currentDate = findDate();
function findDate() {
let d = new Date(),
month = "" + (d.getMonth() + 1),
day = "" + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = "0" + month;
if (day.length < 2) day = "0" + day;
return [year, month, day].join("-");
}
console.log(typeof currentDate);
const UpdateCount = () => {
const [date, setDate] = useState(currentDate);
const [hactCount, setHactCount] = useState("");
--- Handle Submit function ---
const handleSubmit = (e) => {
e.preventDefault();
alert(`${hactCount} hacts on ${date}`);
};
--- Return from functional component ---
return (
<div>
<Card>
<CardTitle className="border-bottom p-3 mb-0">
<i className="mdi mdi-priority-low mr-2"></i>Update your Hact Count
</CardTitle>
<CardBody>
<CardSubtitle className="py-2">
Insert your day's count and we'll do the magic
</CardSubtitle>
<Form onSubmit={handleSubmit}>
<FormGroup>
Date:
<Input
className="mt-2 mb-4"
type="date"
value={date}
onChange={(e) => {
setDate(e.target.value);
console.log(typeof e.target.value);
}}
/>
Count:
<Input
className="my-2 mb-4"
type="number"
placeholder="0"
value={hactCount}
onChange={(e) => {
setHactCount(e.target.value);
console.log(e.target.value);
}}
/>
<br />
<InputGroup className="text-center">
<Button className="text-center" color="primary" type="submit">
Update
</Button>
</InputGroup>
</FormGroup>
</Form>
</CardBody>
</Card>
</div>
);
Add a Button component with type=submit to your reactstrap form the same way you had an <input> with type=submit so that React know's to fire the onSubmit handler when the Button is clicked.
import { Form, FormGroup, Input, Label, Button } from "reactstrap";
<Form onSubmit={handleSubmit}>
<FormGroup>
<Label for="firstname">First Name</Label>{' '}
<Input name="speakername"></Input>
</FormGroup>
<Button type="submit">Submit</Button>
</Form>
you should be able using innerRef
onFormSubmit = (e) => {
e.preventDefault()
console.log(this.emailInputValue)
}
<Form onSubmit={this.onFormSubmit}>
<FormGroup>
<Label >Email:</Label>
<Input innerRef={(node) => this.emailInputValue = node} type="email" name="email" " placeholder="Email" />
<Button type="submit" color="primary" >Submit</Button>
</Form>
You can get the value by referring to the name key and ID of the input.
Exmaple
onFormSubmit = (e) => {
e.preventDefault()
console.log(e.target.company.value)
console.log(e.target.name.value)
}
<Modal isOpen={isModalVisible} toggle={handleModal}>
<ModalHeader toggle={handleModal}>add modal</ModalHeader>
<ModalBody>
<Form onSubmit={onFinish}>
<FormGroup>
<Label for="company">company</Label>
<Input type={"text"} name={"company"} id={"company"} placeholder={"company"} />
</FormGroup>
<FormGroup>
<Label for="name">name</Label>
<Input type={"text"} name={"name"} id={"name"} placeholder={"name"} />
</FormGroup>
<Button type="submit" color={"primary"}>
save
</Button>
</Form>
</ModalBody>
</Modal>

How to show default value in console in react?

I am working on a React project, In that Project I have a form, In that form I have two Input
Tags. For first input tag I defined the value, For the second input tag I am assigning value by
using state. Now I am trying to console values of two Input tags but I am getting only second
Input tag value. So someone please help me to get Two Input tag values from form
This is Form.js
import React, { useState } from 'react';
import './aum-company-modal.css';
import Aumservice from '../../service/aum-service';
import { Button, Col, Modal, ModalBody,ModalFooter, ModalHeader, Row, FormGroup, Label, Input, } from 'reactstrap';
const AumCompanyModal = (props) => {
const [data, sendData] = useState({})
const [firstInputValue] = useState('1000')
const [inputValue, setInputValue] = useState('');
const handleChange = ({target}) => {
const { name, value } = target;
console.warn(name,value)
const newData = Object.assign({}, data, { [name]: value })
sendData(newData)
if (value > -1 && value < 100000000000000000000000000000000000) {
setInputValue(value);
}
}
const handleSubmit = (e) => {
e.preventDefault()
console.log(data)
}
return (
<Row>
<Col md="6" sm="6" xs="6">
<Modal isOpen={props.openModal}
>
<ModalHeader >Add new</ModalHeader>
<ModalBody>
<Row>
<Col md="12" sm="12" xs="12">
<FormGroup>
<Label for="exampleName">Min Value</Label>
<Input
type="text"
name="minValue"
placeholder="Enter minimum value"
value={firstInputValue}
/>
</FormGroup>
<FormGroup>
<Label for="exampleName">Max Value</Label>
<Input
type="number"
name="maxValue"
placeholder="Enter maximum value"
min='1000' max='100000000000000000000000000000000000'
value={inputValue}
onChange={handleChange}
/>
</FormGroup>
</Col>
</Row>
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={props.closeModal}>
Cancel
</Button>
<Button type="submit" onClick={handleSubmit} color="primary">
Submit
</Button>
</ModalFooter>
</Modal>
</Col>
</Row>
)
}
export default AumCompanyModal
If you have any doubt please put a comment.
If for some reason, you need to hard code some value, use state variable as value and then you will have that variable in handleSubmit. Or you can use ref and get value from that ref
const [firstValue] = useState('100');
<Input
type="text"
name="minValue"
placeholder="Enter minimum value"
value={firstValue}
/>
Or you can use React.useRef()
const firstInput = React.useRef();
<Input
type="text"
name="minValue"
placeholder="Enter minimum value"
value="1000"
ref={firstInput}
/>
// in handleSubmit
const handleSubmit = (e) => {
e.preventDefault()
console.log(firstInput.current.value)
}

Resources