Can't Reset a Simple Radio Button - React JS - javascript

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/

Related

I want to disable the options for each question saperately after clicking the option for that question

setIsStarted(true)
setCurrentScore(0)
setResultCard(false)
setCurrentQuestion(0)
}
const checkOption = (isCorrect) =>{
setDisability(true)
if(isCorrect){
setCurrentScore(currentScore+1);
}
setCurrentQuestion(currentQuestion+1);
if(currentQuestion==questions.length-1){
setShowResult(true);
}
}
function showResultButton(showResult){
if (showResult) {
return <button className='show-result' onClick={showResultCard}>Show results</button>
}
}
const showResultCard = () =>{
setShowResult(false)
setResultCard(true);
setIsStarted(false)
}
function displayResultCard(resultCard){
if(resultCard){
return <div className='score-card'>You have answerd {currentScore}/5 correctly</div>
}
}
const updateDisability = () =>{
setDisability(false)
}
function DisplayQuesion(){
const quesList = questions.map((element) => {
return(
<div className='question-card'>
<h2>{element.text}</h2>
<ul>
{element.options.map((option) => {
return <button key={option.id} onClick={() => checkOption(option.isCorrect)} disabled={updateDisability}>{option.text}</button>
})}
</ul>
</div>
)
})
return (<div>{quesList}</div>)
}
In this code my all options are getting disabled even after clicking one option.When an option for a question is clicked, all other buttons for the question are disabled. when all questions are answered, the show results button gets shown.
This happens because you're not splitting down the list of questions in child components and so on.
You need to create three components to achieve this:
Questionary
Question
Answer
By doing so, you'll be able to define a separate state for each question/answer so they don't get mixed up.
Within your code, notice that if you click on an item it will update the state of the entire component which consequentially will update also all the other answers because they shared the same state.
You can check this link to have a better understanding:
https://www.pluralsight.com/guides/passing-state-of-parent-to-child-component-as-props

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([]).

Input radio button's defaultChecked attribute prevents onClick function from being triggered

