React form wrong radio values - javascript

I have this modalWindow Component, with a form with a preselected "small" option:
import React from "react";
import pizzaStore from "./stores/PizzaStore";
import { observer } from "mobx-react-lite";
import cartStore from "./stores/CartStore";
import { action } from "mobx";
function ModalWindowComponent({ activeModal, setActiveModal }: any) {
const [price, setPrice] = React.useState(pizzaStore.modalProps.price);
console.log(price);
const handlePriceChange = (opt: string) => {
opt === "small"
? setPrice(pizzaStore.modalProps.price)
: opt === "medium"
? setPrice(pizzaStore.modalProps.price * 1.5)
: setPrice(pizzaStore.modalProps.price * 2);
};
const [selectedOption, setSelectedOption] = React.useState("small");
const setClose = () => {
setSelectedOption("small");
setActiveModal(false);
};
let fixedSize = pizzaStore.size;
let size =
selectedOption === "small"
? fixedSize
: selectedOption === "medium"
? fixedSize * 1.5
: fixedSize * 2;
let obj = {
modalName: pizzaStore.modalProps.name,
modalDesc: pizzaStore.modalProps.description,
modalSize: size,
modalPrice: price,
modalImage: pizzaStore.modalProps.imageUrl,
};
return (
<div
className={activeModal ? "modal active" : "modal"}
onClick={() => {
setActiveModal(false);
setSelectedOption("small");
}}
>
<div
className="modal-content"
onClick={(e) => {
e.stopPropagation();
}}
>
<div className="modal-content-header">
<button onClick={() => setClose()}>Close</button>
</div>
<img
src={pizzaStore.modalProps.imageUrl}
className="modal-content-img"
/>
<p className="modal-content-pizza-name">{pizzaStore.modalProps.name}</p>
<p className="modal-content-pizza-desc">
{pizzaStore.modalProps.description}
</p>
<p className="modal-content-pizza-size">{size}см</p>
<p className="modal-content-pizza-weight">
{pizzaStore.setWeight(selectedOption)}грамм
</p>
<p className="modal-content-pizza-price">{price}Руб.</p>
<form
className="modal-content-sizes-form"
onSubmit={(e: any) => {
cartStore.handleSubmitForm(e, obj);
}}
>
<label>
<input
name="radio-size"
value="small"
type="radio"
onChange={(e) => {
setSelectedOption(e.target.value);
console.log(selectedOption);
handlePriceChange(selectedOption);
}}
checked={selectedOption === "small"}
className="modal-content-sizes-form-option"
/>
Маленькая
</label>
<label>
<input
name="radio-size"
value="medium"
type="radio"
onChange={(e) => {
setSelectedOption(e.target.value);
console.log(selectedOption);
handlePriceChange(selectedOption);
}}
checked={selectedOption === "medium"}
className="modal-content-sizes-form-option"
/>
Средняя
</label>
<label>
<input
name="radio-size"
value="big"
type="radio"
onChange={(e) => {
setSelectedOption(e.target.value);
console.log(selectedOption);
}}
checked={selectedOption === "big"}
className="modal-content-sizes-form-option"
/>
Большая
</label>
<button
onClick={() => {
setClose();
console.log(cartStore.cartItems);
}}
>
Добавить
</button>
</form>
</div>
</div>
);
}
export default observer(ModalWindowComponent);
The selectedOption state should update when a radiobutton is clicked.
however, if I try to log in to the console it gives the wrong values.
For example, when you click the medium valued radio button the console logs "small". The other problem is that the price state doesn't update accordingly with the selected option state. I don't quite understand what is wrong.

That's because state update is batching and asynchronous
You setSelectedOption and handlePriceChange in the same function which cause the issue that you won't get the latest update selectedOption
So you would use the original value like so:
onChange={(e) => {
setSelectedOption(e.target.value);
console.log(selectedOption);
handlePriceChange(e.target.value);
}}
Or having a useEffect waiting for selectedOption to change before calling handlePriceChange:
useEffect(() => {
handlePriceChange(selectedOption);
}, [selectedOption]);

