简体   繁体   中英

Disable clicked buttons when those are same number of answers in multiple choice using react with typescript

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.

  1. 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.

  2. 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:

  • Checking the current option is not one that's already selected. And...
  • The total number of 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}`}
            >
            

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM