2

I have five questions with 4 answers each on one website. Only one button should be clickable per question.

How can I do this?

new Vue({
  el: '#app',
  data: {
    answers: {},
    currentQuestion: {
      examples: {
        A: 'Lack zum Lackieren der Computergehäuse',
        B: 'Elektrische Energie für die Montagewerkzeuge',
        C: 'Silizium zur Herstellung der CPU',
        D: 'Schrauben zum Befestigen von Bauteilen',
        E: 'Zugekaufte Computergehäuse aus Stahlblech'
      },
      answers: {
        '1': 'Rohstoff',
        '2': 'Fremdbauteil',
        '3': 'Hilfsstoff',
        '4': 'Betriebsstoff'
      },
      rights: {
        A: 3,
        B: 4,
        C: 1,
        D: 3,
        E: 2
      }
    }
  },
  methods: {
    selectedOneAnswerButton(index) {
      Array.from(this.answers).forEach(answer => (answer.active = false));
      let answer = this.answers[index];
      answer.active = !answer.active;
      this.$set(this.answers, index, answer);
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<div id="app">
<div
      v-bind:key="index"
      v-for="(example, index) in currentQuestion.examples"
      class="row"
    >
      <div class="col-md-12">
        <p class="p-3 mb-2 bg-dark text-white">{{ example }}</p>
      </div>
      <div
        v-bind:key="index"
        v-for="(answer, index) in currentQuestion.answers"
        class="col-md-6"
      >
        <p>
          <button
            v-bind:class="{
              'btn-primary': answer.active,
              'btn-secondary': !answer.active
            }"
            v-on:click="selectedOneAnswerButton(index)"
            class="btn btn-lg btn-block"
          >
            {{ answer }}
          </button>
        </p>
      </div>
    </div>
 </div>

That worked

That worked the first time I needed it, but it didn't work the second time I asked a simple question with 4 answers ... and certainly not in the current situation with the four questions and the four possible answers.

Here is the example in JavaScript how I managed it without changing my data.

var currentQuestion =  {
  examples: {
      "A": "Lack zum Lackieren der Computergehäuse",
      "B": "Elektrische Energie für die Montagewerkzeuge",
      "C": "Silizium zur Herstellung der CPU",
      "D": "Schrauben zum Befestigen von Bauteilen",
      "E": "Zugekaufte Computergehäuse aus Stahlblech"
  },
  answers: {
      "1": "Rohstoff",
      "2": "Fremdbauteil",
      "3": "Hilfsstoff",
      "4": "Betriebsstoff"
  },
  rights: {
      "A": 3,
      "B": 4,
      "C": 1,
      "D": 3,
      "E": 2 
  }
};

function selectAnswer(id) {
  $(id).addClass("btn-primary");
  $(id).removeClass("btn-secondary");
}

function deselectAnswer(id) {
  $(id).addClass("btn-secondary");
  $(id).removeClass("btn-primary");
}

var root = document.getElementById("container");
var mutlipleequestionscreen = document.createElement("div");
buildMultipleQuestionScreen();

// LAYOUT
function buildMultipleQuestionScreen() {
  console.log("buildMultipleQuestionScreen");
  mutlipleequestionscreen.id = "multiple-question-screen";
  mutlipleequestionscreen.className = "jumbotron question";
  root.appendChild(mutlipleequestionscreen);
  var div = document.createElement("div");
  div.id = "multiple-questions";
  var h2 = document.createElement("h2");
  h2.textContent = "Frage ";
  var span = document.createElement("span");
  span.className = "multiple-question-number";
  span.textContent = currentQuestion.id;
  var div2 = document.createElement("div");
  div2.className = "situation p-3 mb-2 bg-info text-white";
  var p = document.createElement("p");
  p.className = "multiple-question-situation";
  p.textContent = currentQuestion.situation; 
  var p2 = document.createElement("p");
  p2.className = "multiple-question-description";
  p2.textContent = currentQuestion.description;
  var p3 = document.createElement("p");
  p3.className = "multiple-question-text";
  p3.textContent = currentQuestion.question;
  var p4 = document.createElement("p");
  p4.className = "multiple-question-exercise";
  p4.textContent = currentQuestion.exercise;
  var p5 = document.createElement("p");
  p5.className = "multiple-question-note";
  p5.textContent = currentQuestion.note;
  mutlipleequestionscreen.appendChild(div);
  div.appendChild(h2);
  h2.append(span);
  div.appendChild(div2);
  div2.appendChild(p);
  div.appendChild(p2);
  div.appendChild(p3);
  div.appendChild(p4);
  div.appendChild(p5);
  var letter = "";
  for(var i = 0; i < Object.keys(currentQuestion.examples).length; i++)
  {
      var row = document.createElement("div");
      row.className = "row";
      var div3 = document.createElement("div");
      div3.className = "col-md-12";
      var p6 = document.createElement("p");
      p6.className = "p-3 mb-2 bg-dark text-white";
      p6.textContent = Object.keys(currentQuestion.examples)[i] + " : ";
      var span2 = document.createElement("span");
      letter = Object.keys(currentQuestion.examples)[i];
      span2.id = "multiple-question-example-" + letter.toLowerCase();
      span2.textContent = currentQuestion.examples[Object.keys(currentQuestion.examples)[i]];
      div.appendChild(row);
      row.appendChild(div3);
      div3.appendChild(p6);
      p6.appendChild(span2);
      var row2 = document.createElement("div");
      row2.className = "row";
      for(var j = 1; j <= Object.keys(currentQuestion.answers).length; j++)
      {
          if(j % 2 != 0)
          {
              div.appendChild(row2);
          }
          var div4 = document.createElement("div");
          div4.className = "col-md-6";
          var p7 = document.createElement("p");
          var button = document.createElement("button");
          button.id = "multiple-question-answer-" + letter.toLowerCase() + "-" + j + "-btn"
          button.className = "answer answer-btn answer-" + letter.toLowerCase() + "-btn answer-" + j + "-btn btn btn-secondary btn-lg btn-block";
          var span3 = document.createElement("span");
          span3.className = "multiple-question-answer-" + j;
          span3.textContent = Object.keys(currentQuestion.answers)[j - 1] + ": " + currentQuestion.answers[j];
          button.addEventListener("click", function() {
              selectAnswer(this);
              var letterTmp = this.id.split('-')[3];
              $(".answer-" + letterTmp + "-btn").not(this).each(function() {
                deselectAnswer(this);
              });
              console.log(this.id);
          });
          row2.appendChild(div4);
          div4.appendChild(p7);
          p7.appendChild(button);
          button.appendChild(span3);
      }
  }
  var row3 = document.createElement("div");
  row3.className = "row";
  var div5 = document.createElement("div");
  div5.className ="col-md-10";
  var div6 = document.createElement("div");
  div6.className = "col-md-2";
  var p8 = document.createElement("p");
  var button2 = document.createElement("button");
  button2.id = "multiple-question-answer-commit-btn";
  button2.className = "answer-commit-btn btn btn-primary btn-lg btn-block";
  var span4 = document.createElement("span");
  span4.className = "multiple-question-commit-text";
  span4.textContent = "Antworten";
  // MULTIPLE QUESTION ANTWORTEN BUTTON
  button2.addEventListener("click", function() {
      // IN DEN GLOBALEN EINSTELLUNGEN
      // .answer-commit-btn
      answerCommitButton();
  });
  var p9 = document.createElement("p");
  var button3 = document.createElement("button");
  button3.id ="multiple-question-continue-btn";
  button3.className = "continue-btn btn btn-primary btn-lg btn-block";
  button3.style = "display: none;";
  var span5 = document.createElement("span");
  span5.textContent = "Weiter";
  // MULTIPLE QUESTION WEITER BUTTON
  button3.addEventListener("click", function() {
      var node = document.getElementById("container");
      var child = document.getElementById("multiple-question-screen");
      var child2 = document.getElementById("multiple-questions");
      node.removeChild(child);
      child.removeChild(child2);
      // IN DEN GLOBALEN EINSTELLUNGEN
      continueButton();
  });
  div.appendChild(row3);
  row3.appendChild(div5);
  row3.appendChild(div6);
  div6.appendChild(p8);
  p8.appendChild(button2);
  button2.appendChild(span4);
  div6.appendChild(p9);
  p9.appendChild(button3);
  button3.appendChild(span5);
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    
    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
  <body>
    <div id="container">

    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="example.js"></script>
  </body>
</html>

It is possible to do this in VUE.JS without changing my data?

12
  • Can you rewrite your snippet into a working minimal reproducible example ? i.e. without the export? Commented Apr 3, 2020 at 6:29
  • I rewrite it and try it. Commented Apr 3, 2020 at 6:56
  • I added it for you ;) Commented Apr 3, 2020 at 7:02
  • I changed the code again and don't know how to fix the next error Commented Apr 3, 2020 at 7:17
  • Okay, but how can I change it so that it works? Commented Apr 3, 2020 at 7:23

1 Answer 1

2

The issue is your answers are a string, but you're treating it like an object. Trying to add the active property to it which is not going to work.

Another problem is that if you modify the answers, it will impact all the questions, instead of just the one. Since they all share the same array.

Instead i would modify your examples object, to contain objects instead of strings. This object would contain the question and the answer the user picks. That way you will have a specific answer for each question, and the user can only pick one since it will overwrite the old value.

Note: @click is shorthand for v-on:click, and :class is shorthand for v-bind:class

Option 1:

new Vue({
  el: '#app',
  data: {
    answers: {},
    currentQuestion: {
      examples: {
        A:  {
          question: 'Lack zum Lackieren der Computergehäuse',
          pickedAnswer: null
        },
        B:  {
          question: 'Elektrische Energie für die Montagewerkzeuge',
          pickedAnswer: null
        },
        C:  {
          question: 'Silizium zur Herstellung der CPU',
          pickedAnswer: null
        },
        D:  {
          question: 'Schrauben zum Befestigen von Bauteilen',
          pickedAnswer: null
        },
        E:  {
          question: 'Zugekaufte Computergehäuse aus Stahlblech',
          pickedAnswer: null
        }
      },
      answers: {
        '1': 'Rohstoff',
        '2': 'Fremdbauteil',
        '3': 'Hilfsstoff',
        '4': 'Betriebsstoff'
      },
      rights: {
        A: 3,
        B: 4,
        C: 1,
        D: 3,
        E: 2
      }
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<div id="app">
<div
      :key="index"
      v-for="(example, index) in currentQuestion.examples"
      class="row"
    >
      <div class="col-md-12">
        <p class="p-3 mb-2 bg-dark text-white">{{ example.question }}</p>
      </div>
      <div
        :key="index"
        v-for="(answer, index, key) in currentQuestion.answers"
        class="col-md-6"
      >
        <p>
          <button
            :class="{
              'btn-primary': example.pickedAnswer == key,
              'btn-secondary': example.pickedAnswer != key
            }"
            @click="example.pickedAnswer = key"
            class="btn btn-lg btn-block"
          >
            {{ answer }}
          </button>
        </p>
      </div>
    </div>
 </div>

Instead of converting your examples to objects, you can add a new property to your currentQuestion object. I've called it pickedAnswers in the example, this object will contain which answers the user has picked.

Option 2:

new Vue({
  el: '#app',
  data: {
    answers: {},
    currentQuestion: {
      examples: {
        A: 'Lack zum Lackieren der Computergehäuse',
        B: 'Elektrische Energie für die Montagewerkzeuge',
        C: 'Silizium zur Herstellung der CPU',
        D: 'Schrauben zum Befestigen von Bauteilen',
        E: 'Zugekaufte Computergehäuse aus Stahlblech'
      },
      pickedAnswers: {
        A: null,
        B: null,
        C: null,
        D: null,
        E: null,
      },
      answers: {
        '1': 'Rohstoff',
        '2': 'Fremdbauteil',
        '3': 'Hilfsstoff',
        '4': 'Betriebsstoff'
      },
      rights: {
        A: 3,
        B: 4,
        C: 1,
        D: 3,
        E: 2
      }
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<div id="app">
<div
      :key="index"
      v-for="(example, questionKey, index) in currentQuestion.examples"
      class="row"
    >
      <div class="col-md-12">
        <p class="p-3 mb-2 bg-dark text-white">{{ example }}</p>
      </div>
      <div
        :key="index"
        v-for="(answer, key) in currentQuestion.answers"
        class="col-md-6"
      >
        <p>
          <button
            :class="{
              'btn-primary': currentQuestion.pickedAnswers[questionKey] == key,
              'btn-secondary': currentQuestion.pickedAnswers[questionKey] != key
            }"
            @click="currentQuestion.pickedAnswers[questionKey] = key"
            class="btn btn-lg btn-block"
          >
            {{ answer }}
          </button>
        </p>
      </div>
    </div>
 </div>

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

3 Comments

I added my example code in JavaScript to my post. Can you check it out? Maybe you can convert it in Vue.js without changing the data? If it isn't possible, than I have to change my data...
@Snowappix You're doing DOM manipulation using jQuery in that code. That wont work in Vue. If you don't want to modify your data, you can instead add a new property, which will contain what the user has picked instead of keeping it with the questions.
Can you show me an example of what you mean? Sry, but I'm new in Vue.js...

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.