react state can not read property - javascript

I am facing an issue with react , it worked with individual usestates but when I made it as an object it failed , and this is the code :
import React, { useState } from 'react'
import {Link} from "react-router-dom"
import {DatabaseNetworkPoint} from '#icon-park/react';
import axios from "axios"
export default function Register() {
const [user, setUser] = useState({
username:"",
email:"",
password:"",
age:0,
gender:"",
})
const [file, setFile] = useState(null)
const handleChange = (event) => {
console.log(event.target.value)
setUser({
username:event.target.value,
email:event.target.value,
password:event.target.value,
age:event.target.value,
gender:event.target.value,
img:event.target.files[0]
})
setFile(event.target.files[0])
}
const handleSubmit = (event) => {
event.preventDefault()
console.log('button clicked', event.target)
}
return (
<div className='container'>
<div className='left'>
<div className='logo'>
<DatabaseNetworkPoint theme="outline" size="150" fill="#333"/>
<h1>WonderHit</h1>
</div>
<form className='form' onSubmit={handleSubmit}>
<input placeholder='Username' value={user.username} className='field' type="text" onChange={handleChange} />
<input placeholder='Email' value={user.email} className='field' type="email" onChange={handleChange} />
<input placeholder='Password' value={user.password} className='field' type="password" onChange={handleChange} />
<input placeholder='Age' value={user.age} className='field' name='age' type="number" onChange={handleChange} />
<input placeholder='Gender' value={user.gender} className='field' name='gender' type="text" onChange={handleChange} />
<div className='profilePic'>
<div className='Photo'></div>
<input className='field2' id='file' type="file" onChange={handleChange} />
<label htmlFor = "file" className='uploadPic' >+</label>
</div>
<button className='submit' type="submit">Register</button>
<h3 className='routing'>You already have an account ? <Link className='rot' to="/">Login</Link></h3>
</form>
</div>
<img className='right' src='https://images.unsplash.com/photo-1562577309-4932fdd64cd1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1074&q=80' />
</div>
)
}
and this is the error Iam getting :
Uncaught TypeError: Cannot read properties of null (reading '0')
what might be the problem ?? is it the file thats causing me issues ? should I handle it as string ??????

img:event.target.files[0]
You're calling handleChange for every <input>, whether it's a file type or not.

Use a different handler, don't use the same handler(handleChange) for every input change, the issue is coming because of another field change file type input returning null.
Use another handler for the upload file and set it to use of useState and use it for a later use case.

It's because this line setFile(event.target.files[0]) you should first check existing of event.target.files then set it in your state;
event.target.files && setFile(event.target.files[0])

Maybe you can add a check to your handleChange(event)'s event, and make a conditional setting to your user state. Also remember using new object when setting user state, because you would like to save the other input's state in your user
const handleChange = (event) => {
if(event.target.placeholder === 'Username'){
// đź“Ś use {...user, [update]: event.target.value }
setUser({...user, username:event.target.value });
}
//else if (){ ...other input}
if(event.target.id = 'file'){
setFile(event.target.files[0])
}
}
a simple example:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
function App () {
const [user, setUser] = React.useState({});
const handleChange = (e) => {
if (e.target.placeholder === "Username") {
setUser({...user, username: e.target.value});
}
if (e.target.placeholder === "Email") {
setUser({...user, email: e.target.value});
}
if (e.target.placeholder === "Password") {
setUser({...user, password: e.target.value});
}
if (e.target.placeholder === "Age") {
setUser({...user, age: e.target.value});
}
if (e.target.placeholder === "Gender") {
setUser({...user, gender: e.target.value});
}
console.log(e.target);
if(e.target.id === "file"){
if (e.target.files) {
const img = document.getElementById("img");
console.log(img);
img.src = URL.createObjectURL(e.target.files[0]);
}
}
}
return <div>
<div>Inputs</div>
<input placeholder='Username' value={user.username} className='field' type="text" onChange={handleChange} />
<input placeholder='Email' value={user.email} className='field' type="email" onChange={handleChange} />
<input placeholder='Password' value={user.password} className='field' type="password" onChange={handleChange} />
<input placeholder='Age' value={user.age} className='field' name='age' type="number" onChange={handleChange} />
<input placeholder='Gender' value={user.gender} className='field' name='gender' type="text" onChange={handleChange} />
<div>file (only accept photo)</div>
<input id="file" type="file" accept="image/*" onChange={handleChange}></input>
<div>User Object's props</div>
<div>user.username: {user.username}</div>
<div>user.email: {user.email}</div>
<div>user.password: {user.password}</div>
<div>user.age: {user.age}</div>
<div>user.gender: {user.gender}</div>
<br />
<div>image display</div>
<img id="img"></img>
</div>
}
</script>
<script type="text/babel">
ReactDOM.render(
<App></App>
, document.getElementById("root"));
</script>

Related

I want to reset my form after clicking submit in reactjs. I have tried making another method. but it does not work

import React,{ useState} from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
import axios from 'axios';
const Create = () => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [checkbox, setCheckBox] = useState(false);
Here I am sending data to a mock api I created
const postData = () =>{
axios.post(`https://61cb2af8194ffe0017788c01.mockapi.io/fakeData`,{
firstName,
lastName,
checkbox
})
}
This is the method I created to reset the form but it does not work.
const resetForm = () => {
postData();
setFirstName(" ");
setLastName(" ");
setCheckBox(false);
}
This is my form where on click i am calling resetForm function but it is not resetting it
is sending the data but not resetting the form.
return(
<div>
<Form>
<Form.Field>
<label>First Name</label>
<input id="f1" placeholder='First Name' onChange={(e)=>setFirstName(e.target.value) } />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input id="last1" placeholder='Last Name' onChange={(e)=>setLastName(e.target.value)}/>
</Form.Field>
<Form.Field>
<Checkbox id="c1" label='I agree to the Terms and Conditions' onChange={(e)=>setCheckBox(!checkbox)}/>
</Form.Field>
<Button type='submit' onClick={resetForm}>Submit</Button>
</Form>
<br></br>
<Button onClick={()=>navigate(-1)}>Go Back</Button>
</div>
)
}
export default Create;
Actually it will reset the form, the problem is you do not use Controlled Components to show the latest update value in UI
you should bind the value like this:
<input type="text" value={this.state.value} onChange={this.handleChange} />
You can refer the doc here:
https://reactjs.org/docs/forms.html
You can reset your form using the native form.reset() method.
const Create = () => {
const ref = React.useRef(null);
const resetForm = () => ref.current.reset();
return (
<div>
<Form ref={ref}>
<Form.Field>
<label>First Name</label>
<input id="f1" placeholder="First Name" onChange={(e) => setFirstName(e.target.value)} />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input id="last1" placeholder="Last Name" onChange={(e) => setLastName(e.target.value)} />
</Form.Field>
<Form.Field>
<Checkbox
id="c1"
label="I agree to the Terms and Conditions"
onChange={(e) => setCheckBox(!checkbox)}
/>
</Form.Field>
<Button type="submit" onClick={resetForm}>
Submit
</Button>
</Form>
<br></br>
<Button onClick={() => navigate(-1)}>Go Back</Button>
</div>
);
};
export default Create;
For that, you have to set value property in your input. Try this
const Create = () => {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [checkbox, setCheckBox] = useState(false);
const postData = () => {
console.log(firstName, lastName, checkbox);
};
const resetForm = () => {
postData();
setFirstName(" ");
setLastName(" ");
setCheckBox(false);
};
return (
<div>
<Form>
<Form.Field>
<label>First Name</label>
<input
id="f1"
placeholder="First Name"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input
id="last1"
placeholder="Last Name"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
</Form.Field>
<Form.Field>
<Checkbox
id="c1"
label="I agree to the Terms and Conditions"
checked={checkbox}
onChange={(e) => setCheckBox(!checkbox)}
/>
</Form.Field>
<Button type="submit" onClick={resetForm}>
Submit
</Button>
</Form>
</div>
);
};

reactjs clear file input field after submit

