Work out whether custom radio component is checked or not - javascript

I have a custom radio component in React, when I check and uncheck the values it adds items to an object and should have true or false based on whether they are checked.
At the moment it adds the true value correctly with the name of the radio but I can't seem to find out how to work to make the option false if another option is chosen.
I am currently using
constructor() {
super();
this.state = {
time_frame: {},
}
this.handleRadioChange = this.handleRadioChange.bind(this);
}
handleRadioChange(event) {
let name = event.target.name
let timeFrameCopy = this.state.time_frame;
console.log(event.target)
timeFrameCopy[event.target.value] = true
this.setState({[name]: timeFrameCopy,}, this.checkState)
return
}
}
checkState(event) {
console.log(this.state)
}
My radio component is
const Radio = (props) => {
return (
<Col>
<div>
<input id={props.value} type="radio" name={props.name} value={props.value} className="visually-hidden" onChange={props.handleChange}/>
<label htmlFor={props.value} className="switch-label checkbox-label text-center">{props.label}</label>
</div>
</Col>
)
}
export default Radio
If I check one radio button and then the other my state still has the data:
time_frame: {single: true, recurring: true}
Even though I would expect one of them to be false

If I understand correctly, you're trying to store in the state an object called time_frame, which is going to contain one pair of property-value per radio input, where the name of each of them would be the property name and the checked status the value. If that's the case, I see a logic problem. since you're hard-coding true (for what I understand from your code) always instead of looking for the value stored and toggling/flipping it.
handleRadioChange() function should be something like:
handleRadioChange(event) {
let name = event.target.name;
this.setState((currentState)=>{
let timeFrameCopy = currentState.time_frame;
timeFrameCopy[name] = event.target.checked;
return { "time_frame": timeFrameCopy };
});
}

Related

Get a checkbox value on change of other checkbox in react

I have 2 checkboxes A and B. I want to check whether checkbox B is checked or not on change of checkbox A and vice versa. Also I want to change checkbox B on change of checkbox A. How can we achieve that in react.js.
You can create a state for both of them and change it accordingly.
This way you'll have access to it whenever needed.
Also, to avoid handling changes separately for every input, you can give each of them a name and then have a single dedicated function that changes the value of the checkbox based on it's name.
Example:
function App() {
const [state, setState] = useState({
firstCheckbox: false,
secondCheckbox: false,
})
const handleChange = (e) => {
setState(prev => ({
...prev,
[e.currentTarget.name]: e.currentTarget.checked,
}));
};
return (
<>
<input
name='firstCheckbox'
type='checkbox'
checked={state.firstCheckbox}
onChange={handleChange}
/>
<input
name='secondCheckbox'
type='checkbox'
checked={state.secondCheckbox}
onChange={handleChange}
/>
</>
)
}
Currently in this example, each checkbox relates to it's own state.
However, you can easily adjust the handleChange function based on your needs.

handling a select all in react and materialUI