setSelectedOption actually doesn't change the value of selectedOption in your onChange handler. My guess is, it always logs the previous value to the console.
To fix this, store e.target.value in a variable and log that.

Related

onClick function is not called after I have enabled the button in Reactjs

I have a textarea and a button. The button is disabled by default and when the user starts typing, I enable the button to be clicked. But the problem is that, the onClick function is not called while already disabled = false was set.
I've seen this: button onClick doesn't work when disabled=True is initialized (Reactjs)
Seems to be a good idea, but after I setState with the new value, my component is re-rendering, and I don't really want that.
const refText = useRef(null);
const refBtn = useRef(null);
function handleBtnStatus(e) {
let text = e.target.value;
if(text.replace(/\s/g, "").length > 0) {
refBtn.current.disabled = false;
}
else {
refBtn.current.disabled = true;
}
}
function postThis() {
console.log("You posted! Text:", refText.current.value);
// disable again
refBtn.current.disabled = true;
// delete previous text wrote
refText.current.value = "";
}
return (
<>
{isLogged && (
<div className="container">
<div className="content">
<div className="utool-item-text">
<textarea name="textArea" placeholder="Write something.." ref={refText} onChange={(e) => handleBtnStatus(e)}></textarea>
</div>
<div className="utool-item-post">
<button className="ust-btn-post" ref={refBtn} disabled={true} onClick={postThis}>Da Tweet</button>
</div>
</div>
<div className="posts-section">
<div className="list-posts">
{posts.map((p) => {
return (p.hidden === false ? (
<div className="post" key={p.id}>
<div className="post-text">
<span>{p.text}</span>
</div>
</div>
) : (''))
})}
</div>
</div>
</div>
)}
</>
)
Any help?
Use state instead of refs, re-rendering is ok for your case
Simplified example:
import React, { useState } from 'react';
const SimpleExample = () => {
const [textAreaValue, setTextAreaValue] = useState('');
return (
<>
<button disabled={!textAreaValue} onClick={() => console.log('onClick handler')}>
click me
</button>
<textarea value={textAreaValue} onChange={(e) => setTextAreaValue(e.target.value)} />
</>
);
};
And I would recommend checking this Use state or refs in React.js form components?

React onChange method not working in login form

I'm facing this problem while trying to move input value to component state hook using the onChange attribute.
i'll be happy with your help.
import React from 'react'
import { useState } from 'react';
import './userInterface.css';
function UserInterface() {
const [userInfo, setUserInfo] = useState({
isLoggedIn : '',
userName : '',
email : '',
password : ''
})
let usenamePattern = /[A-Za-z0-9]{3,16}./ ;
let emailPattern = /[A-Za-z0-9#.]{7,}/ ;
const getInputToState = (e,inputField) => {
switch(inputField){
case 'username' : {
setUserInfo(userInfo.userName = e.target.value)
console.log(userInfo)
break
}
case 'email' : {
setUserInfo(userInfo.email = e.target.value)
console.log(userInfo)
break
}
case 'password' : {
setUserInfo(userInfo.password = e.target.value)
console.log(userInfo)
break
}
default:
return null
}
console.log(userInfo)
}
const alertForm = () => {
if(userInfo.userName == '' && userInfo.email == '' && userInfo.password == ''){
return{
msg : '',
color : 'green'
}
}
else if(userInfo.userName.match(usenamePattern)){
return {
msg : 'You are allright !',
color : 'limegreen'
}
}else if(!userInfo.userName.match(usenamePattern)){
return {
msg : 'Username should be more than 3 characters and less than 16, and contains only alphabets and numbers',
color : 'red'
}
}
}
return (
<div id='user-div'>
<form id='user-form'>
<h2 id="form-title">Tell us who you are :)</h2>
<ul id="form-inputs">
<li className="form-input">
<input type="text" className="user-input" placeholder='Enter a username' maxLength={16} onChange={getInputToState()}/>
</li>
<li className="form-input">
<input type="text" className="user-input" placeholder='Enter your e-mail' onChange={getInputToState()}/>
</li>
<li className="form-input">
<input type="text" className="user-input" placeholder='Create a password' onChange={(e) => {getInputToState()}}/>
</li>
<li className="form-input">
<a><button className='action-form' id='submit-button' disabled>Submit</button></a>
</li>
</ul>
<h4 id='alert-msg' style={{color : alertForm()?.color}}>{alertForm()?.msg}</h4>
<h3 id='login-sign'>Already have an account ? <a href="/" id='login-form'>Log In</a></h3>
</form>
</div>
)
}
export default UserInterface ;
here is the entire component code, it has no relation with props or exports.
When i write in inputs the console returns nothing which means that the function do not work
The first you should do is change
onChange={(e) => {getInputToState()}}
to
onChange={(e) => {() => getInputToState( e, 'your_field_name' )}}
And inside your getInputToState function you should pass to setUserInfo new userInfo object with mutated fields or one field. Hope this will help.
Your function should look like this:
const getInputToState = (e, inputField) =>
{
const newUserInfo = userInfo; // create new state object
userInfo[inputField] = e.target.value; // Change th value
setUserInfo(newUserInfo); // Set new state
};
You also can get rid of the switch statement.
The easiest way to solve this would be to use:
onChange={(e) => getInputToState(e, "username")}
onChange={(e) => getInputToState(e, "email")}
onChange={(e) => getInputToState(e, "password")}
The switch statement will not default to null and give the desired results.
Also see this stackoverflow question.