I'm trying to delete my file input field data from e.target but i need the rest of the e.target data to send to emailjs.
The problem is when user uploads a file in my form, the file is most of the time bigger than 50kb and this is the limit for my account on emailjs.
I don't need to send my file to emailjs but i need it to just be stored in my database.
I have tried to clear the form field before sending it to emailjs
with fileUpload.current.value = ""; but the data is still actief in
e.target.
This is e.target Data. i need the data to stay in this way in e.target to send to emailjs
<form class="Grade_inputForm__1lbhQ" autocomplete="off">
<div class="Grade_input_container__3ztZk css-vurnku">
<input type="text" name="name" required="" class="Grade_input__22PTE" placeholder="Name*" maxlength="10">
</div>
<div class="Grade_input_container__3ztZk css-vurnku">
<input type="email" required="" name="email" class="Grade_input__22PTE" placeholder="Email*">
</div>
<div class="Grade_input_container__3ztZk css-vurnku">
<input type="text" name="Address" required="" class="Grade_input__22PTE" placeholder="Address*">
</div>
<div class="Grade_input_container__3ztZk css-vurnku">
<input type="tel" name="phone" class="Grade_input__22PTE" placeholder="Phone">
</div>
<div class="Grade_input_container__3ztZk css-vurnku">
<input type="file" class="Grade_input__22PTE" name="5349366.jpg">
</div>
<div class="Grade_textarea__YR0na css-vurnku">
<textarea name="cards" required="" class="Grade_input__22PTE">
</textarea>
</div>
<div class="Grade_textarea__YR0na css-vurnku">
<textarea name="message" class="Grade_input__22PTE" placeholder="Message">
</textarea>
</div>
<br>
<input type="submit" value="Send" class="Grade_btn__1QKUn">
</form>
how can i delete my file from e.target ?
import React, { useRef, useState } from "react";
import { jsx, Box } from "theme-ui";
import style from "../../style/Grade.module.css";
import { db, storage } from "../components/config/config";
import emailjs from "emailjs-com";
export default function GradeCards() {
const [file, setFile] = useState();
const name = useRef("");
const email = useRef("");
const Addres = useRef("");
const phone = useRef("");
const cards = useRef("");
const message = useRef("");
const fileUpload = useRef("");
const sendEmail = (e) => {
e.preventDefault();
//sending data to emailjs with e.target
emailjs
.sendForm(
"service account",
"template name",
e.target,
"user_id"
)
.then(
(result) => {
console.log(result.text);
},
(error) => {
console.log(error.text);
}
);
};
const sendDataToDb = (e) => {
// sendEmail(e);
e.preventDefault();
e.persist(); // this is test when i use sendEmail() in .then()
const formData = new FormData(e.target);
const obj = {};
for (let [key, value] of formData.entries()) {
obj[key] = value;
}
if (file !== null) {
storage
.ref(`/files/${Date.now() + "-" + file.name}`)
.put(file)
.then(() => console.log("Succes"));
}
//this don't help in deleting data from e.target
delete obj[file.name];
db.collection("collectionName")
.add(obj)
.then(() => {
fileUpload.current.value = "";
})
.then(() => {
//test if the data is deleted her.But its still actief in e.target
console.log(e.target);
sendEmail(e);
})
.then(() => {
name.current.value = "";
email.current.value = "";
Addres.current.value = "";
phone.current.value = "";
cards.current.value = "";
message.current.value = "";
console.log("done sending");
});
};
return (
<section>
<Box className={style.container}>
<Box className={style.form}>
<Box className={style.contact_form}>
<form
onSubmit={(e) => sendDataToDb(e)}
className={style.inputForm}
autoComplete="off"
>
<Box className={style.input_container}>
<input
ref={name}
type="text"
name="name"
required
className={style.input}
placeholder="Name*"
maxLength="10"
/>
</Box>
<Box className={style.input_container}>
<input
ref={email}
type="email"
required
name="email"
className={style.input}
placeholder="Email*"
/>
</Box>
<Box className={style.input_container}>
<input
ref={Addres}
type="text"
name="Address"
required
className={style.input}
placeholder="Address*"
/>
</Box>
<Box className={style.input_container}>
<input
ref={phone}
type="tel"
name="phone"
className={style.input}
placeholder="Phone"
/>
</Box>
<Box className={style.input_container}>
<input
ref={fileUpload}
type="file"
name={file?.name}
onChange={(e) => {
setFile(e.target.files[0]);
}}
className={style.input}
/>
</Box>
<Box className={(style.input_container, style.textarea)}>
<textarea
ref={cards}
name="cards"
required
className={style.input}
></textarea>
</Box>
<Box className={(style.input_container, style.textarea)}>
<textarea
ref={message}
name="message"
className={style.input}
placeholder="Message"
></textarea>
</Box>
<br />
<input type="submit" value="Send" className={style.btn} />
</form>
</Box>
</Box>
</Box>
</section>
);
}
I don't know how you can set it here, but in general, if you have an input of type file and with name let's say image2, then you can do the following:
e.target["image2"].value = [];
this will empty the input.
See this sandbox
If you comment out the previous line of code, it will display the full details of the chosen file.
If you have this line there, it will display the object as it was never assigned a file from your disk.

