How to combine v-for and v-model to edit a list of objects?

Viewed 738

I would like to edit a list of users using Vue.js. Each user has a name and an age. It seems that v-for is the right directive to work with lists and v-model is the right directive to bind the contents of an input to a particular element in the list.

So I tried to implement it like this:

new Vue({
  el: '#exercise',
  data: {
    users: [{
      name: "martin",
      age: 32
    }]
  },
  methods: {
    add_user: function() {
      this.users.push({
        name: "",
        age: ""
      });
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="exercise">
  <form id="list">
    <div></div>
    <div v-for="user in users">
      <input v-model="user.name">
      <input v-model="user.age">
      <button @click="add_user">+</button>
    </div>
  </form>
</div>

However, once I click the button to add a new user, a new line with input fields is displayed only for a fraction of a second and then disappears, leaving the list of users containing only one element.

Please, could you tell me what am I doing wrong?

3 Answers

The reason is <button> with <form> when you're click button it does the request automatically so its refresh or disappear because it fails to try to use <a> or using <button @click.prevent="add_user" />

<div id="exercise">
  <form id="list">
    <div></div>
    <div v-for="user in users">
      <input v-model="user.name">
      <input v-model="user.age">
      <a @click="add_user">+</a> //solution
      <button @click.prevent="add_user">+</button> //another solution 
    </div>
  </form>
</div>

The button is submitting the form, add .prevent to stop the action:

new Vue({
  el: '#exercise',
  data: {
    users: [{
      name: "martin",
      age: 32
    }]
  },
  methods: {
    add_user () {
      this.users = [ ...this.users, {
        name: "",
        age: ""
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="exercise">
  <form id="list">
    <div v-for="(user, index) in users" :key="index">
      <input v-model="user.name" :key="`name-${index}`">
      <input v-model="user.age" :key="`age-${index}`">
    </div>
    <button @click.prevent="add_user">+</button>
  </form>
</div>

You need to set tye type of the button, since it's inside a form it fallbacks to submit button.

Also, it's good to define a :key to help vue to tell the difference between one line to another on v-for.

new Vue({
  el: '#exercise',
  data: {
    users: [{
      id:new Date().getTime(),
      name: "martin",
      age: 32
    }]
  },
  methods: {
    add_user: function() {
      this.users.push({
        id:new Date().getTime(),
        name: "",
        age: ""
      });
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="exercise">
  <form id="list">
    <div v-for="user in users" :key="user.id">
      <input v-model="user.name">
      <input v-model="user.age">
      <button type="button" @click="add_user">+</button>
    </div>
  </form>
</div>

Related