Form Validation - react - javascript

index.js
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import { useHistory } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
const AddRequest = () => {
const [request, setRequest] = useState({
product_name: '',
description: '',
product_img: '',
});
const [error, setError] = useState({
product_error: ''
})
const handleChange = e => {
e.preventDefault();
const {name, value} = e.target;
let formError = {...error};
switch(name) {
case "product_error":
formError.product_error =
value.length < 0 ? "Required" : "";
break;
default:
break;
}
setError({formError, [name]: value});
console.log(error)
setRequest({ ...request, [e.target.name]: e.target.value });
};
const headers = {
'x-access-token': localStorage.getItem('accessToken'),
'content-type': 'multipart/form-data'
}
const handleImageChange = async e => {
e.preventDefault();
setRequest({ ...request, [e.target.name]: e.target.files });
};
const handleSubmit = async e => {
e.preventDefault();
const formData = new FormData()
for (const file of request.product_img) {
formData.append('product_img', file)
}
formData.append('product_name', request.product_name)
formData.append('description', request.description)
await Axios.post(config.api, formData, {
headers: headers
})
.then(res => {
toast.success('Added Successfully!', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
.catch(e => {
console.log(e)
toast.error('not Added', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
setTimeout(function () {
history.push('/')
}, 1500);
};
return (
<>
<ToastContainer />
<form onSubmit={e => handleSubmit(e)} noValidate>
<div className="form-group">
<label htmlFor='product_name'>Product Name:</label>
<input type="text" name="product_name" id="product_name" placeholder="Enter Product Name" className="form-control" noValidate onChange={e => handleChange(e)} />
{errors.product_error}
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='description'>Description:</label>
<input type="text" name="description" id="description" placeholder="Description" className="form-control" onChange={e => handleChange(e)} />
</div>
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='product_img'>Product Image:</label> <br />
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} />
</div>
<button type="submit" className="btn btn-success"> Add Request Rekko </button>
</form>
</>
)
};
export default AddRequest
Everything is working fine but form validation is not working. I am new to react and tried many things but still, it is not working. Can anyone help me with form validation? I only want all 3 fields to be required. It shows the message that this field is required if someone submits a form without entering anything.

You can simply add the tag required inside the input, like this:
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} required />

Related

React: Uncaught TypeError: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'

why do i get this error React: Uncaught TypeError: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. when i try to upload an image in react, i cannot really tell where the error is coming from as i have done pretty much everything to fix the bug.
AddCourse.js
import { useEffect, useState } from 'react';
import axios from 'axios'
const baseUrl = 'http://127.0.0.1:8000/api';
function AddCourse() {
const [cats, setCats] = useState([])
const [courseData, setCourseData] = useState({
category:"",
title:"",
description:"",
teacher:"",
f_img:"",
techs:"",
})
// load the data
useEffect(() => {
try {
axios.get(baseUrl + '/category/').then((res) => {
setCats(res.data)
})
} catch (error) {
console.log(error);
console.log("error");
}
}, [])
// console.log(cats);
const handleChange = (event) => {
setCourseData({
...courseData,
[event.target.name]: event.target.value
})
}
const handleFileChange = (event) => {
setCourseData({
...courseData,
[event.target.name]: event.target.files[0]
})
}
const formSubmit = () => {
const _formData = new FormData()
_formData.append("category", courseData.category)
_formData.append("teacher", 1)
_formData.append("title", courseData.title)
_formData.append("featured_img", courseData.f_img, courseData.f_img.name)
_formData.append("description", courseData.description)
_formData.append("techs", courseData.techs)
try {
axios.post(baseUrl + '/course/', _formData, {
headers: {
'content-type':'multipart/form-data'
}
}).then((res) => {
console.log(res.data);
})
} catch (error) {
}
}
return (
<div>
<input onChange={handleChange} name="title" type="text" className="form-control" name="" id="" />
<textarea onChange={handleChange} name="description" className="form-control" placeholder="" />
<select onChange={handleChange} name="category" className="form-control" id="">
{cats.map((category, index) => {return
<option key={index} value={category.id}>{category.title}</option>
})}
</select>
<input onChange={handleFileChange} name="f_img" type="file" className="form-control" id="" />
<textarea onChange={handleChange} name="techs" className="form-control" placeholder="React, Django, Express" />
<button onClick={formSubmit} className="btn btn-primary" type="submit">Update</button>
</div>
);
}
export default AddCourse;
In the handler it should be files
[event.target.name]: event.target.files[0]
When adding to formdata is should be
_formData.append("featured_img", courseData.f_img, courseData.f_img.name)

How can I write an onChange function that handles multiple individual files and multiple other fields in Next JS?

I am working on a project using Next JS, and I was trying to write an on Change function that deals with multiple individual files that aren't in an array. This is what I have so far, and the function is named "handleChange":
import { useState, useEffect} from 'react';
import Link from 'next/link';
import React from 'react';
import { withRouter } from 'next/router';
import { getCookie} from '../../actions/auth';
import { createBrand } from '../../actions/brand';
const BrandCreate = ({ router }) => {
const [values, setValues] = useState({
error: '',
sizeError: '',
success: '',
formData: '',
name: '',
address: '',
phone:'',
email:'',
hidePublishButton: false
});
const { error, success, formData, name, address, phone, email} = values;
const token = getCookie('token');
useEffect(() => {
setValues({ ...values, formData: new FormData()});
}, [router]);
const publishBrand = e => {
e.preventDefault();
createBrand(formData, token).then(data => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({ ...values, name: '', address:'', phone:'', email:'', error: '', success: `Created Successfully` });
}
});
};
const handleChange = name => e => {
const value = name === 'image' ? e.target.files[0] : e.target.value;
formData.set(name, value);
setValues({ ...values, [name]: value, formData, error: '' });
};
const showError = () => (
<div className="alert alert-danger" style={{ display: error ? '' : 'none' }}>
{error}
</div>
);
const showSuccess = () => (
<div className="alert alert-success" style={{ display: success ? '' : 'none' }}>
{success}
</div>
);
const createBrandForm = () => {
return (
<form onSubmit={publishBrand}>
<div className="formspacing">
<p className="Title">Name</p>
<input type="text" id="Title" value={name} onChange={handleChange('name')} />
<p className="Title">Address</p>
<input type="text" id="Title" value={address} onChange={handleChange('address')} />
<p className="Title">Phone</p>
<input type="text" id="Title" value={phone} onChange={handleChange('phone')} />
<p className="Title">Email</p>
<input type="text" id="Title" value={email} onChange={handleChange('email')} />
<hr className="hrform"/>
<p className="Title">Image</p>
<input id="imgg" onChange={handleChange('logo')} type="file" accept="image/*"/>
<p className="Title">Logo</p>
<input id="imgg" onChange={handleChange('image')} type="file" accept="image/*"/>
</div>
<div className="TwoBtns">
<button type="submit" className="Btn1">PUBLISH</button>
<button type="button" className="cancelbtn"> <Link href="/admin/brands/manageBrands">Back</Link></button>
</div>
</form>
);
};
return (
<React.Fragment>
{createBrandForm()}
<div className="c" width="100px">
{showError()}
{showSuccess()}
</div>
<hr className="hr1" />
</React.Fragment>
);
};
export default withRouter(BrandCreate);
I have another field "logo" that is supposed to also be an image, however I don't know how to handle it in the same function.
If anyone can help me figure this out, I would highly appreciate it.
Thank you in advance!
I have tried this:
const handleChange = name => e => {
const value = name === 'image' ? e.target.files[0] : 'logo' ? e.target.files[0] : e.target.value;
formData.set(name, value);
setValues({ ...values, [name]: value, formData, error: '' });
};
But it doesn't work.

React.js: Array won't print on screen but console.log() works fine

I have a Register.js component that send a request to an express.js backend and then is validated by express-validator and returns an object that looks like this:
data: {
success: Boolean,
errors: array()
}
Register.js
import React, {useState} from "react";
import { Link } from "react-router-dom";
const RegisterForm = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState([]);
const [token, setToken] = useState("");
const handleFormSubmit = (e) => {
e.preventDefault();
const formFields = {
name: username,
password: password
}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formFields)
};
fetch('http://localhost:5000/add_user', requestOptions)
.then(response => response.json())
.then(data => {
if (data.success === false) {
if(data.errors) {
return setErrors(data.errors);
}
if(data.single_error) {
return setErrors([...errors, data.single_error]);
}
}
if(data.success === true) {
setErrors([]);
//Redirect to login
console.log("Success");
}
})
}
return(
<div className="login register">
<h1>Register</h1>
<form onSubmit={handleFormSubmit}>
<label>
<i className="fa fa-user-o" aria-hidden="true"></i>
</label>
<input type="text" name="username"
value={username}
onChange={e => setUsername(e.target.value)}
placeholder="Username" id="username" required />
<label>
<i className="fa fa-unlock-alt" aria-hidden="true"></i>
</label>
<input type="password" name="password"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Password" id="password" required />
{errors ? errors.map((item, key) => (
// <li key={key}>{item}</li>
console.log(item)
)) : null}
<input type="submit" value="Register" />
</form>
<Link className="register-link" to="/"><small>Login 🠖</small></Link>
</div>
)
}
export default RegisterForm;
Any ideas why this will console.log but won't print the data on the screen?
Here is a screenshot of my console.log values: https://prnt.sc/ig6F2O1S1L1L
If I try to map through the array and return the values in a list I don't get any errors just nothing happens.
The <li> HTML element is used to represent an item in a list. It must be contained in a parent element: an ordered list (<ol>), an unordered list (<ul>), or a menu (<menu>).
<ul>
{errors ? errors.map((item, key) => (
<li key={key}>{item}</li>
//console.log(item)
)) : null}
</ul>