Cannot read property 'value' of null in ReactJS

I've been trying to console.log these 2 inputs, but can't seem to figure it out, can anyone tell me what I've done wrong?
I keep getting the Cannot read property 'value' of null error
function printInputs() {
let username = document.getElementById('user').value
let password = document.getElementById('pass').value
console.log(username);
console.log(password);
}
function App() {
return (
<div className="App">
<h1>Log In</h1>
<h1>{code}</h1>
<form>
<input className='userInput' id='user' type='text' placeholder='username' /><br />
<input className='userInput' id='pass' type='password' placeholder='password' /><br />
<input className='userSubmit' type='submit' value='Log In' onSubmit={printInputs()} />
</form>
</div>
);
}
onSubmit={printInputs()}
You are trying to call printInputs immediately (before the render function has returned anything so before the inputs are in the page).
You need to pass a function to onSubmit:
onSubmit={printInputs}
That said, this is not the approach to take for getting data from forms in React. See the Forms section of the React guide for the right approach.
The way to write forms in react. Working example demo
function App() {
const [state, setState] = React.useState({ username: "", password: "" });
const handleSubmit = e => {
e.preventDefault();
console.log(state);
};
const handleChange = e => {
setState({
...state,
[e.target.name]: e.target.value
});
};
return (
<div className="App">
<h1>Log In</h1>
<form onSubmit={handleSubmit}>
<input
className="userInput"
name="username"
type="text"
placeholder="username"
onChange={handleChange}
/>
<br />
<input
className="userInput"
name="password"
type="password"
placeholder="password"
onChange={handleChange}
/>
<br />
<input className="userSubmit" type="submit" value="Log In" />
</form>
</div>
);
}
in the first never use real dom to manipulate the dom in
React ,use a state to get de value and the onSumbit is used in Form tag
import React, { useState } from "React";
const App = () => {
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
const printInputs = () => {
console.log(userName);
console.log(password);
};
return (
<div className="App">
<h1>Log In</h1>
<form onSubmit={printInputs}>
<input
className="userInput"
id="user"
type="text"
placeholder="username"
onChange={event => setUserName(event.target.value)}
/>
<br />
<input
className="userInput"
id="pass"
type="password"
placeholder="password"
onChange={event => setPassword(event.target.value)}
/>
<br />
<input
className="userSubmit"
type="submit"
value="Log In"/>
</form>
</div>
);
};
export default App;

How do I add validation to the form in my React component?

