I am currently working on a form having checkboxes which has to be validated using react JS. I need it to show an error saying 'Please select atleast 2 checkbox' if less than 2 checkboxes are checked. I've tried using the if condition but its not working. I have referred a lot of of websites but couldn't come up with a proper solution. Please do help me.
MY CODE:
class App extends React.Component {
state = {
checkbox: "",
checkboxValid: false,
errorMsg: {},
};
validateForm = () => {
const { checkboxValid } = this.state;
this.setState({
formValid: checkboxValid,
});
};
updateCheckbox = (checkbox) => {
this.setState({ checkbox }, this.validateCheckbox);
};
validateCheckbox = () => {
const { checkbox } = this.state;
let checkboxValid = true;
let errorMsg = { ...this.state.errorMsg };
if (checkbox.checked < 2) {
checkboxValid = false;
errorMsg.checkbox = "Please select atleast 2 checkbox";
}
this.setState({ checkboxValid, errorMsg }, this.validateForm);
};
render() {
return (
<div>
<label htmlFor="checkbox">checkbox</label>
<ValidationMessage
valid={this.state.checkboxValid}
message={this.state.errorMsg.checkbox}
/>
<input
type="checkbox"
onChange={(e) => this.updateCheckbox(e.target.value)}
/>
Sports
<br></br>
<input
type="checkbox"
onChange={(e) => this.updateCheckbox(e.target.value)}
/>
Business
<br></br>
<input
type="checkbox"
onChange={(e) => this.updateCheckbox(e.target.value)}
/>
Health
<br></br>
<input
type="checkbox"
onChange={(e) => this.updateCheckbox(e.target.value)}
/>
Society
<br></br>
<div>
<button
className="button"
type="submit"
disabled={!this.state.formValid}
>
Submit
</button>
</div>
</div>
);
}
}
Define count in the state and update it based on the checkbox selection,
state = {
checkbox: "",
checkboxValid: false,
errorMsg: {},
selectedCheckBox: 0
};
Update Logic:-
updateCheckbox = ({ name, checked }) => {
this.setState(
(prev) => ({
checkbox: checked,
selectedCheckBox: checked
? prev.selectedCheckBox + 1
: prev.selectedCheckBox - 1
}),
this.validateCheckbox
);
};
Use the selectedCheckBox count in the state for validation
Completed Code:-
import React from "react";
import "./styles.css";
export default class App extends React.Component {
state = {
checkbox: "",
checkboxValid: false,
errorMsg: {},
selectedCheckBox: 0
};
validateForm = () => {
const { checkboxValid } = this.state;
this.setState({
formValid: checkboxValid
});
};
updateCheckbox = ({ name, checked }) => {
this.setState(
(prev) => ({
checkbox: checked,
selectedCheckBox: checked
? prev.selectedCheckBox + 1
: prev.selectedCheckBox - 1
}),
this.validateCheckbox
);
};
validateCheckbox = () => {
const { checkbox } = this.state;
let checkboxValid = true;
let errorMsg = { ...this.state.errorMsg };
if (this.state.selectedCheckBox < 2) {
checkboxValid = false;
errorMsg.checkbox = "Please select atleast 2 checkbox";
}
this.setState({ checkboxValid, errorMsg }, this.validateForm);
};
render() {
return (
<div>
<label htmlFor="checkbox">checkbox</label>
{/* <ValidationMessage
valid={this.state.checkboxValid}
message={this.state.errorMsg.checkbox}
/> */}
<input
type="checkbox"
name="business"
onChange={(e) => this.updateCheckbox(e.target)}
/>
Sports
<br></br>
<input
type="checkbox"
name="health"
onChange={(e) => this.updateCheckbox(e.target)}
/>
Business
<br></br>
<input
type="checkbox"
name="society"
onChange={(e) => this.updateCheckbox(e.target)}
/>
Health
<br></br>
<input
type="checkbox"
onChange={(e) => this.updateCheckbox(e.target)}
/>
Society
<br></br>
<div>
<button
className="button"
type="submit"
disabled={!this.state.formValid}
>
Submit
</button>
<br />
<b style={{ fontSize: "30px" }}>{this.state.selectedCheckBox}</b>
</div>
</div>
);
}
}
Working Demo - https://codesandbox.io/s/frosty-colden-8hdm4?file=/src/App.js:0-2160
One way to solve this is by having a different state for each checkbox. Set a name for each checkbox so that it can be access by e.target.name
Notice that the name of the input is the same as the state.
state = {
checkbox1: false,
checkbox2: false,
checkboxValid: false,
};
updateCheckbox = (e) => {
this.setState({ e.target.name: e.target.checked });
};
if(this.state.checkbox1 && this.state.checkbox2) {
//both are checked!
}
change input to
<input
name="checkbox1"
type="checkbox"
onChange={this.updateCheckbox}
checked={this.state.checkbox1}
/>
Related
This is my edit user page and I would like it to pull one user at a time for editing.
When you click the pencil to edit I would like just the one user pulled but instead I get all of them like in the second image.
in the code below I map them out but have tried using filter and a reducer but no fix has worked as of yet. would an inline condition be better like the one below but have not figured how to get the right ID from the URL.
{Collectors.CollectorID === Collectors.CollectorID && <div><h2>1-30 days past due in Tandem – all credit types</h2> <p>{Collectors.CollectorCode}{Collectors.FinanceCompany}</p></div>}
import React from "react";
import axios from 'axios';
class UpdateUser extends React.Component {
constructor(props) {
super(props);
this.state = {
collectorList: [],
CollectorID: props.CollectorID,
ProgramBucketID: props.ProgramBucketID,
CollectorOptionsID: props.CollectorOptionsID,
FinanceCompanyID: props.FinanceCompanyID,
Active: '',
LastName: '',
CollectorCode: '',
Aging1to15: '',
Aging31to45: '',
Aging31to60: '',
AgingOver60: '',
ProgramBucketA: '',
ProgramBucketB: '',
ProgramBucketC: '',
ProgramBucketSU: '',
FinanceCompany: ''
}
this.handleActiveChange = this.handleActiveChange.bind(this);
this.handleAging115Change = this.handleAging115Change.bind(this);
this.handleAging3145Change = this.handleAging3145Change.bind(this);
this.handleAging3160Change = this.handleAging3160Change.bind(this);
this.handleAgingOver60Change = this.handleAgingOver60Change.bind(this);
this.handleProgramAChange = this.handleProgramAChange.bind(this);
this.handleProgramBChange = this.handleProgramBChange.bind(this);
this.handleProgramCChange = this.handleProgramCChange.bind(this);
this.handleProgramSUChange = this.handleProgramSUChange.bind(this);
}
componentDidMount(e) {
this.getCollectors()
}
handleActiveChange(e) {
this.setState({
Active: !this.state.Active
})
}
handleAging115Change() {
this.setState({
Aging1to15: !this.state.Aging1to15
})
}
handleAging3145Change() {
this.setState({
Aging31to45: !this.state.Aging31to45
})
}
handleAging3160Change() {
this.setState({
Aging31to60: !this.state.Aging31to60
})
}
handleAgingOver60Change() {
this.setState({
AgingOver60: !this.state.AgingOver60
})
}
handleProgramAChange() {
this.setState({
ProgramBucketA: !this.state.ProgramBucketA
})
}
handleProgramBChange() {
this.setState({
ProgramBucketB: !this.state.ProgramBucketB
})
}
handleProgramCChange() {
this.setState({
ProgramBucketC: !this.state.ProgramBucketC
})
}
handleProgramSUChange() {
this.setState({
ProgramBucketSU: !this.state.ProgramBucketSU
})
}
getCollectors = () => {
axios.get(`http://localhost:5000/getCollectors`)
.then((result) => result.data)
.then((result) => {
this.setState({collectorList: result});
});
};
onUpdateClick = CollectorID => {
axios.put(`http://localhost:5000/UpdateUser/${CollectorID}`, {
CollectorID: this.state.CollectorID,
CollectorOptionsID: this.state.CollectorOptionsID,
ProgramBucketID: this.state.ProgramBucketID,
FinanceCompanyID: this.state.FinanceCompanyID,
Active: this.state.Active,
LastName: this.state.LastName,
CollectorCode: this.state.CollectorCode,
Aging1to15: this.state.Aging1to15,
Aging31to45: this.state.Aging31to45,
Aging31to60: this.state.Aging31to60,
AgingOver60: this.state.AgingOver60,
ProgramBucketA: this.state.ProgramBucketA,
ProgramBucketB: this.state.ProgramBucketB,
ProgramBucketC: this.state.ProgramBucketC,
ProgramBucketSU: this.state.ProgramBucketSU,
FinanceCompany: this.state.FinanceCompany
});
};
render() {
// console.log(this.state);
return (
<div>
<h1>Update Collectors</h1>
<div className="wrapper">
{this.state.collectorList.map((Collectors) => (
<form className="updateUserForm" key={Collectors.CollectorID}>
<div className="updateUserItem">
<b>{Collectors.FirstName} {Collectors.LastName} | {Collectors.CollectorCode}</b>
{/*Active or inactive User*/}
<label>Active Status</label>
<input
type='checkbox'
name="Active"
value={this.state.Active}
defaultChecked={Collectors.Active === false ? false : true}
onChange={this.handleActiveChange}
/>
{/*Collector Last Name*/}
<label>Last Name</label>
<input
type="text"
name="LastName"
defaultValue={Collectors.LastName}
onChange={e => this.setState({
LastName: e.target.value
})}
/>
{/*Collector Code First Initial Middle Initial Last Initial*/}
<label>Collector Code</label>
<input
type="text"
name="CollectorCode"
defaultValue={Collectors.CollectorCode}
onChange={e => this.setState({
CollectorCode: e.target.value
})}
/>
{/*Aging Bucket selection section */}
<label>Aging Bucket</label>
<div className='newUserCheckboxContainer'>
<label className='newUserCheckboxLabel'>1-15<br/>
<input
type='checkbox'
className='AgingBucketCheckbox'
value={this.state.Aging1to15}
defaultChecked={Collectors.Aging1to15 === false ? false : true}
onChange={this.handleAging115Change}
/></label>
<label className='newUserCheckboxLabel'>31-45<br/>
<input
type='checkbox'
className='AgingBucketCheckbox'
value={this.state.Aging31to45}
defaultChecked={Collectors.Aging31to45 === false ? false : true}
onChange={this.handleAging3145Change}
/></label>
<label className='newUserCheckboxLabel'>31-60<br/>
<input
type='checkbox'
className='AgingBucketCheckboxsm'
value={this.state.Aging31to60}
defaultChecked={Collectors.Aging31to60 === false ? false : true}
onChange={this.handleAging3160Change}
/></label>
<label className='newUserCheckboxLabel'>Over 60<br/>
<input
type='checkbox'
className='AgingBucketCheckboxlg'
value={this.state.AgingOver60}
defaultChecked={Collectors.AgingOver60 === false ? false : true}
onChange={this.handleAgingOver60Change}
/></label>
</div>
{/*Progam code selection section*/}
<label>Program Bucket</label>
<div className='newUserCheckboxContainer'>
<label className='newUserCheckboxLabel'>A<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketA}
defaultChecked={Collectors.ProgramBucketA === false ? false : true}
onChange={this.handleProgramAChange}
/></label>
<label className='newUserCheckboxLabel'>B<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketB}
defaultChecked={Collectors.ProgramBucketB === false ? false : true}
onChange={this.handleProgramBChange}
/></label>
<label className='newUserCheckboxLabel'>C<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketC}
defaultChecked={Collectors.ProgramBucketC === false ? false : true}
onChange={this.handleProgramCChange}
/></label>
<label className='newUserCheckboxLabel'>SU<br/>
<input
type='checkbox'
className='ProgramBucketChecbox'
value={this.state.ProgramBucketSU}
defaultChecked={Collectors.ProgramBucketSU === false ? false : true}
onChange={this.handleProgramSUChange}
/></label>
</div>
{/*Finance Company selection section*/}
<label>Finance Company</label>
<div className='newUserCheckboxContainer'>
<label className='newUserCheckboxLabel'>
<input
type="text"
name="FinanceCompany"
defaultValue={Collectors.FinanceCompany}
onChange={e => this.setState({
FinanceCompany: e.target.value
})}
/></label>
</div>
<button className="updateUserButton" onClick={() => this.onUpdateClick(Collectors.CollectorID) }>Update User</button>
</div>
</form>
))}
</div>
</div>
);
}
}
export default UpdateUser;
After going through some tests I found the below code works wonderfully if anyone is having this issue.
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useParams } from "react-router-dom";
const UpdateUser = () => {
const { CollectorID } = useParams();
const [user, setUser] = useState({
Active: '',
FirstName: '',
LastName: '',
CollectorCode: ''
});
const { Active, FirstName, LastName, CollectorCode } = undefined || user;
const onInputChange = e => {
setUser({
...user, [e.target.name]: e.target.value,
Active: !Active });
};
useEffect(() => {
loadUser();
}, []);// eslint-disable-line react-hooks/exhaustive-deps
const loadUser = async () => {
const result = await axios.get(`http://localhost:5000/getCollectors/${CollectorID}`);
setUser(result.data[CollectorID - 1]);
// console.log(result.data[CollectorID - 1]);
};
const onSubmit = async e => {
e.preventDefault();
await axios.put(`http://localhost:5000/UpdateUser/${CollectorID}`, {
CollectorID: CollectorID,
Active: Active,
LastName: LastName,
CollectorCode: CollectorCode
});
console.log(CollectorID, Active, LastName, CollectorCode)
};
return (
<div className="previewWrapper">
<h1>Update Collector</h1>
{FirstName} {LastName} | {CollectorCode} - {CollectorID} {console.log(user)}
<form className="newUserForm" onSubmit={e => onSubmit(e)}>
<div className="newUserItem">
{/*Active or inactive User*/}
<label>Active</label>
<input
type='checkbox'
defaultValue={Active}
defaultChecked={Active}
onChange={e => onInputChange(e)}
/>
{/*Collector Last Name*/}
<label>Last Name</label>
<input
type="text"
placeholder="Last Name"
name="LastName"
defaultValue={LastName}
onChange={e => onInputChange(e)}
/>
{/*Collector Code First Initial Middle Initial Last Initial*/}
<label>Collector Code</label>
<input
type="text"
name="CollectorCode"
placeholder="Collector Code"
defaultValue={CollectorCode}
onChange={e => onInputChange(e)}
/>
<button className="newUserButton">Update Collector</button>
</div>
</form>
</div>
);
}
export default UpdateUser;
I have created the following UI:
Initially I want Movie Name, Ratings and Durations column to have a black border while if a user enters an invalid input (or empty), it should be red. As you can see, Ratings is still red despite the fact that the page has just refreshed. It should be black like its siblings. Can anyone point out why is this happening? Perhaps there is a different way to handle validations in React because of state hooks?
Initial State:
const [validations, setValidations] = useState({
isNameValid: true,
isRatingValid: true,
isDurationValid: true,
});
Submit form if it's valid:
const handleFormSubmit = (event) => {
event.preventDefault();
if (validateInput(newMovie)) {
props.onSubmit(newMovie);
setNewMovie(emptyObject);
}
};
CSS Rule(s):
.invalid {
border-color: rgb(238, 90, 90);
}
validateInput function:
const validateInput = (movieObject) => {
if (movieObject.name.length === 0) {
setValidations((prevState) => {
return { ...prevState, isNameValid: false };
});
} else {
setValidations((prevState) => {
return { ...prevState, isNameValid: true };
});
}
if (movieObject.ratings.length === 0) {
setValidations((prevState) => {
return { ...prevState, isRatingValid: false };
});
} else if (
parseInt(movieObject.ratings) >= 0 &&
parseInt(movieObject.ratings) <= 100
) {
setValidations((prevState) => {
return { ...prevState, isRatingValid: true };
});
}
if (movieObject.duration.length === 0) {
setValidations((prevState) => {
return { ...prevState, isDurationValid: false };
});
} else {
setValidations((prevState) => {
return { ...prevState, isDurationValid: true };
});
}
console.log(validations);
return (
validations.isNameValid &&
validations.isRatingValid &&
validations.isDurationValid
);
};
Based on validations state, className is applied (or not):
<form onSubmit={handleFormSubmit}>
<div className="layout-column mb-15">
<label htmlFor="name" className="mb-3">
Movie Name
</label>
<input
className={`${!validations.isNameValid ? "invalid" : ""}`}
type="text"
id="name"
placeholder="Enter Movie Name"
data-testid="nameInput"
value={newMovie.name}
onChange={handleChangeEvent}
/>
</div>
<div className="layout-column mb-15">
<label htmlFor="ratings" className="mb-3">
Ratings
</label>
<input
className={!validations.isRatingsValid ? "invalid" : ""}
type="number"
id="ratings"
placeholder="Enter Rating on a scale of 1 to 100"
data-testid="ratingsInput"
value={newMovie.ratings}
onChange={handleChangeEvent}
/>
</div>
<div className="layout-column mb-30">
<label htmlFor="duration" className="mb-3">
Duration
</label>
<input
className={!validations.isDurationValid ? "invalid" : ""}
type="text"
id="duration"
placeholder="Enter duration in hours or minutes"
data-testid="durationInput"
value={newMovie.duration}
onChange={handleChangeEvent}
/>
</div>
<div className="layout-row justify-content-end">
<button type="submit" className="mx-0" data-testid="addButton">
Add Movie
</button>
</div>
</form>
Anybody can point out a better way to apply validations? I feel like there is a lot of repetition here and the fact that Ratings has a red border even at the start, how can this be fixed?
I am learning React and API. Here I am fetching data from API.I am trying to do on click button one user should appear. Or on click of user name all other user info should appear. I want to display one element from API array.If click on button new user should show. How to get only one user or one user info. Botton I added input box which can shoe only one value. I am stuck here.
import React from 'react';
import './App.css';
class Home extends React.Component {
constructor(props) {
super(props)
this.state = {
items: [],
error: '',
email:'',
phone:'',
companyName:''
}
this.handleInputChange = this.handleInputChange.bind(this);
this.showUserEmail = this.showUserEmail.bind(this);
}
handleInputChange(event){
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSelectUserName = (event) => {
console.log(event.target.value);
const myUser = (event.target.value);
this.setState({ name: event.target.value });
const selectedUser= event.target.value;
}
showUserEmail=(e)=>{
console.log("you are clicking name" );
this.setState({
})
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((result) => {
console.log(result);
console.warn(result);
this.setState({ items: result });
});
}
render() {
const { items } = this.state
return (
<div>
<button className="btn"> Show new User</button>
<div className="new-user" onChange={event => this. handleSelectNewUser(event)}>
{this.state.items.map(items => (
<span key={items.name} value={items.name}>
{items.name} <p></p></span>))}
</div>
<p className="para-text"> Data from API</p>
<div className="user-info">
{
items.length ?
items.map(items => <div key ={ items.id }>
<div className="user-details"> {items.name} </div>
<div className="user-details">{items.phone}</div>
<div className="user-details">{items.company.name}</div>
<div className="user-details">{items.username}</div>
<div className="user-details">{items.email}</div>
<div className="user-details">{items.website}</div>
</div>) : null
}
</div>
<h2>Find User By Username</h2>
<div className="input-box">
<select onChange={event => this.handleSelectUserName(event)}>
{this.state.items.map(items => (
<option key={items.name} value={items.name}>
{items.username}
</option>
))}
</select>
{/* Auto select */}
<div className=" Show-User-Auto">
<div className="input-box">
<input type="text"
placeholder=" Auto Select"
required="required"
onChange={event => this.handleInputChange(event)}
value={this.state.name} />
</div>
</div>
</div>
</div>
);
}
}
export default Home;
You have to maintain a state which contains userId , then you can condition render it like below code
import React from "react";
class Users extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
error: "",
email: "",
phone: "",
companyName: "",
userId: "",
orgList: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.showUserEmail = this.showUserEmail.bind(this);
}
handleSetUserId = (userId) => {
if (userId === this.state.userId) {
this.setState({ userId: "" });
} else {
this.setState({ userId });
}
};
handleInputChange(event) {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSelectUserName = (event) => {
console.log(event.target.value);
const myUserId = event.target.value;
if (myUserId) {
console.log(this.state.orgList, "this.state.orgList");
let selectedUser = this.state.orgList.filter((item) => {
return item.id == Number(myUserId);
});
console.log(selectedUser, "selectedUser");
this.setState({ items: selectedUser });
}
};
showUserEmail = (e) => {
console.log("you are clicking name");
this.setState({});
};
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((result) => {
console.log(result);
console.warn(result);
this.setState({ items: result, orgList: result });
});
}
handleFetchAllUsers=()=>{
this.setState({items:this.state.orgList})
}
render() {
const { items } = this.state;
return (
<div>
<button className="btn" onClick={()=>this.handleFetchAllUsers()}> Show All User</button>
<div
className="new-user"
onChange={(event) => this.handleSelectNewUser(event)}
>
{this.state.items.map((items) => (
<span key={items.name}>
<br />
<span onClick={() => this.handleSetUserId(items.id)}>
{items.name}
<br />
</span>
{items.id === this.state.userId && (
<p>
<br />
<div className="user-details">{items.phone}</div>
<div className="user-details">{items.company.name}</div>
<div className="user-details">{items.username}</div>
<div className="user-details">{items.email}</div>
<div className="user-details">{items.website}</div>
</p>
)}
</span>
))}
</div>
<p className="para-text"> Data from API</p>
<h2>Find User By Username</h2>
<div className="input-box">
<select onChange={(event) => this.handleSelectUserName(event)}>
{this.state.orgList.map((items) => (
<option key={items.name} value={items.id}>
{items.username}
</option>
))}
</select>
{/* Auto select */}
<div className=" Show-User-Auto">
<div className="input-box">
<input
type="text"
placeholder=" Auto Select"
required="required"
onChange={(event) => this.handleInputChange(event)}
value={this.state.name}
/>
</div>
</div>
</div>
</div>
);
}
}
export default Users;
I have implemented the same in codesandbox you can use for ref
React-Select with Formik is not loading the selected value in select componenet but I'm able to get values on form submission and validation also works with Yup
Here is a codesandbox demo for the same - https://codesandbox.io/s/wild-violet-fr9re
https://codesandbox.io/embed/wild-violet-fr9re?fontsize=14
import React, { Component } from "react";
import { Formik, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import Select from "react-select";
const debug = true;
class SelectForm extends Component {
constructor(props) {
super(props);
this.state = {
stateList: [],
stateCity: "",
selectedState: "",
citiesToLoad: []
};
}
handleState(opt) {
console.log(opt.value);
let citiesList = [];
Object.keys(this.state.stateCity).forEach(key => {
if (key === opt.value) {
this.state.stateCity[key].map((cityName, j) => {
citiesList.push(cityName);
});
}
});
this.setState({
selectedState: opt.value,
citiesToLoad: citiesList
});
}
handleMyCity(opt) {
console.log(opt.value);
}
componentDidMount() {
let stateLi = [];
fetch(`stateCity.json`)
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
console.log(data);
for (let key in data) {
if (data.hasOwnProperty(key)) {
stateLi.push(key);
}
}
this.setState({ stateCity: data, stateList: stateLi });
})
.catch(err => {
console.log("Error Reading data " + err); // Do something for error here
});
}
render() {
const { selectedState, stateList, citiesToLoad } = this.state;
const newStateList = stateList.map(item => ({ label: item, value: item }));
const newCitiesToLoad = citiesToLoad.map(item => ({
label: item,
value: item
}));
return (
<div id="signupContainer" className="signinup-container">
<h3 className="mb-4"> Sign Up </h3>
<Formik
initialValues={{
state: selectedState,
city: ""
}}
validationSchema={Yup.object().shape({
state: Yup.string().required("Please select state."),
city: Yup.string().required("Please select city.")
})}
onSubmit={(values, { resetForm, setErrors, setSubmitting }) => {
setTimeout(() => {
console.log("Getting form values - ", values);
setSubmitting(false);
}, 500);
}}
enableReinitialize={true}
>
{props => {
const {
values,
touched,
dirty,
errors,
isSubmitting,
handleChange,
setFieldValue,
setFieldTouched
} = props;
return (
<Form id="signUpForm" className="signinupForm" noValidate>
<div className="form-group">
<label htmlFor="state" className="form-label">
State
</label>
<Select
name="state"
id="state"
onBlur={() => setFieldTouched("state", true)}
value={values.state}
onChange={(opt, e) => {
this.handleState(opt);
handleChange(e);
setFieldValue("state", opt.value);
}}
options={newStateList}
error={errors.state}
touched={touched.state}
/>
</div>
<div className="form-group">
<label htmlFor="city" className="form-label">
City
</label>
<Select
name="city"
id="city"
onBlur={() => setFieldTouched("city", true)}
value={values.city}
onChange={(opt, e) => {
this.handleMyCity(opt);
setFieldValue("city", opt.value);
}}
options={newCitiesToLoad}
/>
</div>
{isSubmitting ? (
<span className="loader-gif">
<img src={loading} alt="Loading..." />
</span>
) : null}
<button
type="submit"
className="btn btn-filled"
disabled={!dirty || isSubmitting}
>
Submit
</button>
{/*Submit */}
</Form>
);
}}
</Formik>
</div>
);
}
}
export default SelectForm;
Upon selecting any value from the selecet dropdown, my selected value should appear in select box
You are setting the field value on onchange of select setFieldValue("state", opt.value); so you don't need to set value for the <Select>:
<Select
name="state"
id="state"
onBlur={() => setFieldTouched("state", true)}
onChange={(opt, e) => {
this.handleState(opt);
handleChange(e);
setFieldValue("state", opt.value);
}}
options={newStateList}
error={errors.state}
touched={touched.state}
/>
change for the both <Select>
react-select accepts an object as a value so you need to pass an object of
let object = {
"label": "Andhra Pradesh",
"value": "Andhra Pradesh"
}
bypassing an object in value the selected value appears in the select box
Here is a codesandbox demo https://codesandbox.io/s/floral-fire-8txrt
so updated code is
import React, { Component } from "react";
import { Formik, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import Select from "react-select";
const debug = true;
class SelectForm extends Component {
constructor(props) {
super(props);
this.state = {
stateList: [],
stateCity: "",
selectedState: "",
citiesToLoad: []
};
}
handleState(opt) {
console.log(opt.value);
let citiesList = [];
Object.keys(this.state.stateCity).forEach(key => {
if (key === opt.value) {
this.state.stateCity[key].map((cityName, j) => {
citiesList.push(cityName);
});
}
});
this.setState({
selectedState: opt,
citiesToLoad: citiesList
});
}
handleMyCity(opt) {
console.log(opt.value);
}
componentDidMount() {
let stateLi = [];
fetch(`stateCity.json`)
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
console.log(data);
for (let key in data) {
if (data.hasOwnProperty(key)) {
stateLi.push(key);
}
}
this.setState({ stateCity: data, stateList: stateLi });
})
.catch(err => {
console.log("Error Reading data " + err); // Do something for error here
});
}
render() {
const { selectedState, stateList, citiesToLoad } = this.state;
const newStateList = stateList.map(item => ({ label: item, value: item }));
const newCitiesToLoad = citiesToLoad.map(item => ({
label: item,
value: item
}));
return (
<div id="signupContainer" className="signinup-container">
<h3 className="mb-4"> Sign Up </h3>
<Formik
initialValues={{
state: selectedState,
city: ""
}}
validationSchema={Yup.object().shape({
state: Yup.string().required("Please select state."),
city: Yup.string().required("Please select city.")
})}
onSubmit={(values, { resetForm, setErrors, setSubmitting }) => {
setTimeout(() => {
console.log("Getting form values - ", values);
setSubmitting(false);
}, 500);
}}
enableReinitialize={true}
>
{props => {
const {
values,
touched,
dirty,
errors,
isSubmitting,
handleChange,
setFieldValue,
setFieldTouched
} = props;
return (
<Form id="signUpForm" className="signinupForm" noValidate>
<div className="form-group">
<label htmlFor="state" className="form-label">
State
</label>
<Select
name="state"
id="state"
onBlur={() => setFieldTouched("state", true)}
value={values.state}
onChange={(opt, e) => {
this.handleState(opt);
handleChange(e);
setFieldValue("state", opt);
}}
options={newStateList}
error={errors.state}
touched={touched.state}
/>
</div>
<div className="form-group">
<label htmlFor="city" className="form-label">
City
</label>
<Select
name="city"
id="city"
onBlur={() => setFieldTouched("city", true)}
value={values.city}
onChange={(opt, e) => {
this.handleMyCity(opt);
setFieldValue("city", opt);
}}
options={newCitiesToLoad}
/>
</div>
{isSubmitting ? (
<span className="loader-gif">
<img src={loading} alt="Loading..." />
</span>
) : null}
<button
type="submit"
className="btn btn-filled"
disabled={!dirty || isSubmitting}
>
Submit
</button>
{/*Submit */}
</Form>
);
}}
</Formik>
</div>
);
}
}
export default SelectForm;
Given a React form, I'm having trouble getting the value from the selected radio button, and text box if other is selected. I should be able to pass the fields into the send() for the post, but not sure how to grab them.
class CancelSurvey extends React.Component {
constructor (props) {
super(props)
this.state = {
reasons: [],
reason: {}
}
this.processData = this.processData.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.otherSelected = this.state.reason === "otheroption";
}
componentDidMount () {
this.fetchContent(this.processData)
}
/**
* Fetch reasons
*/
fetchContent (cb) {
superagent
.get('/api/user/survey')
.then(cb)
}
/**
* Set state after reasons have been fetched
* #param data
*/
processData (data) {
this.setState({
reasons: data.body
})
}
handleSubmit (e) {
e.preventDefault()
let reason = this.state.reason
if (reason === 'otheroption') {
reason = this.state.otherreason
}
console.log(reason)
superagent
.post('/api/user/survey')
.send({
optionId: this.state.reason.reason_id,
optionText: this.state.reason.client_reason,
otherReasonText: this.state.otherreason
})
.then(function (res) {
console.log('Survey Sent!')
})
}
/**
* render
*/
render (props) {
const content = this.props.config.contentStrings
const reason = this.state.reasons.map((reason, i) => {
return (
<div className='fieldset__item' key={i}>
<label>{reason.client_reason}</label>
<input type='radio'
id={reason.reason_id}
value={reason.client_reason}
name='reason'
checked={this.state.reason.reason_id === reason.reason_id}
onChange={() => this.setState({reason})} />
</div>
)
})
return (
<div className='survey'>
<h2 className='heading md'>{content.memberCancel.exitSurvey.heading}</h2>
<p className='subpara'>{content.memberCancel.exitSurvey.subHeading}</p>
<form id='exit-survey' onSubmit={this.handleSubmit}>
<fieldset className='fieldset'>
{ reason }
<label>Other reason not included above:</label>
<input type='radio'
id='otheroption'
name='reason'
value={this.state.reason.otherreason}
onChange={() => this.setState({reason:{reason_id: 70, client_reason: 'other'}})} />
<input className='valid'
type='text'
id='otheroption'
name='othertext'
placeholder={content.memberCancel.exitSurvey.reasonPlaceholder}
onChange={(event) => this.setState({otherreason: event.target.value})} />
</fieldset>
<div className='footer-links'>
<button className='btn btn--primary btn--lg' onClick={this.handleSubmit}>{content.memberCancel.exitSurvey.button}</button>
</div>
</form>
</div>
)
}
}
export default CancelSurvey
Your variables aren't correct. I've update them to what I think is correct.
handleSubmit (e) {
e.preventDefault()
superagent
.post('/api/user/survey')
.send({
optionId: this.state.reason.reason_id,
optionText: this.state.reason.client_reason,
otherReasonText: this.state.reason.otherreason
})
.then(function (res) {
console.log('Survey Sent!')
})
.catch(function (err) {
console.log('Survey submission went wrong...')
})
}
/**
* render
*/
render (props) {
const content = this.props.config.contentStrings
const reason = this.state.reasons.map((reason, i) => {
return (
<div className='fieldset__item' key={i}>
<label>{reason.client_reason}</label>
<input
type='radio'
id={reason.reason_id}
name='reason'
checked={this.state.reason.reason_id === reason.reason_id}
value={reason.client_reason}
onChange={() => this.setState({reason})} />
</div>
)
})
return (
<div className='survey'>
<h2 className='heading md'>{content.memberCancel.exitSurvey.heading}</h2>
<p className='subpara'>{content.memberCancel.exitSurvey.subHeading}</p>
<form id='exit-survey' onSubmit={this.handleSubmit}>
<fieldset className='fieldset'>
{ reason }
<label>Other reason not included above:</label>
<input type='radio'
id='otheroption'
name='otheroption'
value={this.state.reason.otherreason}
checked={this.state.reason.reason_id === 0}
onChange={() => this.setState({ reason: {reason_id: 0, client_reason: ""} })} />
<input className='valid'
type='text'
id='othertext'
name='othertext'
value={this.state.reason.otherreason}
placeholder={content.memberCancel.exitSurvey.reasonPlaceholder}
onChange={(event) => this.setState({ reason: {reason_id: 0, client_reason: "", otherreason: event.target.value} })} />
</fieldset>
<div className='footer-links'>
<button className='btn btn--primary btn--lg' onClick={this.handleSubmit}>{content.memberCancel.exitSurvey.button}</button>
</div>
</form>
</div>
);
}