2

I am fetching a list of questions from the Question.js file to Home.js

How can I change the answer border color when the user clicks on that. I want to make green if the user clicks on the right answer and red if the user clicks on the wrong answer.

If the user clicks on the wrong answer then it should show the right answer by making the background green and the rest all should become the red border.

See output: enter image description here

Home.js file:

import React from 'react'
import Questions from './Questions'

const Home = () => {
    function action(){

    }

    return (
        <>
        <div className="main">
            {
            Questions.map((item)=>(
                <div className="box">
                <div className="title">
                <h2 className="qno">{item.numb}</h2> 
                <h2> {item.question}</h2>
                </div>
                <div className="options">
                    <span onClick={()=>action()} >{item.options.q1}</span>
                    <span>{item.options.q2}</span>
                    <span>{item.options.q3}</span>
                    <span>{item.options.q4}</span>
                </div>
            </div>
            ))    
            }
        </div>
        </>
    )
}

export default Home;

Questions.js file:

let Questions = [
  {
    numb: 1,
    question: "What does HTML stand for?",
    answer: "Hyper Text Markup Language",
    options: {
      q1: "Hyper Text Preprocessor",
      q2: "Hyper Text Markup Language",
      q3: "Hyper Text Multiple Language",
      q4: "Hyper Tool Multi Language",
    },
  },
  {
    numb: 2,
    question: "Who is Ankit Yadav?",
    answer: "Engineer",
    options: {
      q1: "Engineer",
      q2: "Doctor",
      q3: "CEO",
      q4: "Scientist",
    },
  },
];

export default Questions;

style.css file:

/* styling */

.main{
    width: 70vw;
    height: 100%;
    box-shadow: 0 0 14px 0;
    margin: 30px auto;
    border-radius: 5px;
}

.box{
    padding: 10px;
    border-bottom: 2px solid #4c4c4c;
}
.title .qno{
    font-size: 1.7rem;
    font-weight: 800;
    font-family: 'Courier New', Courier, monospace;
    background-color: #4c4c4c;
    padding: 5px;
    border-radius: 70px;
    color: #fff;
}
.title h2{
    font-size: 1.7rem;
    font-weight: 500;
    margin-left: 10px;
}
.box .title{
    display: flex;
}

.options{
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    margin: 20px 25px;
}
1
  • Create a ref and with the ref el.style.border = "2px solid green"; or something like that. Commented Nov 28, 2021 at 5:20

2 Answers 2

1

You can achieve it using inline styles and a few util functions

const Home = () => {
  const [answerStatus, setAnswerStatus] = useState(() => {
    return Questions.map((item) => {
      return {
        numb: item.numb,
        answered: false,
        givenAnswer: ""
      };
    });
  });

  const action = (questionNumber, answer) => {
    setAnswerStatus((prevState) => {
      return prevState.map((item) =>
        item.numb === questionNumber
          ? { ...item, answered: true, givenAnswer: answer }
          : item
      );
    });
  };

  const isAnswerCorrect = (questionNumber) => {
    const status = answerStatus.find((item) => item.numb === questionNumber);
    const question = Questions.find((item) => item.numb === questionNumber);
    return status.answered && question.answer === status.givenAnswer;
  };

  const questionAnswered = (questionNumber) => {
    const status = answerStatus.find((item) => item.numb === questionNumber);
    return status.answered;
  };

  const getGivenAnswer = (questionNumber) => {
    return answerStatus.find((item) => item.numb === questionNumber)
      ?.givenAnswer;
  };

  return (
    <>
      <div className="main">
        {Questions.map((item) => (
          <div className="box">
            <div className="title">
              <h2 className="qno">{item.numb}</h2>
              <h2> {item.question}</h2>
            </div>
            <div className="options">
              {Object.entries(item.options).map(([optionId, optionDesc]) => {
                return (
                  <span
                    onClick={() => action(item.numb, optionDesc)}
                    style={{
                      backgroundColor: questionAnswered(item.numb)
                        ? isAnswerCorrect(item.numb) &&
                          getGivenAnswer(item.numb) === optionDesc
                          ? "lightgreen"
                          : isAnswerCorrect(item.numb)
                          ? "lightblue"
                          : item.answer !== optionDesc
                          ? "tomato"
                          : "lightgreen"
                        : "lightblue",
                      padding: "5px",
                      borderRadius: "3px",
                      margin: "3px",
                      cursor: "pointer"
                    }}
                  >
                    {optionDesc}
                    {questionAnswered(item.numb) &&
                      getGivenAnswer(item.numb) === optionDesc &&
                      " (given answer)"}
                  </span>
                );
              })}
            </div>
          </div>
        ))}
      </div>
    </>
  );
};

export default Home;

Code sandbox => https://codesandbox.io/s/quirky-hill-cwoc5?file=/src/App.js

Sign up to request clarification or add additional context in comments.

7 Comments

@Ankit Kumar, check this out !!
How can I add functionality init like once the user chooses an option then he should not be able to click again on other option from that question?
change the onClick ahndler like this => onClick={() => !questionAnswered(item.numb) && action(item.numb, optionDesc)} and span style of cursor to cursor: !questionAnswered(item.numb) ? "pointer" : "not-allowed"
I want to make red only that wrong option on which user clicks not all wrong option should red. how to do that.
@AnkitKumar, updated the code sandbox
|
0

I would recommend to create separate component called Question to avoid working with arrays of data and put state login inside. But if this is not possible I would do it this way:

Home.js

import React from 'react'
import Questions from './Questions'

const Home = () => {
    // Add this two state values
    const { highlightedRightIds, setHighlightedRightIds } = useState([]);
    const { highlightedWrongIds, setHighlightedWrongIds } = useState([]);

    // Handle click here
    const handleClick = (questionId, isRight) => {
        setHighlightedWrongIds([...highlightedWrongIds, questionId]);
        if (isRight) {
            setHighlightedRightIds([...highlightedRightIds, questionId]);
        }
    }

    return (
        <>
        <div className="main">
            {
            Questions.map((item)=>(
                <div className="box">
                <div className="title">
                <h2 className="qno">{item.numb}</h2> 
                <h2> {item.question}</h2>
                </div>
                <div className="options">
                   {
                        // use map to render a list of options
                        item.options.map(option => {
                            const isRight = option === item.answer;
                            const highlight = isRight
                                ? highlightedRightIds.includes(item.numb)
                                : highlightedWrongIds.includes(item.numb);
                            const highlightClass = isRight
                                ? "rightAnswer"
                                : "wrongAnswer";
                            
                            return <span
                                onClick={() => handleClick(item.numb, isRight)}
                                className={highlight ? highlightClass : ""}
                            >
                                {option}
                            </span>;
                        })
                   }
                </div>
            </div>
            ))    
            }
        </div>
        </>
    )
}

export default Home;

style.css (add new classes)

// ... other styles

.rightAnswer{
    background-color: green;
}
.wrongAnswer{
    border-color: red;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.