Have separete handlers where handleSubmit is to submit to server while handleAdd is for keeping some values in UI component states.
const handleSubmit = (event) => {
const isValid = event.currentTarget.checkValidity();
if (!isValid) {
setValidated(true);
} else {
//Submitting to server
}
}
const handleAdd = (event) => {
const isValid = isInnerValid();
if (!isValid) {
setValidated(true); //This enables validation for outer fields as well but I am expecting not to.
} else {
//Saving in component states.
}
}
<Fragment>
<Form noValidate validated={validated} onSubmit={handleSubmit}>
//Main form
<Form.Group>
<Form.Label>
Outer field:
</Form.Label>
<InputGroup hasValidation>
<Form.Control required type="text" ... />
<Form.Control.Feedback type="invalid">
This field is required.
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
//Sub-section of form
<Form.Group>
<Form.Label>
Inner field:
</Form.Label>
<InputGroup hasValidation>
<Form.Control required type="text" ... />
<Form.Control.Feedback type="invalid">
This field is required.
</Form.Control.Feedback>
</InputGroup>
//On click of of Add button dont want to validate Outer field.
<Button onClick={handleAdd}>
Add
</Button>
</Form.Group>
//Submit button for whole form.
<Button type="submit">
Submit
</Button>
</Form>
</Fragment>
On click of Add but I want to validate only the Inner field not Outer Field
The validation on form level enables validation on all fields, how to separate it out?
Related
Trying to make the onChange event of the following componenet to fire but it does not. When I type in the seach box nothing is printed on the console. No change is fired
const Search = () => {
let history = useHistory()
const [search, setSearch] = useState('')
const handleSubmit = (e) => {
e.preventDefault()
if (search) {
console.log("typing..")
history.push(`/?search=${search}`)
} else {
history.push(history.push(history.location.pathname))
}
}
return (
<Form.Group controlId='searchbox' onSubmit={handleSubmit}>
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
>
</Form.Control>
<Button type='submit'>Submit</Button>
</Form.Group>
)
}
export default Search
const Home =()=>{
return (<div><Search /><div>)
}
export default Home
I still can't identify where the error is. How do I get it working?
I am assuming Form.Control is a custom control or a third-party control, hence you cannot convert it to a controlled input. You could try creating a ref and get the value from the ref in the onChange event handler. If the custom control is not a third party control, then you could add the onChange handler inside the Form.Control component and pass a function reference to the control.
Edit:
Here is your solution : https://codesandbox.io/s/vigorous-mclean-4jusl?file=/src/App.js
In case you see an error in the sandbox, refresh the page. There seems to be some error with codesandbox.
Explanation:
Create a ref to access the input using useRef:
const controlref = useRef();
Pass the ref to the control:
<Form.Control
onChange={handleChange}
**ref={controlref}**
type="text"
placeholder="search..."
/>
Get the value in onChange using the ref:
const handleChange = (e) => {
console.log(controlref.current.value);
setSearch(controlref.current.value);
};
Firstly, html "input" is a self closing element.
Secondly, You have missed the "value" inside the Input component.
Your code:
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
></Form.Control>
Solution:
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
Try using event onInput instead:
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onInput={(e) => setSearch(e.target.value)}
/>
I can't believe I made this silly mistake. The issue is due to the fact that I omitted the tag and placed the submit button within the <Form.Group> which doesn't have the property to handle onSubmit event. So I changed this
return (
<Form.Group controlId='searchbox' onSubmit={handleSubmit}>
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
>
</Form.Control>
<Button type='submit'>Submit</Button>
</Form.Group>
)
It was modified to this:
return (
<Form onSubmit={handleSubmit} >
<Form.Group controlId='searchbox' >
<Form.Control
className="auth-input"
type='text'
placeholder="Search..."
onChange={(e) => setSearch(e.target.value)}
>
</Form.Control>
<Button type='submit'>Submit</Button>
</Form.Group>
</Form>
)
EDIT: Require checkbox to be checked is resolved, just cant work out how to get the checkbox values into the email.
The aim: Pass the value of state.TNC and state.promos into the emailjs.sendForm.
The form should return alert "You need to accept Terms and Conditions before proceeding.
I am lost for words as to what I need to google to find a resolution.
Here is my code that I thought was going to do that for me.
sendEmail = (e, props) => {
e.preventDefault();
if (this.state.TNC !== true) {
return emailjs
.sendForm("test", "testTemp", e.target, "user_EPYkKnHwljQTCbuiyfJkzO7YD")
.then(
(result) => {
alert("Email sent successfully!");
e.target.reset();
},
(error) => {
alert("Email send failed... :( I had one job...");
}
);
} else {
return alert(
"You need to accept the Terms and Conditions before proceeding."
);
}
};
The code for the two checkboxes, (I have tried them with and without the value={this.state.TNC})
<Form.Group widths="equal">
<Form.Field>
<Checkbox
label="I agree to the Terms and Conditions"
required
control={Checkbox}
data="TNC"
onChange={this.onToggle}
value={this.state.TNC}
/>
</Form.Field>
<Form.Field>
<Checkbox
label="Send me occasional updates and promotions"
defaultChecked
control={Checkbox}
data="promos"
value={this.state.promos}
onChange={this.onTogglePromos}
/>
</Form.Field>
</Form.Group>
Here is the full code, and you can find a semi-functional version of the form at https://test.ghostrez.net
import React from "react";
import emailjs from "emailjs-com";
import { Component } from "react";
import { Button, Checkbox, Form, Input, TextArea } from "semantic-ui-react";
export default class ContactUs extends React.Component {
constructor(props) {
super(props);
this.state = {
TNC: false,
promos: true,
};
}
onToggle = () => {
const TNC = !this.state.TNC;
this.setState({ TNC });
};
onTogglePromos = () => {
const promos = !this.state.promos;
this.setState({ promos });
};
sendEmail = (e, props) => {
e.preventDefault();
if (this.state.TNC !== true) {
return emailjs
.sendForm("test", "testTemp", e.target, "user_EPYkKnHwljQTCbJkzO7YD")
.then(
(result) => {
alert("Email sent successfully!");
e.target.reset();
},
(error) => {
alert("Email send failed... :( I had one job...");
}
);
} else {
return alert(
"You need to accept the Terms and Conditions before proceeding."
);
}
};
render() {
return (
<Form onSubmit={this.sendEmail}>
<Form.Group widths="equal">
<Form.Field
id="firstName"
control={Input}
label="First name"
name="firstName"
placeholder="First name"
required
/>
<Form.Field
id="lastName"
name="lastName"
control={Input}
label="Last name"
placeholder="Last name"
/>
</Form.Group>
<Form.Group widths="equal">
<Form.Field
id="Email"
control={Input}
label="Email"
name="email"
placeholder="joe#schmoe.com"
onChange=""
required
/>
<Form.Field
id="Phone"
control={Input}
label="Phone"
name="phone"
placeholder="0469 420 689"
required
/>
</Form.Group>
<Form.Field
id="Message"
control={TextArea}
label="Message"
name="message"
placeholder="Message"
required
/>
<Form.Group widths="equal">
<Form.Field>
<Checkbox
label="I agree to the Terms and Conditions"
required
control={Checkbox}
data="TNC"
onChange={this.onToggle}
value={this.state.TNC}
/>
</Form.Field>
<Form.Field>
<Checkbox
label="Send me occasional updates and promotions"
defaultChecked
control={Checkbox}
data="promos"
value={this.state.promos}
onChange={this.onTogglePromos}
/>
</Form.Field>
</Form.Group>
<Form.Field
id="Submit"
control={Button}
type="submit"
value="submit"
positive
content="Submit"
/>
</Form>
);
}
}
Thank you for your help, I really appreciate it.
It's the way you have written the logic
this.state.TNC !== true, what does this equate to? false !== true which is true, hence it goes in the if block. I think what you want is if(this.state.TNC), i.e. if it's true, then go in the if block.
Also, your Email field throws an error because it's onChange is an empty string.
I would like to try to get rid of this warning
index.js:1 Warning: Received true for a non-boolean attribute validate.
If you want to write it to the DOM, pass a string instead: validate="true" or validate={value.toString()}.
I'm making a validation form for subscribing users. I show tooltip, when the email field is not filled out and the user tries to press the subscribe button.
Here is my form (using Material UI styling):
<Form
onSubmit={onSubmit}
initialValues={{ userEmail: 'johndoe#example.com', arn: 'AA-01-23-45-678901-2' }}
validate={validate}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit} validate>
<DialogContentText>
To subscribe to this website, please enter your email address here. We will send updates
occasionally.
</DialogContentText>
<TextField
label="Email Address"
name="userEmail"
margin="none"
required={true}
fullWidth
/>
{formSubmitted && <Grid item xs={12}>
<Typography name='submitMessage' variant='subtitle1'>You have subscribed to {values.arn}. {/* Connect to backend here */}</Typography>
</Grid>}
<DialogActions>
<Button /* onClick={handleClose} */ color="primary" type="submit" disabled={submitting}>
Subscribe
</Button>
<Button onClick={handleClose} color="primary">
Close
</Button>
</DialogActions>
</form>
)}
/>
And my validate function outside of the component function but within the same js file:
const validate = values => {
const errors = {};
if (!values.userEmail) {
errors.userEmail = 'Required';
}
return errors;
};
For future readers, the problem ended up being with the validation function I was using within the Form tags!
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"
/>
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: