Reputation: 604
Having issues with a uni assignment. In this assignment, we have some data as answers for a problem. I need to build up a form to allow an answer to be selected. In this assignment, there will only be one answer. So I thought could just use a radio button, styled to look like a button, to avoid having to code in logic for checking how many answers we should have and set that.
To do this, I created a new AnswerGroup component and pass in an array of answers.
This is the array (taken using a console.log to show the structure):
Array(5) [ {…}, {…}, {…}, {…}, {…} ]
0: Object { chosen: 0, text: "10 \\mbox{ kg.}", correct: false }
1: Object { text: "62 \\frac{2}{9} \\mbox{ kg.}", chosen: 0, correct: true }
2: Object { text: "None of the above", chosen: 0, correct: false }
3: Object { text: "1\\frac{17}{28} \\mbox{ kg.}", chosen: 0, correct: false }
4: Object { chosen: 0, correct: false, text: "1260 \\mbox{ kg.}" }
length: 5
To clarify the data structure in this object: Chosen is meant to be used at a later stage, where the number of times a user has picked this answer is recorded (it is held in cloudstore, so ultimately that info feeds back) text the text which will appear on the button (it is mathjax format, so looks strange) correct a boolean representing if this is the correct answer or not.
And my AnswerComponent looks like this:
import React, {useState} from 'react';
import { MathComponent } from 'mathjax-react'
import '../styles/radioStyles.css'
function AnswerComponent(props) {
let answers = props.answersarray;
const [value, setValue] = useState(false)
function handleChange() {
setValue(value);
// alert(value)
}
return (
<div className="col-12">
<h3 className="text-center">Answer</h3>
<div className="p-3 mb-2 bg-light">
<div className="row">
<div className="answerGroup">
{
answers.map((answer, id) => {
let formulaButton;
let label = answer.text;
label.includes('kg') ? formulaButton = true : formulaButton= false;
return (
<>
<input type='radio'
// className={isActive ? 'radBtn' : 'selectedAnswer'}
className={'radBtn'}
// checked={value}
name='answer'
id={id}
onChange={handleChange}
value={answer.correct}
/>
<label for={id}>{formulaButton === true ? <MathComponent tex={answer.text} /> :answer.text}</label>
</>
)
})
}
</div>
</div>
<div className="col-sm text-center">
<button className='btn-primary mb-2 p-4'>CHECK MY ANSWER</button>
</div>
</div>
</div>
)
}
export default AnswerComponent;
I have styled with the following:
/* .answerGroup input[type="radio"] {
opacity: 0;
} */
.answerGroup label {
background-color: #95a5a6;
border: none;
padding: 15px 32px;
border-radius: 8px;
text-align: center;
color: white;
box-shadow: 0 0.2rem #798d8f;
text-shadow: 0 0.075rem #617374;
}
.answerGroup label:hover {
background-color: #a3b1b2;
box-shadow: 0 0.2rem #87999a;
}
.selectedAnswer {
background-color: #FF0000;
border: none;
padding: 15px 32px;
border-radius: 8px;
text-align: center;
color: white;
box-shadow: 0 0.2rem #798d8f;
text-shadow: 0 0.075rem #617374;
}```
Updated question:
When I click on an individual radio button, I would like the background colour to change (I had created the selectedAnser class in the CSS - and I know that it duplicates the answergroup label class except the background colour)
What I want is that when the buttons are created, if I click on a check answer button, that if the radio with "correct=true" is selected, then the user gets a "well done" (now at this point, that button is somewhere else, but I am refactoring this on the fly - so that button **Could** end up in the react with the answer group - in fact, it is probably a good place for it.
Upvotes: 0
Views: 3245
Reputation: 468
As @a-haworth correctly pointed out the culprit is this block of code.
.answerGroup input[type="radio"] {
display: none;
}
I believe you added this to get the mathjax render/styled correctly but it straight up hides the radio buttons. So you can comment this block in your css file.
I wasn't able to render the equations so I changed <label>
to <button>
(changed the css accordingly). This renders the equations inside of the button.
Note: You still have to click on the radio button instead of the grey button with equation; to select.
You are right to think about using this line.
className={isActive ? 'radBtn' : 'selectedAnswer'}
But it should really be used as a prop for <label>
instead of <input>
since those radio buttons are just small blue circles whose color can't be changed. The bg-color you can change is the <label>
. It would have been simple if label had some css selector like checked
and would act like a radio button but I couldn't find any. So we are stuck with using react for changing the color (IMO this is the better way!)
There is still a remaining problem though. You can't get away with one value = true/false
you need an array of boolean
(or a number for the id of the option) to know which option is being selected. Then conditionally setting the class for <label>
would get our job done.
function AnswerGroup(props) {
const answers = props.answersarray;
// console.log('> ', answers);
const [values, setValues] = useState(() =>
answers.map((a) => false)
);
// console.log(values);
const handleChange = (event) => {
const option_id = Number(event.target.value);
setValues(
values.map((a, idx) => (option_id === idx ? true : false))
);
};
return (
<div className='col-12'>
<h3 className='text-center'>Answer</h3>
<div className='p-3 mb-2 bg-light'>
<div className='row'>
<div className='answerGroup'>
{answers.map((answer, id) => {
let formulaButton;
let label = answer.text;
label.includes('kg')
? (formulaButton = true)
: (formulaButton = false);
return (
<React.Fragment key={id}>
<input
type='radio'
className={'radBtn'}
name='answer'
onChange={handleChange}
value={id}
/>
<label
className={
values[id] ? 'selected' : 'notSelected'
}
forhtml={id}
>
{formulaButton === true ? (
<MathComponent tex={answer.text} />
) : (
answer.text
)}
</label>
</React.Fragment>
);
})}
</div>
</div>
<div className='col-sm text-center'>
<button className='btn-primary mb-2 p-4'>
CHECK MY ANSWER
</button>
</div>
</div>
</div>
);
}
/* .answerGroup input[type="radio"] {
opacity: 0;
} */
.notSelected {
background-color: #95a5a6;
border: none;
padding: 15px 32px;
border-radius: 8px;
text-align: center;
color: white;
box-shadow: 0 0.2rem #798d8f;
text-shadow: 0 0.075rem #617374;
}
.answerGroup label:hover {
background-color: #a3b1b2;
box-shadow: 0 0.2rem #87999a;
}
.selected {
background-color: #00ccff;
border: none;
padding: 15px 32px;
border-radius: 8px;
text-align: center;
color: white;
box-shadow: 0 0.2rem #798d8f;
text-shadow: 0 0.075rem #617374;
}
Upvotes: 1