I'm working on making multiple choice component that has props such as number of options, number of Answers and callback fn in order to get data of selected options given by users. And when a button is clicked, a checkmark is shown on the button.
This component is supposed to work like this.
If the number of answers is 1, as soon as user clicks one button, all of other buttons should be disabled. But once the button that user clicked at first is clicked again, then the other buttons should not be disabled anymore.
if the number of answers is more than 1(meaning multiple), as soon as user clicks buttons as same number of the times as answers, it should work like the first case above, but the difference is when any button out of clicked ones is clicked again, the rest of buttons should not be disabled.
// Parent Component, where the multipleChoice component is called
import MultipleChoice from 'components/MultipleChoice';
const ParentComponent = () => {
const [curSelectedOptions, setCurSelectedOptions] = useState<number[]>([]);
<MultipleChoice
numOfOptions={5}
numOfAnswers={1}
onClick={(selectedOption) => {
setCurSelectedOptions((prev) =>
prev.includes(selectedOption)
? prev.filter((option) => option !== selectedOption)
: [...prev, selectedOption]
);
}}
/>
// MultipleChoice Component
import { useState } from 'react';
import styles from './MultipleChoice.module.scss';
import _ from 'lodash';
import { CheckOutlined } from '@ant-design/icons';
interface IMultipleChoice {
numOfOptions: number;
numOfAnswers: number;
onClick: (selectedOption: number) => void;
}
const MultipleChoice: React.FC<IMultipleChoice> = ({
numOfOptions,
numOfAnswers,
onClick,
}) => {
const [checkedOption, setCheckedOption] = useState<any>({});
const onHandleClick = (index: any) => {
setCheckedOption((prev: any) => ({ ...prev, [index]: !prev[index] }));
}
return (
<div className={styles.container}>
{numOfOptions && _.range(1, numOfOptions + 1).map((option, index) => {
return (
<button
key={option}
value={option}
onClick={(e) => {
onHandleClick(e, index);
onClick(e.currentTarget.value);
}}
// disabled={}
className={`${styles.choiceButton} ${styles.center}`}
>
<div
className={
`${styles.circleOfNumber} ${styles.center}`
}
>
<span className={styles.numberText}>{option}</span>
{checkedOption[index] ? ( // this condition determines whether checkmark is displayed
<div className={styles.checkMarkWrapper}>
<CheckOutlined
style={{
fontSize: 68,
color: 'red',
}}
/>
</div>
) : null}
</div>
</button>
);
})}
</div>
)
'checkedOption' state goes like this. if user clicks 1,2 buttons out of 5, then it will be {0: true, 1: true}. and if user clicks same buttons again, then it turns into {0: false, 1: false}, NOT like this -> {}. And checkMark is shown when index key of checkedOption state has 'true' value.
It's tricky to put disabling certain buttons conditionally with the way of check mark working with code 'checkedOption[index] ? ...' and 'onHandleClick' function together.
How can I make those two described above working?
Any help would be appreciated.
We do it by enforcing the condition:
true
values in checkedOption
is the same as the number of answers allowed (for "defensive coding" sake, we also check if its more than the answers allowed) <button
key={option}
value={option}
onClick={(e) => {
onHandleClick(e, index);
onClick(e.currentTarget.value);
}}
disabled={!checkedOption[index] && Object.values(checkedOption).filter(selected => selected === true).length >= numOfAnswers}
className={`${styles.choiceButton} ${styles.center}`}
>