<section key={i}>
<input
type='radio'
key={attribute.name + item.id}
id={attribute.name + item.id}
name={attribute.name}
value={item.value}
defaultChecked={i === 0}
onClick={(event) => inputClick(attribute, event)}
/>
<label
htmlFor={attribute.name + item.id}
>
{
item.value
}
</label>
</section>
The code above is more or less what a .map() function is supposed to return in my React.js APP, creating input radio buttons for customizing a product before adding it to the cart state. All I did was remove some classes, etc. that were there for CSS purposes, etc.
Ideally, what is supposed to happen here is that...
When rendering the product page for the first time, the very first input radio button that is returned by .map() should be checked by default. This works thanks to the "defaultChecked" attribute. No problems here.
After I click a different input radio button (not the "defaultChecked" one), the checked input should change and all the other inputs should be left unchecked. As I understand it, input radio buttons with the same 'name' attribute do this automatically.
When clicking the input radio button, the "onClick" function should trigger. This is where the code is not functioning as I wish it would.
The issue is that when my page renders for the first time and I click on an input radio button (other than the "defaultChecked") the "onClick" function does not trigger. It only triggers when I have clicked on a different input once and then on another.
A.k.a. it triggers on the second click. After that second click, it works as intended - every time a different input radio button is selected/clicked on - the function triggers, but not for the very first time.
I tested this with console.log("I am triggered") at the end of the "onClick" "inputClick(attribute, event)" function, and only on the second click would the console log "I am triggered".
I was able to fix the issue by removing the "defaultChecked" attribute. I think the issue might be tied to the fact that the "onClick" function is only able to be triggered when one input gains the "checked" attribute and another loses it, but the "defaultChecked" attribute does not count as an input being "fully checked" or something like that.
I could leave it at that, but the project that I am working on required me to have a default checked input radio button on the first-page render. So, I can't just delete the "defaultChecked" attribute and call it a day.
Any ideas on what could be causing this behavior?
UPDATE1
The following is the body of the inputclick() function:
//* Handle input selection
const inputClick = (attribute, event) => {
//* Parse state
let state = JSON.parse(JSON.stringify(itemState));
//* Get all the required values from the clicked input
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Check if the attribute is in state
const attributeIs = state.some(item => item.id === attributeId);
//* If the attribute does not exsist - add the attribute to state
if(attributeIs === false) {
const obj = {
id: attributeId,
selectedItem: itemTargetValue
};
state.push(obj);
return setitemState(state);
}
//* If the attribute id already exsists in state
if(attributeIs) {
//* Find the index of the attribute in question
const attributeIndex = state.map(object => object.id).indexOf(attributeId);
const attributeInQuestion = state[attributeIndex].selectedItem;
//* If the attribute's item's id is the same as the seelected input - do nothing
if(attributeInQuestion === itemTargetValue) {
return
}
//* If the attribute's item's id is not the same - change it to the new value
if(attributeInQuestion !== itemTargetValue) {
state[attributeIndex].selectedItem = itemTargetValue;
console.log(state);
return setitemState(state);
}
}
};
Here is the working code that fixes the issue.
Yes, there is some streamlining, for example, code shortening, etc. Yet, the difference that solves the issue is that...
The code that I had posted in the question originally was working. Meaning, that it was firing the inputClick() function and changing which input was selected, the problem was that...
...the defaultChecked logic in the was preventing the chosen input from being rendered as a selected input a.k.a. to change its CSS styling.
Bellow is the new onClick() function.
//* Handle input selection
const inputClick = (product, attribute, event) => {
let newCart = JSON.parse(JSON.stringify(cartState));
const productId = product.id;
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Find the product in cart state */
const productIndex = newCart.map((object) => object.id).indexOf(productId);
//* Find the attribute by id in question */
const attributeIndex = newCart[productIndex].selectedAttributes.map(object => object.id).indexOf(attributeId);
//* Change the products selected attribute item */
newCart[productIndex].selectedAttributes[attributeIndex].selectedItem = itemTargetValue;
setcartState(newCart);
};
Below is what the "inside" of the looks like now.
<input
type='radio'
key={product.id + attribute.name + item.id}
id={product.id + attribute.name + item.id}
name={product.id + attribute.name}
value={item.value}
defaultChecked={product.selectedAttributes[selectedId].selectedItem === item.value}
onChange={(event) => inputClick(product, attribute, event)}
>
</input>

Work out whether custom radio component is checked or not

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 };
});
}

Office UI Fabric Checkbox - How to Uncheck multiple check boxes at once through code

I render multiple checkboxes for a filter overlay. Now i want to clear all the checkboxes on a click of a button. How can i do this?
I render the checkboxes like this:
{
filter.Choices.map((choice: any) => (
<Checkbox
title = {filter.InternalName}
label = {choice}
onChange = {this._makeChangeHandler(choice, filter.InternalName, filter.Id)}
/>
))
}
Here is how i render my clear filter button:
<DefaultButton className={style.overlayClearButton} onClick={this._clearFilters}>Clear Filters</DefaultButton>
I want to uncheck all the checkboxes when i click the "Clear Filters" button.
you can use a controlled Checkbox for this. It´s basically the same, but you control the value of your checkbox on your own. Store this with your filter.Choices objects
filter.Choices.map((choice: any) => (
<Checkbox
title = {filter.InternalName}
label = {choice.label}
onChange = {this._makeChangeHandler(choice, filter.InternalName, filter.Id)}
checked={choice.isChecked}
/>
))
And on your button click you can now unset all checkboxes:
//Clear isChecked values of choices and set state for rerender
public _clearFilters() {
this.setState(state => ({...state, filter: state.filter.Choices.map(choice => {choice.isChecked = false; return choice;}))});
}
The solution depends on how you handle state in your application. But the best way is to control the checkbox state yourself.
I hope this helps,
greetings joe
for more sharepoint related help look at https://www.smarterbusiness.at/smarter-blog

Categories