React Form Validation - javascript

I've just started learning react and I am doing a simple form app.
And my question is how can I validate the text and email inputs?
I've tried few ways to do it but the code it's getting really messy so I removed the code w/ 'validation'
Here's my code this is my parent 'Form' component
import React, { Component } from "react";
import Name from "components/Name";
import Email from "components/Email";
import Select from "components/Select";
import Bio from "components/Bio";
// Create Form Component
class Form extends Component {
constructor(props) {
super(props);
this.state = {
firstName: "",
lastName: "",
email: "",
country: "Norway",
bio: ""
};
}
// Handle inputs value on change event
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
};
// Handle the form submission
handleSubmit = event => {
event.preventDefault();
// Send POST Request (every postbin expires aftre 30min)
fetch("https://postb.in/1580328526126-6915104780346", {
method: "POST",
mode: "no-cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*"
},
body: JSON.stringify(this.state)
});
console.log(this.state);
// Clear form inputs
this.setState({
firstName: "",
lastName: "",
email: "",
country: "",
bio: ""
});
};
// Render Form Component and its child components
render() {
// Destructuring the current component state
const { firstName, lastName, email, country, bio } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<div className="shape rectangle"></div>
<div className="shape triangle"></div>
<div className="shape circle"></div>
<Name
firstName={firstName}
lastName={lastName}
handleChange={this.handleChange}
/>
<Email email={email} handleChange={this.handleChange} />
<Select country={country} handleChange={this.handleChange} />
<Bio bio={bio} handleChange={this.handleChange} />
<button type="submit" className="btn">
Submit
</button>
</form>
);
}
}
export default Form;
And here's a child component the rest of the child components are similar to this one.
import React, { Component } from "react";
// Create Name component for name && email inputs
class Name extends Component {
// Render labels and name inputs
render() {
const { firstName, lastName, handleChange } = this.props;
return (
<div className="form-names">
<label htmlFor="firstName">Name</label>
<br />
<input
type="text"
name="firstName"
value={firstName}
placeholder="First Name"
id="firstName"
onChange={handleChange}
required
/>
<input
type="text"
name="lastName"
value={lastName}
placeholder="Last Name"
id="lastName"
onChange={handleChange}
required
/>
</div>
);
}
}
export default Name;

https://react-hook-form.com/
There are a few libraries you can use for doing form validation in react. Basically you will just have a form validation function that uses things like regex comparisons and conditionals that these libraries support. The link above provides a comparison to some popular libraries.

Related

this.props.history.push('/') IS NOT WORKING in CLASS Component

Please help me to resolve the issue of this.props.history.push('/') IS NOT WORKING in CLASS Component. As we do not have any scope of using history anymore. Unable to implement navigate.
Please do help. Same issue with props.location.state.contact.
**const { name, email } = props.location.state.contact;**
import React, { Component } from "react";
import "../assets/css/AddContact.css";
import { Navigate } from "react-router-dom";
import { v4 as uuid } from "uuid";
class AddContact extends Component {
state = {
id: uuid(),
name: "",
email: "",
};
add = (e) => {
e.preventDefault();
if (this.state.name === "" || this.state.email === "") {
alert("All fields are required!");
return;
}
this.props.addContactHandler(this.state);
this.setState({ name: "", email: "" });
this.props.history.push("/");
};
render() {
return (
<div className="contactForm">
<h2 className="contactForm__title">Add Contact</h2>
<div className="contactForm__form">
<form action="/" method="post" onSubmit={this.add}>
<div className="contactForm__nameField">
<label htmlFor="name">Name</label>
<br />
<input
type="text"
placeholder="Enter your name"
name="name"
id="name"
value={this.state.name}
onChange={(e) => this.setState({ name: e.target.value })}
/>
</div>
<div className="contactForm__emailField">
<label htmlFor="email">Email</label>
<br />
<input
type="email"
placeholder="Enter your email"
name="email"
id="email"
value={this.state.email}
onChange={(e) => this.setState({ email: e.target.value })}
/>
</div>
<button className="contactForm__button">Add</button>
</form>
</div>
</div>
);
}
}
export default AddContact;
I tried out from all of my references.
You need to use the withRouter Higher Order Component provided with the React Router library in order to get access to those props (history and location automatically).
So just import that, and change your export to
export default withRouter(AddContact);
[Note that this assumes you are using React Router v5 or before - there is no withRouter in v6 which is the latest version. But your use of a class component implies that you are using an earlier version - v6 only works well if you use function components, as withRouter has been replaced with Hooks.]

I am facing a problem in JavaScript/ReactJS

