Search code examples
javascriptvue.jsvuex

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>

Solution

  • 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>