'Vuejs get index in multiple input forms

I have an array of strings like:

questions: [
  "Question 1?",
  "Question 2?",
  "Question 3?",
  "Question 4?",
],

Then I have form fields in my data() like:

legitForm: {
  name: '', // this will be equal to question string
  answer: '',
  description: '',
  duration: '',
},

Now, the problem I'm facing is when I fill inputs for any of questions above the same field for other questions gets same value.

Here is my template code:

<div v-for="(question, index) in questions" :key="index">
    <form @submit.prevent="legitStore(question)" method="post">
        <div class="row">
            <div class="col-md-12">
                <p>
                    <strong>{{question}}</strong>
                </p>
            </div>
            <div class="col-md-6">
                <label for="answer">Answer</label>
                <select class="mb-1 field" v-model="legitForm.answer" name="answer" id="answer">
                    <option value="1">Yes</option>
                    <option value="0">No</option>
                </select>
            </div>
            <div class="col-md-6">
                <label for="duration">Duration</label>
                <input class="field" v-model="legitForm.duration" type="text">
            </div>
            <div class="col-md-12">
                <label for="description">Description</label>
                <textarea style="height: 190px;" type="text" cols="5" rows="10" id="address" class="mb-1 field" v-model="legitForm.description"></textarea>
            </div>
        </div>
        <button type="submit" class="saveButtonExperience float-right btn btn--custom">
            <span class="text">Save</span>
        </button>
    </form>
</div>

And this is my post method that sends data to backend:

legitStore(question) {
    this.legitForm.name = question; // set "name" in `legitForm` to value of `question` string
    axios.post('/api/auth/userLegitsStore', this.legitForm, {
        headers: {
            Authorization: localStorage.getItem('access_token')
        }
    })
    .then(res => {
        // reset my data after success
        this.legitForm = {
            name: '',
            answer: '',
            description: '',
            duration: '',
        };
    })
    .catch(error => {
        var errors = error.response.data;
        let errorsHtml = '<ol>';
        $.each(errors.errors,function (k,v) {
            errorsHtml += '<li>'+ v + '</li>';
        });
        errorsHtml += '</ol>';
        console.log(errorsHtml);
    })
},

Here is issue screenshot:

one

Note: I've tried to

  1. change legitForm to array like legitForm: [], and legitForm: [{....}]
  2. add index to my inputs v-model

but I've got errors so i wasn't sure what I'm doing wrong, that's why I'm asking here.



Solution 1:[1]

If you think of your questions as questions and answers, you can do something like this:

questions: [
  {
    question: 'Question 1',
    answer: null,
    description: null,
    duration: null,
  },
  {
    question: 'Question 2',
    answer: null,
    description: null,
    duration: null,
  },
]

Then when looping through your form, it would be more like this:

<div v-for="(question, index) in questions" :key="index">
    <form @submit.prevent="legitStore(question)" method="post">
      ...
      <select class="mb-1 field" v-model="question.answer" name="answer" id="answer">
        <option value="1">Yes</option>
        <option value="0">No</option>
      </select>
      ...
    </form>
</div>

And in the storing function you could send the data in the question instead of this.legitForm

Solution 2:[2]

<div v-for="(question, index) in questions" :key="index">

In your template you iterate through questions and within this tag render object legitForm it all questions will refer to the same 1 object that's why all question have the same data.

You should have had create an array of question contains it own question's content like

<template>
  <div v-for="(question, index) in questions" :key="index">
    <form @submit.prevent="legitStore(question)" method="post">
      ...
      <div class="col-md-12">
         <p>
            <strong>{{question.id}}</strong>
         </p>
      </div>
      ...
      <select class="mb-1 field" v-model="question.answer" name="answer" id="answer">
        <option value="1">Yes</option>
        <option value="0">No</option>
      </select>
      ...
    </form>
  </div>
</template>

<script>
class QuestionForm {
  // pass default value if you want
  name = ''
  answer = ''
  description = ''
  duration = ''
  id = ''
  constructor(form) {
    Object.assign(this, form)
  }
}

function initQuestions(num) {
  // can generate a Set object cause question are unique
  return Array.from({ length: num }, (v, i) => i).map(_j => new QuestionForm())
}

export default {
  data() {
    return {
      questions: initQuestions(5), // pass number of question you want to generate
    }
  }
}
</script>

Solution 3:[3]

Like you said you tried here:

change legitForm to array like legitForm: [], and legitForm: [{....}]

add index to my inputs v-model

You are supposed to be doing that.

I would change legitForm to:

//create legitForms equal to the length of questions
const legitForms = [];

for (i in questions) legitForms.push(
  {
    name: '', // this will be equal to question string
    answer: '',
    description: '',
    duration: '',
  }
);

and in template:

<div v-for="(question, index) in questions" :key="index">
    <form @submit.prevent="legitStore(question)" method="post">
        <div class="row">
            <div class="col-md-12">
                <p>
                    <strong>{{question}}</strong>
                </p>
            </div>
            <div class="col-md-6">
                <label for="answer">Answer</label>
                <select class="mb-1 field" v-model="legitForms[index].answer" name="answer" id="answer">
                    <option value="1">Yes</option>
                    <option value="0">No</option>
                </select>
            </div>
            <div class="col-md-6">
                <label for="duration">Duration</label>
                <input class="field" v-model="legitForms[index].duration" type="text">
            </div>
            <div class="col-md-12">
                <label for="description">Description</label>
                <textarea style="height: 190px;" type="text" cols="5" rows="10" id="address" class="mb-1 field" v-model="legitForms[index].description"></textarea>
            </div>
        </div>
        <button type="submit" class="saveButtonExperience float-right btn btn--custom">
            <span class="text">Save</span>
        </button>
    </form>
</div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Joakim Johansson
Solution 2
Solution 3 cSharp