75

I have an input text field with a v-model attached, and every time someone hits the "Add" button, another input text gets added to the DOM with the same v-model attached. I thought I'd then get an array of the v-model values, but it only gets the value of the first v-model input:

<div id="app">
  <div id="references">
    <input v-model="references" type="text">
  </div>
  <button @click="addReference">Add</button>
</div>

The html I append to the dom is triggered by the addReference method:

addReference: function(e) {
  e.preventDefault();
  console.log(this.references);
  var inputEl = '<input v-model="references" type="text">';
  $('#references').append(inputEl);
}

Is this something Vue.js can't do? Is there a different approach of gathering values from dynamic dom elements with Vue.js?

new Vue({
  el: "#app",
  data: {
    references: "text"
  },
  methods: {
    addReference: function(e) {
      e.preventDefault();
      console.log(this.references);
      var inputEl = '<input v-model="references" type="text">';
      $('#references').append(inputEl);
    }
  }
})
input {
  display: block;
  margin: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app">
  <div id="references">
    <input v-model="references" type="text">
  </div>
  <button @click="addReference">Add</button>
</div>
Dave Mackey
  • 4,306
  • 21
  • 78
  • 136
jlos
  • 1,010
  • 1
  • 8
  • 12
  • 15
    Looking back after using Vue for a couple years, at this personal "hello world" Vue question makes me smile, come a long way :D Thanks againd @Bill Criswell – jlos Mar 29 '18 at 12:52
  • 2
    I love to hear that! Sorry I didn't see this sooner. – Bill Criswell Jan 17 '19 at 02:08
  • 1
    No problem ^^ Vue makes it so easy to do quite complex things, absolutely loving it still – jlos Jan 17 '19 at 14:46

3 Answers3

124

You're thinking through DOM, it's a hard as hell habit to break. Vue recommends you approach it data first.

It's kind of hard to tell in your exact situation but I'd probably use a v-for and make an array of finds to push to as I need more.

Here's how I'd set up my instance:

new Vue({
  el: '#app',
  data: {
    finds: []
  },
  methods: {
    addFind: function () {
      this.finds.push({ value: '' });
    }
  }
});

And here's how I'd set up my template:

<div id="app">
  <h1>Finds</h1>
  <div v-for="(find, index) in finds">
    <input v-model="find.value" :key="index">
  </div>
  <button @click="addFind">
    New Find
  </button>
</div>

Although, I'd try to use something besides an index for the key.

Here's a demo of the above: https://jsfiddle.net/crswll/24txy506/9/

Joel G Mathew
  • 7,561
  • 15
  • 54
  • 86
Bill Criswell
  • 32,161
  • 7
  • 75
  • 66
  • 2
    Aha! So by making finds an array, which allows you to create a v-for, you kind of tell vue it's going to be an array, opposed to expecting v-model single-value to array-value magic of vuejs! Thanks a bunch! Absolutely loving Vuejs. – jlos Jan 17 '16 at 09:54
  • Actually @Bill Criswell, although this has cleared up some things, it's not really an answer to what I need, so let me try to rephrase. I have an array of references to a find, and when someone adds a find (clicks the + button) a new input field appears that can be filled with another reference. So basically it's a list of references that a user can provide. – jlos Jan 18 '16 at 12:52
  • 1
    That's what the fiddle is doing as far as I can see. – Bill Criswell Jan 18 '16 at 17:03
  • 1
    Thanks a lot, `thinking too DOM, it's a hard as hell habit to break` – Oniya Daniel Jun 16 '17 at 20:40
  • How did vuejs knew that It should access the find[x].value? even without specifying the x?... – Sean Reyes Sep 16 '18 at 00:50
  • 1
    When I try this, I get `vue.runtime.esm.js?2b0e:1737 TypeError: Cannot read property '_withTask' of undefined` – Soubriquet Dec 09 '18 at 21:51
  • It's possible to use Array type with no key? Like something `["aa", "bb"]`, or Vue need an Array of objects? – ManUtopiK Sep 02 '19 at 19:23
  • You can but you'd need to use an `index` as the `:key`. I just noticed in this answer I don't use a `key` so I'll update that. – Bill Criswell Sep 02 '19 at 20:53
  • It's working but not reflecting in a computed property @BillCriswell – Jatin Raikwar Oct 14 '19 at 17:04
31

If you were asking how to do it in vue2 and make options to insert and delete it, please, have a look an js fiddle

new Vue({
  el: '#app',
  data: {
    finds: [] 
  },
  methods: {
    addFind: function () {
      this.finds.push({ value: 'def' });
    },
    deleteFind: function (index) {
      console.log(index);
      console.log(this.finds);
      this.finds.splice(index, 1);
    }
  }
});
<script src="https://unpkg.com/vue@2.5.3/dist/vue.js"></script>
<div id="app">
  <h1>Finds</h1>
  <div v-for="(find, index) in finds">
    <input v-model="find.value">
    <button @click="deleteFind(index)">
      delete
    </button>
  </div>
  
  <button @click="addFind">
    New Find
  </button>
  
  <pre>{{ $data }}</pre>
</div>
Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
14

Here's a demo of the above:https://jsfiddle.net/sajadweb/mjnyLm0q/11

new Vue({
  el: '#app',
  data: {
    users: [{ name: 'sajadweb',email:'sajadweb@outlook.com' }] 
  },
  methods: {
    addUser: function () {
      this.users.push({ name: '',email:'' });
    },
    deleteUser: function (index) {
      console.log(index);
      console.log(this.finds);
      this.users.splice(index, 1);
      if(index===0)
      this.addUser()
    }
  }
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
  <h1>Add user</h1>
  <div v-for="(user, index) in users">
    <input v-model="user.name">
    <input v-model="user.email">
    <button @click="deleteUser(index)">
      delete
    </button>
  </div>
  
  <button @click="addUser">
    New User
  </button>
  
  <pre>{{ $data }}</pre>
</div>
sajjad
  • 626
  • 1
  • 7
  • 25