7

My data is stored in an array. For each array item, there should be a text input in the form. When the user types into one of the text inputs, the array should be updated with the new values.

  <div class="form-group" v-for="synonym in row.synonyms">
    <input type="text" class="form-control" v-model="synonym" />
  </div>

Here's a fiddle: https://jsfiddle.net/eywraw8t/122210/

The idea is when you type into one of the textboxes, the array value (shown below in that fiddle) should also update, but it doesn't.

3 Answers 3

4

Upon inspecting the console, you would find the following error:

You are binding v-model directly to a v-for iteration alias. This will not be able to modify the v-for source array because writing to the alias is like modifying a function local variable. Consider using an array of objects and use v-model on an object property instead.

Meaning, we need to give v-model access to a direct reference to the synonym and its index:

new Vue({
  el: "#app",
  data: {
    row: {
    	synonyms: [
      	"abc", 
        "def", 
        "ghj",
      ]
    }
  },
  methods: {

  }
})
body {
  font-family: 'Exo 2', sans-serif;
}

#app {
  margin: auto;
}
<div id="app">
  <h2>Items</h2>
  <div class="form-group" v-for="(synonym,i) in row.synonyms">
    <input type="text" class="form-control" v-model="row.synonyms[i]" />
  </div>
  
  <br>
  
  <h3>
  The text below should change if yout type inside the textboxes:
  </h3>
  
  <p>
  {{ JSON.stringify(row)}}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

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

6 Comments

I'm still learning Vue but I'm pretty sure you don't want form-group AND v-for in the same tag. Otherwise, you'll end up with multiple form-group divs. I'm happy to be corrected if I'm mistaken.
@ultrageek - it really doesn't matter here, I typically add the v-for to a parent because I'm using the contents (in this case, row.synonyms[i]) multiple times within the children; here that doesn't really apply, so you could remove the div and use the v-for directly on the input.
It doesn't matter for the loop functionality, but you want the form-group to be an ancestor up, not in where the v-for is. That's all I was pointing out
@ultrageek - the form group is just a class name I made up, it's entirely irrelevant here. It could be named foo and it'd still accomplish the same thing.
Well Bootstrap has it, and I was using it when I read your comment. So I assumed that's what you were doing. My bad
|
2

The correct way to do it is to use an index, which vue.js provides in loops:

  <div class="form-group" v-for="(synonym, index) in row.synonyms">
    <input type="text" class="form-control" v-model="row.synonyms[index]" />
  </div>

https://jsfiddle.net/m14vd89u/1/

1 Comment

Darn, you beat me to the punch
0

This is the recommended way that Vue.js wants you to do it by using an index (synonym, index):

https://v2.vuejs.org/v2/guide/list.html

<div class="form-group" v-for="(synonym, index) in row.synonyms">
  <input type="text" class="form-control" v-on:blur="onItemsChanged(synonym)" v-model="row.synonyms[index]" />
</div>

If you wanted to do it another way you could introduce a method v-on:blur:

new Vue({
  el: "#app",
  data: {
    row: {
        synonyms: [
        "abc", 
        "def", 
        "ghj",
      ]
    }
  },
  methods: {
    onItemsChanged (synonym) {
      // do something with array
    }
  }
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.