React Bootstrap can't validate forms - javascript

I am trying to add some validation to my React + Bootstrap project but I am not able to achieve this. According to Bootstrap Form validation documentation I have to provide a Form.Control.Feedback component to the Form Group component.
But is not showing the errors but check marks like everything is fine. I created this Code Sandbox yo demostrate what I need to achieve and what is showing me:
And just in case, this is the code if you don't need the sandbox to see the error:
import React, { useState } from "react";
import "./styles.css";
import { Container, Form, Button } from "react-bootstrap";
import validator from "validator";
import empty from "is-empty";
export default function App() {
const [validated, setValidated] = useState(false);
const [errors, setErrors] = useState({});
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = async e => {
e.preventDefault();
const errors = {};
// validation
if (!validator.isMobilePhone(phone, ["es-UY"])) {
errors.phone = "Invalid phone number";
}
if (!validator.isEmail(email)) {
errors.email = "Invalid email address";
}
if (!empty(errors)) {
setErrors(errors);
}
setValidated(true);
};
return (
<Container>
<Form validated={validated} onSubmit={handleSubmit}>
<h1>Test form</h1>
<Form.Group controlId="phone">
<Form.Label>Phone number</Form.Label>
<Form.Control
type="tel"
value={phone}
onChange={e => setPhone(e.target.value)}
/>
<Form.Control.Feedback type="invalid">Error</Form.Control.Feedback>
{errors.phone && (
<Form.Control.Feedback type="invalid">
{errors.phone}
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controlId="email">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
feedback="Error"
/>
{errors.email && (
<Form.Control.Feedback type="invalid">
{errors.email}
</Form.Control.Feedback>
)}
</Form.Group>
<Form.Group controld="submit">
<Button type="submit" variant="primary">
Submit
</Button>
<Button
type="reset"
variant="info"
style={{ marginLeft: 10 }}
onClick={() => {
setErrors({});
setValidated(false);
}}
>
Reset
</Button>
</Form.Group>
</Form>
</Container>
);
}
So, what am I doing wrong?

Make sure you've set setValidated as false for the errors
const handleSubmit = async e => {
e.preventDefault();
const allErrors = {}; // <--- changed this as well
// validation
if (!validator.isMobilePhone(phone, ["es-UY"])) {
allErrors.phone = "Invalid phone number";
}
if (!validator.isEmail(email)) {
allErrors.email = "Invalid email address";
}
if (!empty(allErrors)) {
setErrors(allErrors);
setValidated(false);
}
else {
setValidated(true);
}
};
In your field add isInvalid as props:
<Form.Control
type="tel"
value={phone}
isInvalid={!!errors.phone} <------
onChange={e => setPhone(e.target.value)}
/>
<Form.Control
type="text"
value={email}
isInvalid={!!errors.email} <-----
onChange={e => setEmail(e.target.value)}
feedback="Error"
/>

Related

Input doesn't change the value in reactjs

Problem
I'm working on project using reactjs and graphql with apollo client. I'm trying to get user by id and it works, the value shows in the form modal.
But, I can't delete or add the text or content inside form input.
I'm using onChange handler but it doesn't work. here's the code
import React, { useEffect, useState } from "react";
import { useMutation, useQuery } from "#apollo/client";
import { Button, Modal, Form } from "react-bootstrap";
import { GET_USER_BY_ID } from "../../../gql/query";
const ModalEdit = (props) => {
// state for check input component
const [isChecked, setIsChecked] = useState('ACTIVE');
const [value, setValue] = useState({
full_name: "",
email: "",
phone: "",
address: "",
password: "",
group_id: "",
});
useEffect(() => {
if (props.show) {
document.body.classList.add("modal-open");
}
return () => {
if (document.body.classList.contains("modal-open")) {
document.body.classList.remove("modal-open");
}
};
}, [props.show]);
const { data, loading, error } = useQuery(GET_USER_BY_ID, {
variables: { username: props.username },
});
const dataUser = data?.getUserByID;
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
const onChange = (event) => {
setValue({
...value,
[event.target.name]: event.target.value
})
}
return (
<Modal show={props.show}>
<Modal.Header>
<Modal.Title> <span>FORMULIR AKUN PENGGUNA</span> </Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group className="mb-3">
<Form.Label>Role Akun</Form.Label>
<Form.Select aria-label="pilih user role">
<option>{dataUser.group_id}</option>
<option>Admin RJ</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Nama Lengkap</Form.Label>
<Form.Control name="full_name" value={dataUser.full_name} onChange= {onChange} />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Email</Form.Label>
<Form.Control type="email" name="email" value={dataUser.email} onChange={ onChange }/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Phone</Form.Label>
<Form.Control type="text" name="phone" value={dataUser.phone} onChange={ onChange } />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Address</Form.Label>
<Form.Control type="text" name="address" value={dataUser.address} onChange={ onChange } />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Password</Form.Label>
<Form.Control type="password" name="password" value={dataUser.password} onChange={ onChange } />
</Form.Group>
<Form.Label>Aktifkan Akun</Form.Label>
{dataUser.status === 'ACTIVE' ? (
<Form.Check
type="switch"
checked={isChecked}
onChange={(event) => setIsChecked(event.target.checked)}
id="custom-switch"
label="Aktifkan Akun"
/> ) : (
<Form.Check
type="switch"
id="custom-switch"
checked={isChecked}
onChange={(event) => setIsChecked(event.target.checked)}
label="Aktifkan Akun"
/>
)}
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" type="submit" >Submit</Button>
<Button variant="secondary" onClick={props.onClose}>
Close
</Button>
</Modal.Footer>
</Modal>
);
};
export default ModalEdit;
Question
How can i'm edit the form input?
Any help will be apprieciated, thank you
The value prop of your inputs are causing this issue. Instead of binding the value directly to dataUser.address and such, you should set them to value.address and so on.
As for showing the user's data, you should map the values when creating the state.
Your state should be as follows:
const [value, setValue] = useState({
full_name: dataUser.full_name,
email: dataUser.email,
phone: dataUser.phone
address: dataUser.address,
password: dataUser.password,
group_id: dataUser.group_id,
});
And your input should be as follows:
<Form.Control name="full_name" value={value.full_name} onChange= {onChange} />

Error: Cannot read property "name" of undefined. However, after the page is refreshed, the error is removed

I have the following code for when the profile route is being called:
import React, { useState, useEffect } from 'react'
import { Row, Col, Form, Button } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import Message from '../components/Message'
import Loader from '../components/Loader'
import { getUserDetails } from '../actions/userActions'
const ProfileScreen = ({ location, history }) => {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const dispatch = useDispatch()
const userDetails = useSelector((state) => state.userDetails)
const { loading, user, error } = userDetails
const userLogin = useSelector((state) => state.userLogin)
const { userInfo } = userLogin
useEffect(() => {
if (!userInfo) {
history.push('/login')
} else {
if (!user.name) {
dispatch(getUserDetails('profile'))
} else {
setName(user.name)
setEmail(user.email)
}
}
}, [history, userInfo, dispatch, user])
const submitHandler = (e) => {
e.preventDefault()
// DISPATCH PROFILE UPDATE
}
return (
<Row>
<Col md={3}>
<h1>Sign Up</h1>
{error && <Message variant='danger'>{error}</Message>}
{loading && <Loader />}
<Form onSubmit={submitHandler}>
<Form.Group controlId='name'>
<Form.Label>Full Name</Form.Label>
<Form.Control
type='name'
placeholder='Enter your Full Name'
value={name}
onChange={(e) => setName(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId='email'>
<Form.Label>Email Address</Form.Label>
<Form.Control
type='email'
placeholder='Enter your email address'
value={email}
onChange={(e) => setEmail(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId='password' className='my-3'>
<Form.Label>Password</Form.Label>
<Form.Control
type='password'
placeholder='Enter your password'
value={password}
onChange={(e) => setPassword(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId='confirmPassword' className='my-3'>
<Form.Label>Confirm Password</Form.Label>
<Form.Control
type='password'
placeholder='Confirm your password'
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
></Form.Control>
</Form.Group>
<Button type='submit' variant='primary' className='my-4'>
Update
</Button>
</Form>
</Col>
<Col md={9}>
<h2>My Orders</h2>
</Col>
</Row>
)
}
export default ProfileScreen
After the code is being executed, and the user goes to the profile route, at first it shows "Cannot read property 'name' of undefined"
however after the page is being refreshed, the error gets removed and the app then works completely fine.
This is the error being shown
Please check your condition.
useEffect(() => {
if (!userInfo) {
history.push('/login')
} else {
if (Object.keys(user).length === 0) {
dispatch(getUserDetails('profile'))
} else {
setName(user.name)
setEmail(user.email)
}
}
}, [history, userInfo, dispatch, user])

Gatsby send file from form data to getform.io with axios

I can post name and emails to my getform.io form fine. But the file just shows up as [] and the files tab is empty. I see in the network tab my request payload is {email: "test#gmail.com", file: {}, name: "test"}
Any help is appreciated, thank you!
import React, { useState } from "react"
import { Button, Form } from "react-bootstrap"
import axios from "axios"
const SingleJobForm = ({ jobTitle, jobEmployer }) => {
const [email, setEmail] = useState(null)
const [name, setName] = useState(null)
const [file, setFile] = useState(null)
const handleSubmit = e => {
e.preventDefault()
let formData = { email, name, file }
axios({
method: "POST",
url: "https://getform.io/f/5e110b76-25c7-4a13-9464-e53d2493f446",
data: formData,
header: {
"Content-Type": "multipart/form-data; boundary=${form._boundary}",
},
})
}
return (
<Form onSubmit={handleSubmit}>
<Form.Group controlId="formName">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
placeholder="First Last Name"
onChange={e => {
setName(e.target.value)
}}
/>
</Form.Group>
<Form.Group controlId="formEmail">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
placeholder="Enter email"
value={email || ""}
onChange={e => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group onChange={e => setFile(e.target.files[0])}>
<Form.File id="resume" label="Resume" />
</Form.Group>
<Form.Group controlId="formCheckbox">
<Form.Check type="checkbox" label="I confirm I am 18 years or older" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
)
}
export default SingleJobForm
The solution from this stack overflow post worked
I had to use FormData interface.

Check user name availability from firebase in react

I am currently stuck on checking unique username in the sign up(on firebase) in react. My goal is that
1. when the user input the username, the function checkNameAvalaible go to the firebase database and check if the name exists.
2.if the name exists set the state of usernameavalaible to false, and set it to true if name works
3.disable the submit button of the sign up if the usernameavalaible is false.
4.If the username is taken, use helper text in textfield to alert the current user.
I am stuck with the if statement, I tried a few times and it is not working here is my code
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { auth } from "../firebase";
import { db} from "../firebase";
import "./auth.css";
import * as routes from "../constants/routes";
import { SignInLink } from "./SignIn";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
const SignUpPage = ({ history }) => (
<div align="center" className="SignUpBox">
<h1>SignUp</h1>
<SignUpForm history={history} />
<SignInLink />
</div>
);
const INITIAL_STATE = {
username: "",
name: "",
email: "",
passwordOne: "",
passwordTwo: "",
error: null
};
const byPropKey = (propertyName, value) => () => ({
[propertyName]: value
});
class SignUpForm extends Component {
state = { ...INITIAL_STATE };
// checkPassword() {
// if(!this.state.passwordOne || this.state.passwordOne !== this.state.passwordTwo){
// this.setState({error:"passwords do not match"});
// }
// else {
// this.setState({error:null});
// }
// }
onSubmit = event => {
event.preventDefault();
const { email, passwordOne, name, username } = this.state;
auth
.doCreateUserWithEmailAndPassword(
email,
passwordOne,
name,
username
)
.then(authUser => {
this.setState(() => ({ ...INITIAL_STATE }));
this.props.history.push(routes.HOME);
})
.catch(error => {
this.setState(byPropKey("error", error));
});
};
render() {
var usernameAvalaible
const {
username,
name,
email,
passwordOne,
passwordTwo,
error
} = this.state;
checkNameAvalaible(){
if (db.doc(`/users/${username}`).get().exists){
this.setState{usernameAvalaible:false};
}
else{
this.setState{usernameAvalaible:true};
}
};
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === "" ||
email === "" ||
name === "" ||
username === ""|| usernameAvalaible===false;
return (
<form onSubmit={this.onSubmit}>
<TextField
name="Username"
id="standard-secondary"
label="User name"
color="primary"
value={username}
onChange={event =>
this.setState(byPropKey("username", event.target.value))
}
type="text"
/>
<TextField
name="name"
value={name}
id="standard-secondary"
label="Full name"
color="primary"
onChange={event =>
this.setState(byPropKey("name", event.target.value))
}
type="text"
/>
<TextField
name="email"
value={email}
id="standard-secondary"
label="Email Address"
color="primary"
onChange={event =>
this.setState(byPropKey("email", event.target.value))
}
type="email"
/>
<TextField
name="password"
value={passwordOne}
id="standard-secondary"
label="Password"
color="primary"
onChange={event =>
this.setState(byPropKey("passwordOne", event.target.value))
}
type="password"
/>
<TextField
name="ConfirmPassword"
value={passwordTwo}
id="standard-secondary"
label="Comfirm Password"
color="primary"
onChange={event =>
this.setState(byPropKey("passwordTwo", event.target.value))
}
type="password"
/>
<br />
<br />
<Button
type="submit"
disabled={isInvalid}
variant="contained"
color="primary"
>
Sign Up
</Button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</form>
);
}
}
const SignUpLink = () => (
<p>
Don't have an account? <Link to={routes.SIGN_UP}>Sign Up</Link>
</p>
);
export default SignUpPage;
export { SignUpForm, SignUpLink };

Modal doesnt show up in react

I'm new to react thus the question.
This is my CustomModal,
import React from 'react';
import {useState} from "react";
import {Button, Modal} from "react-bootstrap";
const CustomModal = (props) =>{
const [show, setShow] = useState(true);
const handleClose = () => setShow(false);
return (
<div>
<Modal show={show} animation={false}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>{props.message}</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
)
};
export default CustomModal;
I want to render it inside a class component when user submits a registration form.
class Register extends React.Component {
state = {
email : '',
username: '',
password: '',
second_password: ''
};
handleSubmit = async (event) =>{
event.preventDefault();
const emailValidated = await this.validateEmail(this.state.email);
const usernameValidated = this.validateUsername(this.state.username);
const passwordValidated = this.validatePassword(this.state.password, this.state.second_password);
let registrationComplete = false;
if(emailValidated === true && usernameValidated === true && passwordValidated === true){
registrationComplete = await this.register(this.state.email, this.state.username, this.state.password);
console.log(registrationComplete);
this.showModal("Hello World!"); //This is the function begin called to show the modal.
}
};
validateUsername = (username) =>{
return true;
};
validatePassword = (password, second) =>{
return true;
};
validateEmail = async (email) =>{
return true;
};
//This is the function that should display the modal
showModal = (message) =>{
return (<CustomModal message={message}/>);
};
register = async (email, username, password) =>{
return true;
};
render() {
return (
<div className="register">
<h1>Register</h1>
<Form onSubmit={this.handleSubmit}>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email"
placeholder="Enter email"
value={this.state.email}
onChange={event => this.setState({email: event.target.value})}/>
<Form.Text className="text-muted">
Please make sure you've access to this mail. You'll receive an activation code here.
</Form.Text>
</Form.Group>
<Form.Group controlId="formPlainText">
<Form.Label className="form-label">Username</Form.Label>
<Form.Control type="text"
placeholder="Username"
value={this.state.username}
onChange={event => this.setState({username: event.target.value})}/>
<Form.Text className="text-muted">
Please make it atleast 8 characters long.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
value={this.state.password}
onChange={event => this.setState({password: event.target.value})}/>
<Form.Text className="text-muted">
Please make sure it's atleast 8 characters long and uses a mix of letters and numbers.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Retype Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
value={this.state.second_password}
onChange={event => this.setState({second_password: event.target.value})}/>
</Form.Group>
<Button variant="primary" type="submit">
Register
</Button>
</Form>
</div>
);
}
}
export default Register;
All the values are correct and the console log shows true but the Modal doesn't display. Can someone help me with this?
There are some issues on your code
The customModal has to be part of the render of the Register component
There should be a state to track the status of the modal from the Register component
Also the register has to be notified when the Modal closes
I have modified your code and working. You can find it live here
I prefer attack this problem creating portals here documentation.
you might to have issues with z-index in the future.
Basically, you create an element outside the DOM hierarchy.
Now, your issue is that, you must render modal inside render method and control it, with boolean state "showModal".
I prepare for you an example:
example in my GitHub account
git clone ...
npm install
npm run start
preview:

Categories

Resources