where to call the Axios post request in reactjs

I have a form,thats data are saved in the state to be sent to the backend server.
i am handling the form with handleSubmit function and useEffect hook, where the handleSubmit prevents the form from being submitted unless it calls the validation function, in the useEffect I check if there are any errors using if condition and then console.log my data.
now I want to post the data hold in the state -the state is sent as a props to me- but I am confused whether to put the request in the HandleSubmit function or in the useEffect inside the body of the if condition.
import react, { Component, useState, useEffect } from 'react';
import {useNavigate } from 'react-router-dom';
import axios from 'axios';
import './sign.css';
const SignA = (props) => {
const navigate = useNavigate();
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleSubmit = (err) => {
err.preventDefault();
setFormErrors(validate(props.data));
setIsSubmit(true);
}
useEffect(() => {
console.log(Object.keys(formErrors).length);
if (Object.keys(formErrors).length === 0 && isSubmit) {
console.log('console the props data', props.data)
//here is where I think the post request should be put
if (isSubmit) {
return (navigate('/profileadmin'))
}
}
}, [formErrors])
const validate = (values) => {
const errors = {};
const regex = /^[^\s#]+#[^\s#]+\.[^\s#]{2,}$/i;
if (!values.firstname) {
errors.firstname = 'firstname is required!';
}
if (!values.lastname) {
errors.lastname = 'lastname is required!';
}
if (!values.mobile) {
errors.mobile = 'mobile is required!';
}
if (!values.email) {
errors.email = 'email is required!';
} else if (!regex.test(values.email)) {
errors.email = 'this is not a valid email format!'
}
return errors;
}
return (
<div className='signup'>
<form onSubmit={handleSubmit} >
<div className="container">
<h1>Sign Up</h1>
<div className="name">
<div>
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={props.change}
/>
</div>
<div>
<input
type="text"
placeholder="Last name"
name="lastname"
value={props.data.lastname}
onChange={props.change}
/>
</div>
</div>
<p className='errorMsg'>{formErrors.firstname}</p>
<p className='errorMsg'>{formErrors.lastname}</p>
<br />
<div>
<input
type="text"
placeholder="Business mobile number"
name="mobile"
value={props.data.mobile}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.mobile}</p>
<br />
<input
type="text"
placeholder="Email Adress"
name="email"
value={props.data.email}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.email}</p>
<br />
</div>
</div>
<br />
<div className="checkbox">
<label>
<input type="checkbox" className="check" />i’ve read and agree with <a href="url" >Terms of service</a>
</label>
</div>
<div className="clearfix">
<button type="submit" className="signupbtn">Sign Up</button>
</div>
</div>
</form >
</div >
)
}
export default SignA;
this is the request
axios.post('', props.data)
.then(res => console.log('post res', res))
.catch(error => {
console.error('There was an error in post request!', error);
});
You don't necessarily need useEffect here.
Here is how you can implement such thing:
Declare a state to hold form values:
const [formData, setFormData] = useState({})
Declare function to set the state:
const handleChange = (name, value) => {
setFormData({...formData, [name]: value})
}
Input onChange to capture:
// handleChange has two parameters
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={(event) => handleChange('firstName', event.target.value)}
/>
function for calling post axios post request
const handleSubmit = () => {
//check for validations code here
// if validations are right then post request here
// this will give you all the fields like firstName: "", lastName: ""
let requestBody = {
...formData
}
axios.post("url", requestBody).then((res)=> {
//your code here
})
}