My Contact page form is as follows,
<form name="contactform" onSubmit={this.contactSubmit.bind(this)}>
<div className="col-md-6">
<fieldset>
<input ref="name" type="text" size="30" placeholder="Name"/>
<br/>
<input refs="email" type="text" size="30" placeholder="Email"/>
<br/>
<input refs="phone" type="text" size="30" placeholder="Phone"/>
<br/>
<input refs="address" type="text" size="30" placeholder="Address"/>
<br/>
</fieldset>
</div>
<div className="col-md-6">
<fieldset>
<textarea refs="message" cols="40" rows="20"
className="comments" placeholder="Message"/>
</fieldset>
</div>
<div className="col-md-12">
<fieldset>
<button className="btn btn-lg pro" id="submit"
value="Submit">Send Message</button>
</fieldset>
</div>
</form>
Need to add validation for all fields. Can anyone help me to add validation in this react form?
You should avoid using refs, you can do it with onChange function.
On every change, update the state for the changed field.
Then you can easily check if that field is empty or whatever else you want.
You could do something as follows :
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
fields: {},
errors: {},
};
}
handleValidation() {
let fields = this.state.fields;
let errors = {};
let formIsValid = true;
//Name
if (!fields["name"]) {
formIsValid = false;
errors["name"] = "Cannot be empty";
}
if (typeof fields["name"] !== "undefined") {
if (!fields["name"].match(/^[a-zA-Z]+$/)) {
formIsValid = false;
errors["name"] = "Only letters";
}
}
//Email
if (!fields["email"]) {
formIsValid = false;
errors["email"] = "Cannot be empty";
}
if (typeof fields["email"] !== "undefined") {
let lastAtPos = fields["email"].lastIndexOf("#");
let lastDotPos = fields["email"].lastIndexOf(".");
if (
!(
lastAtPos < lastDotPos &&
lastAtPos > 0 &&
fields["email"].indexOf("##") == -1 &&
lastDotPos > 2 &&
fields["email"].length - lastDotPos > 2
)
) {
formIsValid = false;
errors["email"] = "Email is not valid";
}
}
this.setState({ errors: errors });
return formIsValid;
}
contactSubmit(e) {
e.preventDefault();
if (this.handleValidation()) {
alert("Form submitted");
} else {
alert("Form has errors.");
}
}
handleChange(field, e) {
let fields = this.state.fields;
fields[field] = e.target.value;
this.setState({ fields });
}
render() {
return (
<div>
<form
name="contactform"
className="contactform"
onSubmit={this.contactSubmit.bind(this)}
>
<div className="col-md-6">
<fieldset>
<input
ref="name"
type="text"
size="30"
placeholder="Name"
onChange={this.handleChange.bind(this, "name")}
value={this.state.fields["name"]}
/>
<span style={{ color: "red" }}>{this.state.errors["name"]}</span>
<br />
<input
refs="email"
type="text"
size="30"
placeholder="Email"
onChange={this.handleChange.bind(this, "email")}
value={this.state.fields["email"]}
/>
<span style={{ color: "red" }}>{this.state.errors["email"]}</span>
<br />
<input
refs="phone"
type="text"
size="30"
placeholder="Phone"
onChange={this.handleChange.bind(this, "phone")}
value={this.state.fields["phone"]}
/>
<br />
<input
refs="address"
type="text"
size="30"
placeholder="Address"
onChange={this.handleChange.bind(this, "address")}
value={this.state.fields["address"]}
/>
<br />
</fieldset>
</div>
</form>
</div>
);
}
}
React.render(<Test />, document.getElementById("container"));
In this example I did the validation only for email and name, but you have an idea how to do it. For the rest you can do it self.
There is maybe a better way, but you will get the idea.
Here is fiddle.
Try this, example,
the required property in the below input tag will ensure that the name field shouldn't be submitted empty.
<input type="text" placeholder="Your Name" required />
I've taken your code and adapted it with library react-form-with-constraints: https://codepen.io/tkrotoff/pen/LLraZp
const {
FormWithConstraints,
FieldFeedbacks,
FieldFeedback
} = ReactFormWithConstraints;
class Form extends React.Component {
handleChange = e => {
this.form.validateFields(e.target);
}
contactSubmit = e => {
e.preventDefault();
this.form.validateFields();
if (!this.form.isValid()) {
console.log('form is invalid: do not submit');
} else {
console.log('form is valid: submit');
}
}
render() {
return (
<FormWithConstraints
ref={form => this.form = form}
onSubmit={this.contactSubmit}
noValidate>
<div className="col-md-6">
<input name="name" size="30" placeholder="Name"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="name">
<FieldFeedback when="*" />
</FieldFeedbacks>
<input type="email" name="email" size="30" placeholder="Email"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="email">
<FieldFeedback when="*" />
</FieldFeedbacks>
<input name="phone" size="30" placeholder="Phone"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="phone">
<FieldFeedback when="*" />
</FieldFeedbacks>
<input name="address" size="30" placeholder="Address"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="address">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="col-md-6">
<textarea name="comments" cols="40" rows="20" placeholder="Message"
required minLength={5} maxLength={50}
onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="comments">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="col-md-12">
<button className="btn btn-lg btn-primary">Send Message</button>
</div>
</FormWithConstraints>
);
}
}
Screenshot:
This is a quick hack. For a proper demo, check https://github.com/tkrotoff/react-form-with-constraints#examples
import React from 'react';
import {sendFormData} from '../services/';
class Signup extends React.Component{
constructor(props){
super(props);
this.state = {
isDisabled:true
}
this.submitForm = this.submitForm.bind(this);
}
validateEmail(email){
const pattern = /[a-zA-Z0-9]+[\.]?([a-zA-Z0-9]+)?[\#][a-z]{3,9}[\.][a-z]{2,5}/g;
const result = pattern.test(email);
if(result===true){
this.setState({
emailError:false,
email:email
})
} else{
this.setState({
emailError:true
})
}
}
handleChange(e){
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
if(e.target.name==='firstname'){
if(e.target.value==='' || e.target.value===null ){
this.setState({
firstnameError:true
})
} else {
this.setState({
firstnameError:false,
firstName:e.target.value
})
}
}
if(e.target.name==='lastname'){
if(e.target.value==='' || e.target.value===null){
this.setState({
lastnameError:true
})
} else {
this.setState({
lastnameError:false,
lastName:e.target.value
})
}
}
if(e.target.name==='email'){
this.validateEmail(e.target.value);
}
if(e.target.name==='password'){
if(e.target.value==='' || e.target.value===null){
this.setState({
passwordError:true
})
} else {
this.setState({
passwordError:false,
password:e.target.value
})
}
}
if(this.state.firstnameError===false && this.state.lastnameError===false &&
this.state.emailError===false && this.state.passwordError===false){
this.setState({
isDisabled:false
})
}
}
submitForm(e){
e.preventDefault();
const data = {
firstName: this.state.firstName,
lastName: this.state.lastName,
email: this.state.email,
password: this.state.password
}
sendFormData(data).then(res=>{
if(res.status===200){
alert(res.data);
this.props.history.push('/');
}else{
}
});
}
render(){
return(
<div className="container">
<div className="card card-login mx-auto mt-5">
<div className="card-header">Register here</div>
<div className="card-body">
<form id="signup-form">
<div className="form-group">
<div className="form-label-group">
<input type="text" id="firstname" name="firstname" className="form-control" placeholder="Enter firstname" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="firstname">firstname</label>
{this.state.firstnameError ? <span style={{color: "red"}}>Please Enter some value</span> : ''}
</div>
</div>
<div className="form-group">
<div className="form-label-group">
<input type="text" id="lastname" name="lastname" className="form-control" placeholder="Enter lastname" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="lastname">lastname</label>
{this.state.lastnameError ? <span style={{color: "red"}}>Please Enter some value</span> : ''}
</div>
</div>
<div className="form-group">
<div className="form-label-group">
<input type="email" id="email" name="email" className="form-control" placeholder="Enter your email" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="email">email</label>
{this.state.emailError ? <span style={{color: "red"}}>Please Enter valid email address</span> : ''}
</div>
</div>
<div className="form-group">
<div className="form-label-group">
<input type="password" id="password" name="password" className="form-control" placeholder="Password" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="password">Password</label>
{this.state.passwordError ? <span style={{color: "red"}}>Please enter some value</span> : ''}
</div>
</div>
<button className="btn btn-primary btn-block" disabled={this.state.isDisabled} onClick={this.submitForm}>Signup</button>
</form>
</div>
</div>
</div>
);
}
}
export default Signup;
With React Hook, form is made super easy (React Hook Form: https://github.com/bluebill1049/react-hook-form)
i have reused your html markup.
import React from "react";
import useForm from 'react-hook-form';
function Test() {
const { useForm, register } = useForm();
const contactSubmit = data => {
console.log(data);
};
return (
<form name="contactform" onSubmit={contactSubmit}>
<div className="col-md-6">
<fieldset>
<input name="name" type="text" size="30" placeholder="Name" ref={register} />
<br />
<input name="email" type="text" size="30" placeholder="Email" ref={register} />
<br />
<input name="phone" type="text" size="30" placeholder="Phone" ref={register} />
<br />
<input name="address" type="text" size="30" placeholder="Address" ref={register} />
<br />
</fieldset>
</div>
<div className="col-md-6">
<fieldset>
<textarea name="message" cols="40" rows="20" className="comments" placeholder="Message" ref={register} />
</fieldset>
</div>
<div className="col-md-12">
<fieldset>
<button className="btn btn-lg pro" id="submit" value="Submit">
Send Message
</button>
</fieldset>
</div>
</form>
);
}
Assuming you know about react useState Hook, If your form is simple, you can use state variables to hold the value of each input field. Then add onChange handler function on each input field which will update state variables. At the end, you can check the values stored in state variables to ensure that all the input fields had some value. Here is a simple example.
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const onChangeHandler = (fieldName, value)=>{
if(fieldName === "name"){
setName(value);
}
else if(fieldName==="email"){
setEmail(value);
}
}
const onSubmitHandler = (e)=>{
e.preventDefault();
if(name.trim()==="" || email.trim() ==""){
alert("required both field");
}
else{
alert(name+" " +email);
setName("");
setEmail("");
}
}
return (
<div className="App">
<form onSubmit={(e)=>{onSubmitHandler(e)}}>
<input type="text" value={name} onChange={(e)=>{ onChangeHandler("name",e.target.value)}} /> <br/>
<input type="email" value={email} onChange={(e)=>{ onChangeHandler("email",e.target.value)}} /> <br/>
<input type="submit" value="Submit" />
</form>
</div>
);
}
However, if you are having a complex form, it's hard to keep each value in state variables and then use validation on each field. For complex forms, it is recommended to use Formik that will do everything for you and you can use Yup validation package which is also supported by Formik that will allow you to add more than just simple validation.
2022
React suggests 3 approaches to handle forms:
Controlled components - In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState(). We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
Uncontrolled components - It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component. This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library. In these situations, you might want to check out uncontrolled components, an alternative technique for implementing input forms.
Fully-Fledged Solutions - If you’re looking for a complete solution including validation, keeping track of the visited fields, and handling form submission, Formik is one of the popular choices. However, it is built on the same principles of controlled components and managing state — so don’t neglect to learn them.
All approaches are valid to react hooks too.
First consider which component better suit your needs, and use its appropriate validation solution.
We have plenty of options to validate the react js forms. Maybe the npm packages have some own limitations. Based up on your needs you can choose the right validator packages. I would like to recommend some, those are listed below.
react-form-input-validation
redux-form
If anybody knows a better solution than this, please put it on the comment section for other people references.
Cleaner way is to use joi-browser package. In the state you should have errors object that includes all the errors in the form. Initially it shoud be set to an empty object.
Create schema;
import Joi from "joi-browser";
schema = {
username: Joi.string()
.required()
.label("Username")
.email(),
password: Joi.string()
.required()
.label("Password")
.min(8)
.regex(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,1024}$/) //special/number/capital
};
Then validate the form with the schema:
validate = () => {
const options = { abortEarly: false };
const result = Joi.validate(this.state.data, this.schema, options);
console.log(data) // always analyze your data
if (!result.error) return null;
const errors = {};
for (let item of result.error.details) errors[item.path[0]] = item.message; //in details array, there are 2 properties,path and message.path is the name of the input, message is the error message for that input.
return errors;
};
Before submitting the form, check the form:
handleSubmit = e => {
e.preventDefault();
const errors = this.validate(); //will return an object
console.log(errors);
this.setState({ errors: errors || {} }); //in line 9 if we return {}, we dont need {} here
if (errors) return;
//so we dont need to call the server
alert("success");
//if there is no error call the server
this.dosubmit();
};
Might be late to answer - if you don't want to modify your current code a lot and still be able to have similar validation code all over your project, you may try this one too -
https://github.com/vishalvisd/react-validator.
Try powerform-react . It is based upon powerform which is a super portable Javascript form library. Once learnt, it can be used in any framework. It works even with vanilla Javascript.
Checkout this simple form that uses powerform-react
There is also a complex example.
Try this validation plugin in your form where you can add your custom validation rules.
Create a component FormValidation.js
import { useState } from "react";
const FormValidation = ({ validationRules, formInput }) => {
const [errors, setErrors] = useState(null);
const validation = () => {
// define a empty object to store errors.
let allErrors = {};
// Run loop on validation object
Object.keys(validationRules).forEach((name) => {
// name is the name of input field
const rulesArr = validationRules[name];
// Run loop on validation array applied on that input
rulesArr.forEach((rule) => {
// Skip if any error message is already stored in allErrors object
if (!allErrors[name]) {
let result;
// If rule is an array than it is a type of a function with parameter
switch (Array.isArray(rule)) {
case true: {
// take the function name and parameter value from rule array
const [functionName, paramValue] = rule;
// call validation function
result = functionName(formInput, name, paramValue);
break;
}
default:
// call validation function
result = rule(formInput, name);
break;
}
if (result) {
// append error in object
allErrors = { ...allErrors, ...result };
}
}
});
});
return allErrors;
};
const validate = () =>
new Promise((resolve, reject) => {
const errorObj = validation();
if (Object.keys(errorObj).length === 0) {
setErrors({});
resolve("Success");
} else {
setErrors(errorObj);
reject(Error("Some Error Occurred"));
}
});
return { validate, errors, setErrors };
};
export const required = (formInputs, inputName) =>
!formInputs[inputName] && { [inputName]: "This field is required" };
function emailPattern(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,}))$/
);
}
export const email = (formInputs, inputName) =>
!emailPattern(formInputs[inputName]) && {
[inputName]: "Please enter valid email",
};
export function passwordPattern(formInputs, inputName) {
const value = formInputs[inputName];
let error;
if (value.length < 8) {
error = "Your password must be at least 8 characters";
}
if (value.search(/[a-z]/i) < 0) {
error = "Your password must contain at least one letter.";
}
if (value.search(/[0-9]/) < 0) {
error = "Your password must contain at least one digit.";
}
if (value.search(/[ `!##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/) < 0) {
error = "Your password must contain at least one special character.";
}
return (
error && {
[inputName]: error,
}
);
}
export const maxLength = (formInputs, inputName, paramValue) =>
formInputs[inputName].length > paramValue && {
[inputName]: `Maximum characters are ${paramValue}`,
};
export const minLength = (formInputs, inputName, paramValue) =>
formInputs[inputName].length < paramValue && {
[inputName]: `Minimum characters are ${paramValue}`,
};
export default FormValidation;
I want to implement validations in my Login.js
import React, { useState } from "react";
import { Button, Form } from "react-bootstrap";
import FormValidation, {
required,
email,
passwordPattern,
} from "utils/FormValidation";
const Login = () => {
const [formInput, setFormInput] = useState({
email: "",
password: "",
});
const { validate, errors, setErrors } = FormValidation({
validationRules: {
email: [required, email],
password: [required, passwordPattern],
},
formInput,
});
const handleChange = (e) => {
setFormInput({ ...formInput, [e.target.name]: e.target.value });
};
const handleSubmit = (e) => {
e.preventDefault();
validate().then(() => {
//do whatever you want
console.log(formInput);
// you can set server error manually
setErrors({ email: "Email already exist" });
});
};
return (
<section className="gradient-form" style={{ backgroundColor: "#eee" }}>
<div className="container py-5 h-100">
<div className="row d-flex justify-content-center align-items-center h-100">
<div className="col-xl-10">
<div className="card rounded-3 text-black">
<div className="row g-0">
<div className="col-lg-6">
<div className="card-body p-md-5 mx-md-4">
<Form onSubmit={handleSubmit}>
<p>Please login to your account</p>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Control
type="text"
name="email"
placeholder="Enter email"
onChange={handleChange}
/>
{errors?.email && <span>{errors.email}</span>}
</Form.Group>
<Form.Group
className="mb-3"
controlId="formBasicPassword"
>
<Form.Control
type="password"
name="password"
placeholder="Password"
onChange={handleChange}
/>
{errors?.password && <span>{errors.password}</span>}
</Form.Group>
<Form.Group
className="mb-3"
controlId="formBasicCheckbox"
>
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<div className="d-grid gap-2 mb-3">
<Button
variant="primary"
type="submit"
className="gradient-custom-2"
size="md"
>
Submit
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default Login;
Now you can pass any custom function in your validation array :
const { validate, errors, setErrors } = FormValidation({
validationRules: {
email: [required, email],
password: [required, passwordPattern, customFunciton],
},
formInput,
});
const customFunciton = (formInputs, inputName) => ({
[inputName]: `This error is from my custom function`,
});
I would like to suggest the following library, it is not react-specific. However, it provides an easy syntax and handy methods to run form validation. This is the react validation example from the library's documentation https://www.simple-body-validator.com/react/validation-quickstart

Rewriting a react-addons feature on React 15.1.0

How would I rewrite the following code without using 'LinkedStateMixin'? Since I am upgrading to React 15.0 and this feature is deprecated.
reactMixin(LoginView.prototype, React.addons.LinkedStateMixin);
<div className='form-group'>
<input type='text'
className='form-control input-lg'
valueLink={this.linkState('email')}
placeholder='Email' />
</div>
<div className='form-group'>
<input type='password'
className='form-control input-lg'
valueLink={this.linkState('password')}
placeholder='Password' />
</div>
The above code is where it is being used and I am using Redux for managing state.
You could just manage the state yourself. Are you using babel/es6?
class MyForm extends React.Component {
state = {}
emailChanged = (e) => {
this.setState({ email: e.target.value });
}
passwordChanged = (e) => {
this.setState({ password: e.target.value });
}
render() {
const { email, password } = this.state;
return (
<form>
<div className='form-group'>
<input type='text'
className='form-control input-lg'
value={email}
placeholder='Email'
onChange={this.emailChanged} />
</div>
<div className='form-group'>
<input type='password'
className='form-control input-lg'
value={password}
placeholder='Password'
onChange={this.passwordChanged} />
</div>
</form>
);
}
}
Example: http://www.webpackbin.com/EJjZTnu4Z
If you look at the Two-Way Binding Helpers doc page, there's an example that shows how to do the same thing without using LinkedStateMixin.

Categories

Resources