0

So, I need to generate x amount of "selects" based on a result from a query to an external endpoint.

Below is an example of the json that is the data I use to generate my selects. This example contains only one "question" in an array of "questions". (Also, the array construct inside the "answers" is a little bit exaggerated but that's what I have to work with)

"questions": [{
    "question": [
    {
       "answers": [
        {
          "answer": [
            {
              "answer": "Answer 1",
              "id": 216,
              "questionID": 83,
              "selected": false,
              "sortOrder": 1
            },
            {
              "answer": "Answer 2",
              "id": 217,
              "questionID": 83,
              "selected": true,
              "sortOrder": 2
            },    
            ... plus x number of "answers" here..           
          ]
        }
       ],
       "question": "Question 1",
     }
    ]}
 ...]

So, I generate the selects like so (I have stripped the example from irrelevant styling):

<v-layout row wrap v-for="question in questionnaire.questions[0].question" 
:key="question.id">  
      <span>{{question.question}}</span>

      <v-select
        item-text="answer"
        item-value="id"
        :items="question.answers[0].answer"
        ref="answer_selects"    
      ></v-select>

Now, back to my question. As you can see in the json the second "answer" has a property "selected" with the value of "true". This means that I have to set this particular item as selected "by default". How do I achieve this in a good vue manner?

Toby Fieldgroove
  • 243
  • 4
  • 16

1 Answers1

1

If you only want to set it as a default value, vou can use the :value-Property and just pass the first Object from the answer-array that has selected set to true.

:value="question.answers[0].answer.find(answer -> answer.selected)"

Note that when using that the value is not bound to what is selected, so if you select a different item the data in the parent component will not update! If you want it automatically updated, you should consider using v-model along with computed-properties.

Edit: Ok so I've looked into your question a bit deeper and I think I came up with a pretty good solution.

First of all, I don't really understand the properties you set in the v-select component, since none of them are defined in the VueSelect Api. In this answer I use the properties defined there. Also, I'm not quite sure how to interpret your data structure, so I'll just give an example with a array of questions which contains an id, a question text and an array of answers.

In order to use v-model with a computed property you have to to implement a getter which will be called to set the v-select-component data and a setter for updating the data when a different item is selected in the select-component. Since in your case you would have to have one computed property for each element in the questions-array, you should wrap the display of a question-object into its own component and display multiple of those in a loop.

Vue.component('v-select', VueSelect.VueSelect);
Vue.component("question", {
  "template": "#questionTemplate",
  "props": {
    "question": Object
  },
  "computed": {
    "selectedId": {
      "get": function() {
        return this.question.answers.find(answer => answer.selected).id;
      },
      "set": function(id) {        
        //set selected flag on newly selected element
        this.question.answers.find(answer => answer.id === id).selected = true;
        //reset previous choice
        this.question.answers.find(answer => answer.selected && answer.id !== id).selected = false;
      }
    }
  }
});

new Vue({
  "el": "#app",
  "data": function() {
    return {
      "questions": [
        {
          "id": 83,
          "question": "QuestionText",
          "answers": [
            {
              "answer": "Answer 1",
              "id": 216,
              "questionID": 83,
              "selected": false,
              "sortOrder": 1
            },
            {
              "answer": "Answer 2",
              "id": 217,
              "questionID": 83,
              "selected": true,
              "sortOrder": 2
            }
          ]
        }
      ]
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-select@latest"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-select@latest/dist/vue-select.css">

<div id="app">
  <question v-for="question in questions" :question="question" :key="question.id"></question>
</div>

<script type="text/x-template" id="questionTemplate">
  <div>
    <p>{{question.question}}</p>
    <v-select
      v-model="selectedId"
      :options="question.answers" 
      label="answer"
      :reduce="answer => answer.id"></v-select>
      
      <p>Selected AnswerId: {{selectedId}}</p>
  </div>
</script>

If you want to be able to select multiple values, the VueSelect-component will return an array of IDs instead of one single ID, sou you woukd have to adjust the computed getter and setter accordingly.

Hope I could help, let me know if you need any further help!

Josef
  • 304
  • 2
  • 14
  • Could you elaborate on how to use v-model and computeds? I noticed that if I put a v-model="something" on my selects the result is that whenever I select something in a select all the other selects lose their selected value..so they go blank so to speak... – Toby Fieldgroove Sep 14 '19 at 08:25
  • What I didn't show in my example is that I also create checkboxes dynamically from some types of questions that are "multiple choice". These checkboxes I can bind to a v-model which holds all the checkboxes answer-id in an array.. But for the selects it doesn't appear to work that way... – Toby Fieldgroove Sep 14 '19 at 08:59
  • Thank you! Even though I solved it in another manner (by using the $refs where the selected item is available) I think this looks like a more vue-ish solution. The reason why you don't understand the properties is probably because I'm on vuetify 1.5 instead of the current 2.0-something... :) – Toby Fieldgroove Sep 17 '19 at 14:26