I have several sets of checkboxes that should work independently and a toggle that toggles them all (within their groups only). I have two states (one for the toggle and one for the checkboxes). I can identify the checkbox I'm clicking with the event.target.value, that way I can manipulate it individually. But I'm having trouble controlling them all at once with the toggle as well as making the toggle come active when someone independently checks them all true.
In summary
1- when the toggle is on, all checkboxes within its group come on, same for off
2- When I turn on each checkbox individually until they are all on, the toggle turns on and when I uncheck one of them, the toggle turns off
I've made a sandbox for you to play on. Thanks in advance
const [active, setActive] = useState(false)
const [singleactive, setSingleActive] = useState([])
const handleSwitch = (e) => {
if(e.target.value === "Select All") {
setActive(e.target.checked)
setSingleActive([...singleactive])
} else {
setSingleActive([])
}
}
const handleSingleSwitch = (e) => {
const index = singleactive.indexOf(e.target.value)
if(index === -1) {
setSingleActive([...singleactive, e.target.value])
} else {
setSingleActive(singleactive.filter((singleactive) => singleactive !== e.target.value))
}
}
Well, I figure it out. Though I find answering your own question a bit pretentious lol, here it is in case it helps
Updated states and functions
const [active, setActive] = useState(false)
/// fill a new array with false values for the length of the data to load them all unchecked
const [checkedState, setCheckedState] = useState(new Array(data.length).fill(false));
const handleSwitch = (e) => {
if(e.target.checked) {
/// if the toggle event comes back checked, set the active state to true and re-fill the array with all true values which is what Select All does
setActive(true)
setCheckedState(new Array(data.length).fill(true));
} else {
/// if the toggle event comes back unchecked, set the active state to false and re-fill the array with all false values which is what Deselect All does
setActive(false)
setCheckedState(new Array(data.length).fill(false));
}
}
const handleOnChange = (position) => {
// every time you click an infividual checkbox, map through the state and compare its index with the position in the array. If it's true, make it true otherwise false; then set the state with this value
const updatedCheckedState = checkedState.map((item, index) => {
return (
index === position ? !item : item
)}
);
setCheckedState(updatedCheckedState);
/// if the new generated array of values contains at least one false in it, set the active class on the toggle to false, but if there isn't at least one false, then all are true, so set the active class to true on the toggle
if(updatedCheckedState.includes(false)) {
setActive(false)
} else {
setActive(true)
}
};
I also removed the value on the toggleAll checkbox that I inadvertently set statically to Select All. This way I can control it via state
<Stack direction="row" spacing={1} alignItems="center">
<Typography>Deselect All</Typography>
<Switch
size="small"
checked={active}
onChange={handleSwitch} />
<Typography>Select All</Typography>
</Stack>
And lastly the checkboxes
<FormControlLabel
control={
<Checkbox
size="small"
name={item.toLowerCase()}
value={item.toLowerCase()}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
}
label= {item.replaceAll('_', ' ')} />
Check the sandbox for the updated code.

How to get custom number buttons to show on correct input field react.js

