jSutcliffe90
jSutcliffe90

Reputation: 323

Updating array inside vue components data

I have a key inside my components data that may be initialised as null or have some strings inside. I want to be able to create as many associatedKeys as I want, while also allowing for it to be initialised as null or with multiple values. The problem I'm having is that each time I am pressing the button to add a new input field, the page is re rendering and the data is then reset once initialised again.

I have been looking at this article, I have placed a debugger inside the addKeys function and am getting the error message this.licence.associatedKeys.$set is not a function. I don't understand this error and am not sure how to add elements to the associatedKeys array

<template>
    <div>
        <form>
            <label>Associated Keys</label>
            <button v-on:click="addNewKey">Add new key</button>
            <div v-for="(k,index) in licence.associatedKeys" :key="k">
                <input type="text" :value="k" @input="licence.associatedKeys[index]=$event.target.value">
            </div>  
        </form>
    </div>
</template>

<script>
import util from '~/assets/js/util'
export default {
    methods: {
        addNewKey() { 
            this.licence.associatedKeys.$set(this.licence.associatedKeys, null)
        }
    },
    data: () => ({
        licence: {
            associatedKeys: []
        }
    })
}
</script>

Upvotes: 2

Views: 64

Answers (2)

FK82
FK82

Reputation: 5075

Have a look at event modifiers, specifically this example:

<!-- the submit event will no longer reload the page -->
<form v-on:submit.prevent="onSubmit"></form>

I think this is what you need to stop the page reloading.

As for the undefined error: you can try to use the instance itself, i.e.

this.$set('license.associatedKeys[' + this.license.associatedKeys.length + ']', null); 

Also, you probably misread the documentation, the .$set and .$add methods on nested data properties take key and value arguments. So, you should have written

this.licence.associatedKeys.$set(this.licence.associatedKeys.length, null)

Upvotes: 1

Daniel
Daniel

Reputation: 35724

the reason you get a redirect is that you have a button inside a form. While other browsers don't, Chrome will treat it as a redirect by default. The easiest way to resolve it is to define an action action="#" that way, you don't have to handle every button to prevent default action.

@input is fine, but vue has a lot of built-in functionality, such as v-model that will automatically bind value, showing and updating it on change.

you don't need to use $set when you're pushing (plus you set it on the vue instance and not the value (this.$set(this.myVal, 'myKey', null) instead of this.myVal.myKey.$set(null))

finally, if you want key-value pair stored in an array, you need two objects the key and the value

new Vue({
  el: "#app",
  methods: {
    addNewKey() {
      //this.licence.associatedKeys.$set(this.licence.associatedKeys, null)
      this.licence.associatedKeys.push({key:null, val:null});
    }
  },
  data: () => ({
    licence: {
      associatedKeys: []
    }
  })
})
body {background: #20262E;padding: 20px;font-family: Helvetica;}
button {padding: 8px 16px;border-radius: 20px;border: none;}
#app {background: #fff;border-radius: 4px;padding: 20px;transition: all 0.2s;}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
    <div>
        <form action="#">
            <label>Associated Keys</label>
            <button v-on:click="addNewKey">Add new key</button>
            <div v-for="(k,index) in licence.associatedKeys" :key="k">
                <input type="text" v-model="k.key">
                <input type="text" v-model="k.val">
            </div>  
        </form>
    </div>
    <pre>{{this.licence}}</pre>
</div>

Upvotes: 1

Related Questions