useState() hook not updating the value on change

Little context, I am trying to create a form for for getting User Signup.
I first wrote code as following .
import { useState } from 'react';
const SignupComponent = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
error: '',
loading: false,
message: '',
showForm: true
})
const { name, email, password, error, loading, showForm } = formData;
const onChange = e => {
setFormData({ ...formData, error: false, [e.target.name]: e.target.value })
console.log(name)
}
const handleSubmit = async e => {
e.preventDefault();
console.table({ name, email, password, error, loading, showForm })
}
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Enter Your Name" values={name} onChange={e => onChange(e)} />
</div>
<div className="form-group">
<input values={email} onChange={e => onChange(e)} type="email" className="form-control" placeholder="Enter Your Email" />
</div>
<div className="form-group">
<input values={password} onChange={e => onChange(e)} type="password" className="form-control" placeholder="Enter Your Password" />
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>{signupForm()}</React.Fragment>};
export default SignupComponent;
I noticed that in this code snippet, the state in setFormData is not getting updated, console logging name or any other value returns a empty string.
result for the above code
But after tweaking the code as such
import { useState } from 'react';
const SignupComponent = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
error: '',
loading: false,
message: '',
showForm: true
})
const { name, email, password, error, loading, showForm } = formData;
const handleChange = value => (e) => {
setFormData({ ...formData, error: false, [value]: e.target.value })
console.log(name)
}
const handleSubmit = async e => {
e.preventDefault();
console.table({ name, email, password, error, loading, showForm })
}
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Enter Your Name" values={name} onChange={handleChange('name')} />
</div>
<div className="form-group">
<input values={email} onChange={handleChange('email')} type="email" className="form-control" placeholder="Enter Your Email" />
</div>
<div className="form-group">
<input values={password} onChange={handleChange('password')} type="password" className="form-control" placeholder="Enter Your Password" />
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>{signupForm()}</React.Fragment> };
export default SignupComponent;
Makes the code work and result is as desired. As in this image.
2nd way
Why is this behaving like this. Why is the first way not working.
You forgot the name attribute in your inputs, and the value attribute without s
<input name="email" value={email} onChange={onChange} ... />
then
const onChange = e => {
// The event will get passed as an argument even if you don't bind it in onChange={onChange}.
console.log(e.target.name, e.target.value)
setFormData({ ...formData, error: false, [e.target.name]: e.target.value })
}
The event will get passed as an argument.
It works for the second cause you're passing the name as an argument
see docs, https://reactjs.org/docs/thinking-in-react.html
React’s one-way data flow (also called one-way binding) keeps everything modular and fast.
Important thing to solve your question.
The Functional Component(FC) state is changed, UI is re-rendered.
But, your signupForm render function is declared in FC.
So, It is re-delcared as a new, when SignupComponent state is changed.
First. change signupForm render function to FC component.
Second, Pass props to component.
Thrid, re-used them.
import React from 'react'; // React is required to render JSX
const FormInput = ({
type,
placeholder,
value,
onChange,
}) => (
<div className="form-group">
<input type={type} className="form-control" placeholder={placeholder} value={value} onChange={onChange} />
</div>
);
const SignupComponent = () => {
const [formData, setFormData] = React.useState({
name: '',
email: '',
password: '',
error: false,
loading: false,
message: '',
showForm: true,
});
const {
name, email, password, error, loading, showForm,
} = formData;
const handleChange = (value) => (e) => {
setFormData({
...formData,
error: false,
[value]: e.target.value,
});
console.log(name);
};
const handleSubmit = async (e) => {
e.preventDefault();
console.table({
name, email, password, error, loading, showForm,
});
};
return (
<form onSubmit={handleSubmit}>
<FormInput type="text" value={name} placeholder="Enter Your Name" onChange={handleChange('name')} />
<div>
<button type="submit" className="btn btn-primary">Signup</button>
</div>
</form>
);
};
export default SignupComponent;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Categories

Resources