Having a hard time seeing how I could accomplish this. I created some custom number buttons from 0-9 that users can click on instead of using the keyboard. The problem I'm having is I have multiple dynamically created input fields depending on JSON Data so let's say there are 10 dynamically created input fields and a user starts with question one and the user then uses the custom number buttons I created and clicks numbers "145" to answer question one, but what happens is then all 10 inputs have the same number "145" not the problem the user was trying to solve. I'm using the context API to then save the values typed in on a function called getButtonValue that I then call to the parent component and save the values in a state array, so I know that my problem is that all the inputs share the same state array but how could I make sure the correct input the user clicks on is only receiving those values.
Thanks in advance.
My Custom Number Button Component:
import { FormContext } from "../../lib/FormContext";
function ActivityBar() {
const { getButtonValue } = useContext(FormContext);
return (
<div className={`${activity.activity__workSheet__numberButton}`}>
<button value={0} onFocus={(e) => getButtonValue(e)}>
<img
className={`${activity.activity__workSheet__img0}`}
src={"/assets/activityNumber-btn.png"}
alt="activity number button"
/>
.... more code
Parent Component:
const [numberButtonClicked, setNumberButtonClicked] = useState([]);
const getButtonValue = (e) => {
setNumberButtonClicked((prevButtonClicked) => [
...prevButtonClicked,
e?.target?.attributes[0].value
]);
};
return (
<Carousel>
<div ref={imageRef} style={{ height: "100%" }}>
{Object.entries(elements).map((element, i) => {
const { fields } = element[1];
if (fields) {
return (
<Element
key={i}
field={fields[0]}
id={i}
useReff={`answer${i}`}
currentValue={
numberButtonClicked === "" ? null : numberButtonClicked.join("")
}
/>
);
} else {
return;
}
})}
</div>
</Carousel>
Got a good working version figured out for this scenario, what I did was.
I have a onFocus method on my input tags that then takes in the event and calls a handleChange(e) function. Within that function I then save the currentInputId in a variable by using e?.target?.attributes[0]?.value and the previous InputId in a state variable and just check if the previous InputId is equal to the currentId user just focused on. If so then we'll add the next number user clicks into the same field, else if previousInputId !== currentInputId then make my user value state array empty, setNumberButtonClicked([]).

Can't Reset a Simple Radio Button - React JS

I am writing a trivia app. When I select an answer, I check if it is the right one and get a new question right after. The problem is that I can't get the React to render the selected radio button when it is the wrong answer.
Screenshot of what it looks like
I am generating the Trivia questions from a JSON file. I have to make a input and a label tag dynamically. This is what I have so far:
I can get my next question when the selected one is right, but it doesn't show any radio selected. My isRadioChecked starts with false. I also tried checked={this.state.isRadioChecked == object}.
Below, I check if the clicked radio was the right answer and my render method
checkResult = event => {
this.setState(
{
selectedAnswer: event.target.value
},
() => {
if (this.state.selectedAnswer === this.state.correctAnswer) {
this.setState(
{
isRadioChecked: false,
currentQuestionNumber: this.state.currentQuestionNumber + 1
},
() => {
this.getNewQuestion();
}
);
render() {
return (
<div onChange={this.checkResult}>
<h2>Question Component</h2>
<h3>{this.displayQuestion()}</h3>
<div>{this.displayAlternatives()}</div>
</div>
);
}
}
I really appreciate your help. Thank You!!
[EDIT]
Thank You, Arpitha that was the first thing I tried and actually my last attempts came straight from http://react.tips/radio-buttons-in-reactjs/ . I think the issue is that I am creating the radios using dynamic data.
Anyways, I did change it to like it was before and still, I get no visible selected radio, even though the log shows the selected answer.
setUpAnswers() {
let tempAnswerArray = this.mergeAnswers(this.state.currentQuestionNumber);
tempAnswerArray = tempAnswerArray.map((object, i) => renderHTML(object));
console.log(tempAnswerArray[0]);
tempAnswerArray = tempAnswerArray.map((object, i) => (
<div key={i}>
<input
type="radio"
name="answers"
checked={this.state.selectedAnswer === object}
onChange={this.handleOptionChange}
id={object}
value={object}
/>
<label htmlFor={object}>{object}</label>
</div>
));
this.setState({
answerArray: tempAnswerArray
});
}
//*************************************************** */
handleOptionChange = changeEvent => {
this.setState(
{
selectedAnswer: changeEvent.target.value
},
() => {
console.log(this.state.selectedAnswer);
}
);
};
You are assigning this.state.isRadioChecked status to all the radio buttons like this checked={this.state.isRadioChecked} . So all the radio buttons will be checked or unchecked at the same time.
Instead you can use state.selectedAnswer to update checked attribute of radio button. Something like this -
checked={this.state.selectedAnswer === object}
A nice article on how to create radio groups is explained here - http://react.tips/radio-buttons-in-reactjs/

React Select mapping issue

I'm using react-select in my project and I'm using it within a map like that:
renderItems() {
this.props.items.map(item => (
<Select
id="options"
value={this.state.optionSelected}
onChange={this.onChangeOption}
options={this.showOptions()}
/>
);
}
It show correctly all my options for all my items but now I can not get rid about the select...
Basically when I select an option on a single item, that option is changing for all items...
This is what i did so far:
onChangeOption(e) {
this.setState({ optionSelected: e.value });
}
How can I adjust it to change the option only on the one I wish to change it?
Thanks
You are using the same change handler for all of your select components and then set the same state value for all your select components. To deal with this either you need to separate your select components with a container component that handles their own state and change event or you need to give each select component a unique state value.
Example
renderItems() {
this.props.items.map(item => (
<Select
id="options"
value={this.state.optionSelected[item.id]}
onChange={(event) => this.onChangeOption(event, item.id)}
options={this.showOptions()}
/>
);
}
onChangeOption(event, itemId) {
this.setState((prevState) => {
const prevStateClone = Object.assign({}, prevState);
prevStateClone.optionSelected[itemId] = event.target.value;
return prevStateClone;
});
}
Instead of making optionSelected string variable, make it as array in state.
Now do the following.
renderItems() {
this.props.items.map(item, index => (
<Select
id="options"
value={this.state.optionSelected[index]}
onChange={(selectedValue) => this.onChangeOption(selectedValue, index)}
options={this.showOptions()}
/>
);
}
onChangeOption(selectedValue, index) {
const optionSelected = this.state.optionSelected.slice() // slicing to get new copy of optionSelected instead of referencing to old one which causes mutation
optionSelected[index] = selectedValue
this.setState({optionSelected: optionSelected})
}
What you were doing is using a single variable to hold values of the select box. So if anyone changes, it will reflect all select box
Try cloning the object to a new object or if this optionSelected is a class, you can implement a constructor that clones it for your like:
export class optionSelectedClass {
myfield = '';
constructor(fields){
this.myField = fields.myField;
}
}
or even
export class optionSelectedClass {
myfield = '';
constructor(fields){
for (let f in fields) {
if (!this[f]) {
this[f] = fields[f];
}
}
}
}

Categories