handling updating state when value comes in undefined

I am having trouble handling cases where the users phone number comes in undefined. I attempted to make the state conditional which I believe is bad practice so now I am using the useEffect hook to update the state on page load but now my onChange function in the field is not working for updating the state. Here's my code:
const EditableSection = ({
profile,
patientSex,
editingProfile,
setEditingProfile,
userID,
setProfile,
}) => {
const [PCPAreaCode, setPCPAreaCode] = useState();
const [PCPThreeDigit, setPCPThreeDigit] = useState();
const [PCPFourDigit, setPCPFourDigit] = useState();
useEffect(()=> {
if (!profile.medicalProfile.primaryCareProvider.fax){
setPCPAreaCode("")
setPCPThreeDigit("")
setPCPFourDigit("")
}else{
setPCPAreaCode(profile.medicalProfile.primaryCareProvider.fax.split(" ")[0]);
setPCPThreeDigit(profile.medicalProfile.primaryCareProvider.fax.split(" ")[1].split("-")[0]);
setPCPFourDigit(profile.medicalProfile.primaryCareProvider.fax.split("-")[1]);
}
});
const submitData = async () => {
if (!validProps()) {
return;
}
let res = await api.UserRecords.update(userID, {
PCPhysician: {
fax: `${PCPAreaCode} ${PCPThreeDigit}-${PCPFourDigit}`,
name: PCPName
}
});
if (editingProfile) {
return (
<FormGroup>
<div className={styles.profileBlock}>
<div className="d-flex">
<Input
type="text"
maxLength="3"
defaultValue={PCPAreaCode.replace(/\(|\)/g, "")}
onChange={(e) => setPCPAreaCode(e.target.value)}
className={PCPFaxError ? styles.inputError : styles.inputField}
style={{ width: "4rem" }}
/>
<Input
type="text"
maxLength="3"
defaultValue={PCPThreeDigit}
onChange={(e) => setPCPThreeDigit(e.target.value)}
className={PCPFaxError ? styles.inputError : styles.inputField}
style={{ width: "4rem" }}
/>
<Input
type="text"
maxLength="4"
defaultValue={PCPFourDigit}
onChange={(e) => setPCPFourDigit(e.target.value)}
className={PCPFaxError ? styles.inputError : styles.inputField}
style={{ width: "4rem" }}
/>
</div>
</div>
</FormGroup>
)
}
return (
<>
<div className={styles.profileBlock}>
<h2>Primary Care Provider</h2>
<p>
{PCPName || "Not provided"}, Fax: {`${PCPAreaCode} ${PCPThreeDigit}-${PCPFourDigit}` || "Not provided"}
</p>
</div>
</>
So right now when I add a value in these input fields It doesnt update and im wondering if theres something im obviously doing wrong here?

How to implement a check all button for radio buttons, using React Hooks?

Don't get this confused with checking each radio button I have on the page. I want to implement a check all button that sets the value of a nested object state equal to a certain value. I am storing each question in a nested state. Ex.
formQuestions({
kitchen: [question,question2,question3],
living: [question,question2,question3]
})
Four radio buttons are being made for each question. Now one radio button can only be selected at once. Each radio button has its' own value. Ex. `"Good", "Fair", "Poor", "N/A".
When a radio button is selected a state is generated dynamically for that section and question. Ex.
formAnswers({
kitchen: {
question: "Good"
question2: "Poor"
}
})
The goal here is the button that I want to create that checks only one value for each question Ex. clicks button question: "Good", question2: "Good" etc..
For me to set the state of a dynamic value I would need the "Section name" lets call it Name and the "Question" we'll call it question. That would give me access to the value like so formAnswers[Name][question]: value
I am trying to set that state from a component called SectionHeader. These contain the buttons.
SectionHeader.js
import { FormAnswersContext, FormQuestionsContext } from "../../Store";
function SectionHeader({ title, name }) {
const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
return (
<div>
<h1 className={styles["Header"]}>{title}</h1>
<div className={styles["MarkAllWrapper"]}>
<button className={styles["MarkAll"]}>
Mark all items as "Good" in this section
</button>
<br />
<button className={styles["MarkAll"]}>
Mark all items as "N/A" in this section
</button>
</div>
</div>
);
}
The parent of Section Header and the rest of the form code excluding the child radio buttons which I have explained, are in another component LivingRoom.js
LivingRoom.js
import { FormQuestionsContext, FormAnswersContext } from "../../Store";
function LivingRoomForm({ Name }) {
const [expanded, setExpanded] = useState(false);
const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
const array = formQuestions.living;
const onChange = (e, name) => {
const { value } = e.target;
setFormAnswers((state) => ({
...state,
[Name]: { ...state[Name], [name]: value },
}));
};
const handleOpen = () => {
setExpanded(!expanded);
};
return (
<div>
<Button
className={styles["CollapseBtn"]}
onClick={handleOpen}
style={{ marginBottom: "1rem", width: "100%" }}
>
<p>LIVING ROOM INSPECTION</p>
<FontAwesome
className="super-crazy-colors"
name="angle-up"
rotate={expanded ? null : 180}
size="lg"
style={{
marginTop: "5px",
textShadow: "0 1px 0 rgba(0, 0, 0, 0.1)",
}}
/>
</Button>
<Collapse className={styles["Collapse"]} isOpen={expanded}>
<Card>
<CardBody>
{array ? (
<div>
<SectionHeader title="Living Room Inspection" name={Name} />
<div
className={styles["LivingRoomFormWrapper"]}
id="living-room-form"
>
{array.map((question, index) => {
const selected =
formAnswers[Name] && formAnswers[Name][question]
? formAnswers[Name][question]
: "";
return (
<div className={styles["CheckboxWrapper"]} key={index}>
<h5>{question}</h5>
<Ratings
section={Name}
question={question}
onChange={onChange}
selected={selected}
/>
</div>
);
})}
</div>
<br />
<ImageUploader name="living" title={"Living Room"} />
</div>
) : (
<div></div>
)}
</CardBody>
</Card>
</Collapse>
</div>
);
}
If there is anything I am missing please let me know, I would be happy to share it. Cheers
Edit: for anyone that needs the radio buttons component.
Ratings.js
import React from "react";
import { FormGroup, CustomInput } from "reactstrap";
function Ratings({ selected, section, question, onChange }) {
return (
<div>
<FormGroup>
<div>
<CustomInput
checked={selected === "Good"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Good`}
value="Good"
label="Good"
/>
<CustomInput
checked={selected === "Fair"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Fair`}
value="Fair"
label="Fair"
/>
<CustomInput
checked={selected === "Poor"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Poor`}
value="Poor"
label="Poor"
/>
<CustomInput
checked={selected === "N/A"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_NA`}
value="N/A"
label="N/A"
/>
</div>
</FormGroup>
</div>
);
}
I do not completely understand your question, I am sorry but I think this will help you.
Here is an implementation of radio buttons using react -
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
handleChange = e => {
const { name, value } = e.target;
this.setState({
[name]: value
});
};
render() {
return (
<div className="radio-buttons">
Windows
<input
id="windows"
value="windows"
name="platform"
type="radio"
onChange={this.handleChange}
/>
Mac
<input
id="mac"
value="mac"
name="platform"
type="radio"
onChange={this.handleChange}
/>
Linux
<input
id="linux"
value="linux"
name="platform"
type="radio"
onChange={this.handleChange}
/>
</div>
);
}
}
After a few attempts, I was able to figure out the solution to this issue.
The key here was to figure out a way to get gather each question so that it may be used as a key when setting the state. As my questions were stored in a ContextAPI, I was able to pull them out like so...
this may not be the best solution however it worked for me.
const setStateGood = () => {
formQuestions[name].map((question) => {
setFormAnswers((state) => ({
...state,
[name]: { ...state[name], [question]: "Good" },
}));
});
};
const setStateNA = () => {
formQuestions[name].map((question) => {
setFormAnswers((state) => ({
...state,
[name]: { ...state[name], [question]: "N/A" },
}));
});
};
I was able to map through each question since the name is being passed through props is a key inside the actual object, formQuestions[name]. Because i'm mapping through each one I can set that question as a key and return the new state for each question to whatever I would like.
However, if I was to create an onClick={setState('Good')}, React didn't like that and it created an infinite loop. I will look for more solutions and update this post if I find one.

Retrieving value of checkbox in React.js

I want to retrieve the value of my checkbox when it is checked.
I am using this "http://react-component.github.io/checkbox/".
My code looks like this.
<div className="user_box">
{ check.map((values , i)=> {
return <Checkbox
name = "checkbox"
onChange={this.checkvalue.bind(this)}
value={values.username}
/>
})}
</div>
My function:
checkvalue(e){
// var all_users = [];
// var value = this.checkbox.value;
// all_users.push(value);
// console.log(all_users);
console.log('checkbox checked:', (e.target.checked));
}
I'm not understanding how to retrieve the value of the checkbox.
you need to pass the "e, Synthetic event parameter to your handler" :
handleChange(e) {
let isChecked = e.target.checked;
// do whatever you want with isChecked value
}
render() {
// ... your code here
return (
{/* your other jsx here */}
<Checkbox otherProps onChange={e => this.handleChange(e)} />
{/* your other jsx here */}
);
}
Use the Synthetic event parameter, here is an example:
const element1 = "boy";
const element2 = "girl";
<input
type="checkbox"
name={element1}
value={element1}
onChange={this.handleChange}
/>
<label for="element" style={{ fontSize: 35 }}>
{element2}
</label>
<input
type="checkbox"
name={element2}
value={element2}
onChange={this.handleChange}
/>
<label for="element" style={{ fontSize: 35 }}>
{element2}
</label>
handleChange = (e) => {
// to find out if it's checked or not; returns true or false
const checked = e.target.checked;
// to get the checked value
const checkedValue = e.target.value;
// to get the checked name
const checkedName = e.target.name;
//then you can do with the value all you want to do with it.
};
Try this :
getChckeboxValue(event) {
const value = event.target.value;
}
In render:
<input onClick={this.getChckeboxValue.bind(this)} type="checkbox" value="Text" />
We can get check box value by declaring onChange={this.likeClicked} defaultChecked={false} on input element properties
constructor(props){
super(props)
this.likeClicked = this.likeClicked.bind(this)
}
likeClicked(){
console.log(event.target.checked, event.target.id);
}
render(){
return (
<div className='px-3'>
<div className='item-header item-wrapper cirle'>
<input
type="checkbox"
onChange={this.likeClicked}
defaultChecked={false}
className="checkbox"
id={`checkbox_${this.props.product.sku}`}
/>
<label htmlFor={`checkbox_${this.props.product.sku}`}>
<HeartIcon className="heart-svg"></HeartIcon>
</label>
</div>
</div>
);
}
One liner:
onChange={e => doSomethingWithValue( e.currentTarget.checked )}

Categories

Resources