Home > Software engineering >  "setstate" in vanilla javascript, enforce changes
"setstate" in vanilla javascript, enforce changes

Time:02-13

I am new to Js, and i am coding a simple quiz app with HTML, CSS and JS to learn.

I am a mobile developer and use Flutter and Dart, dart is pretty similar to JS. On the quiz app, when someone presses the next button after an answered question, i want it to switch to the next question.

When the user presses the button nothing happens... In dart i would use the setState method, which forces the UI to reload with the updated changes. Is there an equivalent method in JS? I found that setState is used in ReactJS, however this is coded in vanilla Js.

I have an Array of 2 questions (which are maps containing the questiopn text, answer alternatives and correct answer). Then I have an integer variable which is the questionIndex. So first question the index i 0, and when the user presses the next button ( to go to the next question) it should increment by 1.

Here is the code for the button click:

function onClickNext() {
    console.log("called");
    
    currentQuestionIndex  ;
    
}

the Array of questions:

const questions = [
  {
    question: "What is the capital of Sweden?",
    "alt 1": "Stockholm",
    "alt 2": "Gothenburg",
    "alt 3": "Malmö",
    "alt 4": "Linköping",
    correctIndex: 0,
  },
  {
    question: "What is the capital of England?",
    "alt 1": "London",
    "alt 2": "Manchester",
    "alt 3": "Bournemouth",
    "alt 4": "Cardiff",
    correctIndex: 0,
  },
];

And here are the dynamic HTML components (the question answer alternatives, which are suppoosed to change when next is pressed, so it moves onto the next question.

document.getElementById("question").innerHTML =
  questions[currentQuestionIndex]["question"];
button1.innerHTML = questions[currentQuestionIndex]["alt 1"];
button2.innerHTML = questions[currentQuestionIndex]["alt 2"];
button3.innerHTML = questions[currentQuestionIndex]["alt 3"];
button4.innerHTML = questions[currentQuestionIndex]["alt 4"];

Would be really thankful for some guidance, and also if someone knows a way to make my code more consise and efficiant.

Thank you!

CodePudding user response:

Since Vanilla JS has no state listeners that will update the DOM automatically, you can program this yourself, for example:

function onClickNext() {
    console.log("called")
    
    currentQuestionIndex  
    drawQuestionScreen()
    
}

function drawQuestionScreen(){
   document.getElementById("question").innerHTML =
      questions[currentQuestionIndex]["question"];
   button1.innerHTML = questions[currentQuestionIndex]["alt 1"];
   button2.innerHTML = questions[currentQuestionIndex]["alt 2"];
   button3.innerHTML = questions[currentQuestionIndex]["alt 3"];
   button4.innerHTML = questions[currentQuestionIndex]["alt 4"];
}

CodePudding user response:

Just populate the question HTML anew after calling onClickNext so that the reassignment has an effect.

To make the code more concise, save the question at the current index in a variable first, instead of accessing through the index each time.

const questionDiv = document.getElementById("question");

const populateQuestion = () => {
  const question = questions[currentQuestionIndex];
  questionDiv.innerHTML = question.question;
  button1.innerHTML = question["alt 1"];
  button2.innerHTML = question["alt 2"];
  button3.innerHTML = question["alt 3"];
  button4.innerHTML = question["alt 4"];
}

// populate on pageload:
populateQuestion();

// and also on click:
function onClickNext() {
  currentQuestionIndex  ;
  populateQuestion();
}

An even better approach would be to use an array for the buttons and answers instead of separate property and variable names. Consider naming the array of possible answers answers instead of alt, it'll probably make more sense at a glance.

const populateQuestion = () => {
  const question = questions[currentQuestionIndex];
  questionDiv.innerHTML = question.question;
  question.answers.forEach((answer, i) => {
    buttons[i].textContent = answer;
  });
}

You should also consider using .textContent - only use .innerHTML when deliberately inserting HTML markup.

  • Related