I am working in ReactJS on post API. I have given a task to create some text fields in which I have to give some values and then on click of a submit button the information from text field will be submitted to POST API which I have taken from JasonPlaceHolder.
I have written a code which is given at last. Whenever I click Register button the value in last input field (which in my case is "EMAIL") overrides the values of all the input fields.
A screenshot of my problem is also attached:
Code
import React from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
error: null,
isLoaded: false,
items: [],
inter:0,
ID: '',
Name: '',
username : '',
Email: ''
};
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
updateInput(event){
this.setState({ID : event.target.value})
this.setState({Name : event.target.value})
this.setState({username : event.target.value})
this.setState({Email : event.target.value})
}
handleSubmit(){
var dict = { id: this.state.ID, name:this.state.Name , username: this.state.username , email: this.state.Email };
axios.post('https://jsonplaceholder.typicode.com/users', dict)
.then(response => {
console.log(response)
this.setState({isLoaded:true,
flag:1,
})
})
.catch(error => {
alert(error);
console.log(error);
})
}
render() {
const { error, isLoaded, items } = this.state;
if (this.state.inter == 0){
return(
<div>
<form>
<p>ID:<input type="text" name="ID" onChange={this.updateInput}/> </p>
<p>Name:<input type="text" name="name" onChange={this.updateInput} /> </p>
<p>User Name:<input type="text" name="username" onChange={this.updateInput} /></p>
<p>Email: <input type="text" name="email" onChange={this.updateInput} /></p>
</form>
<button onClick={this.handleSubmit}>
Register
</button>
</div>
);
}else{
return(
<div>
<button onClick={this.handleSubmit} >
Register
</button>
<h1> Post Request Submitted Successfully</h1>
</div>
);
}
}
componentDidMount() {
}
}
export default App;
Your updateInput method overrides all the other fields, that's why the last updated field (the email) is the one you are seeing on the request payload.
To solve this you can separate the updateInput method for each input field or inside updateInput check which field you're currently updating and update only that field.
You can check here for more details:
https://medium.com/#zacjones/handle-multiple-inputs-in-react-with-es6-computed-property-name-e3d41861ae46
You have to update the fields like this,
updateInput({target: {name, value}}){
this.setState({[name]: value});
}
The issue is in the updateInput method. change it to.
const { name, value } = event.target;
this.setState(state => ({
...state, [name]: value,
}));
N:B You will have to make the names of the input element same as the state field.
Change your updateInput logic to this.
updateInput(event){
this.setState({[event.target.name] : event.target.value})
}

Why does my React form auto-refresh the page even if I put "event.preventDefault()" on handleSubmit?

I have two files which work together to render things. The first is App.js, which first renders Form.js. The form will then collect information, which on submission, changes the Form state and calls a function from App.js. This function is called "createProject." Calling "createProject" in Form.js "handleSubmit" makes the page auto-refresh. However, if I remove "createProject" from handleSubmit, the page does not auto-refresh. Here are the two files.
import React, { Component } from "react";
import Project from "./components/Project.js"
import Form from "./Form.js";
class App extends Component {
constructor(props) {
super(props);
this.state = {
projectList: [],
myProjects: [],
userList: [],
submitted: false
};
this.createProject = this.createProject.bind(this);
}
createProject(title, desc, langs, len, exp) {
this.setState({
projectList: this.state.projectList.push([
{
title : title,
description : desc,
language : langs,
length : len,
experience : exp
}
]),
submitted : true
});
}
deleteProject(title) {
const projects = this.state.projectList.filter(
p => p.title !== title
);
this.setState({projects});
}
render() {
let info;
if (this.state.submitted) {
info = (
<div>
<p>cccc</p>
</div>
);
} else {
info = (
<br/>
);
}
return(
<div>
<Form/>
{info}
{this.state.projectList.map((params) =>
<Project {...params}/>)}
</div>
);
}
}
export default App;
import React from "react";
import createProject from "./App.js"
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
description: "",
language: "",
length: 0,
experience: "",
submitted: false
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleSubmit(event) {
this.setState({
submitted: true
})
createProject(
this.state.title,
this.state.description,
this.state.language,
this.state.length,
this.state.experience
)
event.preventDefault();
}
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
let info;
if (this.state.submitted) {
info = (
<div>
<h1>{this.state.title}</h1>
<p>{this.state.description}</p>
<p>{this.state.language}</p>
<p>{this.state.length}</p>
<p>{this.state.experience}</p>
</div>
);
} else {
info = <br/>;
}
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Title:
<input
name="title"
type="textbox"
checked={this.state.title}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Description:
<input
name="description"
type="textbox"
checked={this.state.description}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Language:
<input
name="language"
type="textbox"
checked={this.state.language}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Length:
<input
name="length"
type="number"
checked={this.state.length}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Experience:
<input
name="experience"
type="textbox"
checked={this.state.experience}
onChange={this.handleInputChange} />
</label>
<br />
<input type="submit" value="Submit" />
</form>
{info}
</div>
);
}
}
export default Form;
I've also tried adding "new" to the "createProject" in handleSubmit, and while that does stop the auto-refresh, it will not call the createProject function. (Or maybe it does, but none of the code in the createProject function seems to be run.) Can anyone help with preventing this auto refresh while also allowing App's createProject function to run properly?
The page auto refreshes because execution never gets to your event.PreventDefault() line. This is due to an error encountered when react tries to evaluate createProject. To fix this, correct handleSubmit like so.
handleSubmit(event) {
event.preventDefault(); // moved up in execution.
this.setState({
submitted: true
})
createProject(
this.state.title,
this.state.description,
this.state.language,
this.state.length,
this.state.experience
)
}
Notice that moving event.PreventDefault() to the top of your handleSubmit(event) function just before this.setState line prevents default form behaviour on submit.
You however get an error because App.js doesn't export a function called createProject. To maintain the createProject within App instance, you need to pass it as a prop which you can then reference as this.props.createProject.
See this answer on how to do call a Parent method in ReactJS.

Can't set React state with defaultValue

I'm trying to make the user profile editable in my component. Right now, when the user clicks "edit," the profile is replaced with a form that has the values they typed in as defaults. However, if they update only one field, the others get rewritten with blank values instead of passing the default value to the state.
Is there a way to pass the defaultValue to the state? I've tried value={} too but then the value doesn't change at all.
I'm trying to avoid having an "Edit" button for each input.
class AccountEditor extends Component {
constructor() {
super()
this.state = {
isEditing: false,
profile: {
firstName: '',
lastName: '',
city: '',
email: '',
bio: '',
}
}
}
toggleEdit(event) {
event.preventDefault()
this.setState({
isEditing: !this.state.isEditing
})
}
updateProfile(event) {
let updatedProfile = Object.assign({}, this.state.profile)
updatedProfile[event.target.id] = event.target.value
this.setState({
profile: updatedProfile
}
}
submitUpdate(event) {
event.preventDefault()
this.props.onUpdate(this.state.profile)
this.setState({
isEditing: !this.state.isEditing
})
}
render() {
let profile = this.props.profile
let content = null
if (this.state.isEditing == true) {
content = (
<div>
<input
id="firstName"
onChange={this.updateProfile.bind(this)}
defaultValue={profile.firstName} />
<br />
<input
id="lastName"
onChange={this.updateProfile.bind(this)}
defaultValue={profile.lastName} />
<br />
<input
id="city"
onChange={this.updateProfile.bind(this)}
defaultValue={profile.city} />
<br />
<input
id="email"
onChange={this.updateProfile.bind(this)}
defaultValue={profile.email} />
<br />
<textarea
id="bio"
onChange={this.updateProfile.bind(this)}
defaultValue={profile.bio} />
<br />
<button onClick={this.submitUpdate.bind(this)}>Done</button>
</div>
)
} else {
content = (
<div>
<h4>Name: </h4>
<span>{profile.firstName}</span>
<span>{profile.lastName}</span><br/>
<h4>City: </h4>
<span>{profile.city}</span><br/>
<h4>Bio :</h4>
<p>{profile.bio}</p><br />
<button onClick={this.toggleEdit.bind(this)}>Edit</button>
</div>
)
}
return (
<div>
{content}
</div>
)
}
}
export default AccountEditor
You should replace defaultValue with value = { this.state.someProp }. So an example with your code would be
constructor(props) {
super(props)
this.state = {
isEditing: false,
profile: props.profile // Setting up the initial data from the passed prop
}
}
and
<input id="firstName"
onChange={ this.updateProfile.bind(this) }
value={ this.state.profile.firstName } />
More about using react with form elements in these docs.

Uncaught TypeError: Cannot read property 'value' of undefined in REACT JS

I am creating a login form using REACT JS as front-end and PHP as back-end. I am trying to get input values. Code is as below:
import React, { Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, IconButton} from 'react-toolbox/lib/button';
import Input from 'react-toolbox/lib/input';
export default class Login extends React.Component {
constructor() {
super();
this.state = {email: ''};
this.state = {password: ''};
this.onSubmit = this.onSubmit.bind(this);
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
}
handleEmailChange(e) {
this.setState({email: e.target.value});
}
handlePasswordChange(e) {
this.setState({password: e.target.value});
}
onSubmit() {
fetch('http://xyz/check-login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: this.state.email,
password: this.state.password,
})
})
}
And form is as below:
<form name="Login">
<Input type="text" name="email" value={this.state.email} placeholder="Email Id" className="form-control" onChange={this.handleEmailChange} />
<Input name="password" value={this.state.password} placeholder="Password" type="password" className="form-control m-b-10" onChange={this.handlePasswordChange} />
<Button type="button" className="m-t-20 orange" label="Sign in " onClick={this.onSubmit} />
</form>
But getting the following error:
Uncaught TypeError: Cannot read property 'value' of undefined
I am using react-toolbox. So, I am using component from https://github.com/react-toolbox/react-toolbox/blob/dev/components/input/Input.js and component from https://github.com/react-toolbox/react-toolbox/blob/dev/components/button/Button.js.
First of all, what are <Input ..../> and <Button .../>? Are they your components or they are only form input fields?
I suppose that they are only form fields, thus they need to be in lower case <input ..../> , <button .../>.
Try to bind your functions inside render, like : this.functionName.bind(this).
This is a working code :
class Test extends React.Component {
constructor(props){
super(props);
this.state = {
email: '',
password: '',
};
}
handleEmailChange(e) {
this.setState({email: e.target.value});
}
handlePasswordChange(e) {
this.setState({password: e.target.value});
}
render(){
return (
<div>
<form name="Login">
<input type="text" name="email" value={this.state.email} placeholder="Email Id" className="form-control" onChange={this.handleEmailChange.bind(this)} />
<input name="password" value={this.state.password} placeholder="Password" type="password" className="form-control m-b-10" onChange={this.handlePasswordChange.bind(this)} />
<button type="button" className="m-t-20 orange" label="Sign in " onClick={this.onSubmit}>Sign in</button>
</form>
</div>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is the fiddle.
UPDATE
I tested it here :
constructor(props){
super(props);
this.state = {
name: '',
email: ''
}
}
handleChange(name, value){
let state = this.state;
state[name] = value;
this.setState({state});
}
render () {
return (
<section>
<Input type='text' label='Name' name='name' value={this.state.name} onChange={this.handleChange.bind(this, 'name')} maxLength={16} />
<Input type='email' label='Email address' icon='email' value={this.state.email} onChange={this.handleChange.bind(this, 'email')} />
</section>
);
}
I'm not sure how it works, but it pass name and value as params to the handleChange function, thus, you can get value as a second param. You don't need event.
First change your this.state in constructor to single - this.state = {emai:'',password:''}, then try to bind handleEmailChange and handlePasswordChange inside of input instead in constructor, u need to set this direct to input,
UPDATE
or if Input and Button are components, u need implement changeMethod and onChange event in them, and send value back to component Login via callback
HOW IT WORKS -
class Input extends React.Component{
constructor(props){
super(props);
this.state= {
value : this.props.value
}
}
componentWillReceiveProps(nextProps){
this.setState({
value: nextProps.value,
})
}
render(){
return(
<input onChange={this.handleChangeValue.bind(this)} type="text" name={this.props.name} value={this.state.value} placeholder={this.props.placeholder} className={**just class name or send via props too**} />
)
}
handleChangeValue(e){
this.setState({value:e.target.value});
this.props.changeValue(e.target.value);
}
}
class Login extends React.Component{
constructor(props){
super(props);
this.state= {
emailValue : '',
passwordValue: '',
...
}
}
render(){
return(
<div>
<Input type="text" name='email' value={this.state.emailValue} placeholder={'Write email'} className='someName' changeValue={this.changeEmailValue.bind(this)} />
<Input type="text" name='password' value={this.state.passwordValue} placeholder={'Write password'} className='someName' changeValue={this.changePasswordValue.bind(this)} />
</div>
)
}
changeEmailValue(value){
this.setState({emailValue:value});
}
changePasswordValue(value){
this.setState({passwordValue:value});
}
}
Since you are using a custom component <Input/>, it is likely whatever special code that component has is abstracting away the default event passed from the built-in component <input/>. (note the lower case "i") So maybe you need it to read:
handleEmailChange(value) {
this.setState({email: value});
}
handlePasswordChange(value) {
this.setState({password: value});
}
Regardless the fix is likely that onChange is not returning an event, but some other value you were not expecting.
Instead on binding events in the constructor bind it with the input fields, it will solve your problem.
one more suggestion: you are using two state object, Don't use two separate state variable initialisation, define it like this:
this.state = {
email: '',
password: '',
};
If you use Formik, You should set initialValues for it.
<Formik
initialValues={{
email: '',
password: '',
}}
onSubmit={(values) => {
console.log("formik", values)
}}
>

Categories

Resources