Home > front end >  Vue.js - loop through simple Object and send Object when user clicks a checkbox
Vue.js - loop through simple Object and send Object when user clicks a checkbox

Time:08-25

I am new to Vue.js and would like to understand how v-model works with a checkbox. I am working with vuetify checkboxes. My components gets an object as value prop and I would like to display checkboxes according to each key value pair that would look like that

this.value = {property1: true, property2: false} So here i want to display a checkbox with lable property1 and the checkbox should be checked as the value is true. The second checkbox would be unchecked.

When checking a checkbox I want to send an object with the key and the value in order to save it. I am only able to get the value for now, but what can I do with it ? If I try to get the key and the value, the issue is that when i uncheck it sends null instead of the key, value pair, how should i manage this ?

  <template>
  <div >
    <div >
      <v-checkbox
        
        ref="additionalDetails"
        v-for="(value, key) in additionalDetails"
        type="checkbox"
        :key="key"
        :value="{key, value}"
        v-model="additionalDetails"
        :label="key"
        ><template v-slot:label
          ><span 
            >{{
              key
            }}
          </span>
        </template></v-checkbox
      >
    </div>
  </div>
</template>

<script>
export default {
  name: "additional-details",

  props: {
    value: Object,
  },
  components: {},
  data: function () {
    return {
      newAdditionalDetails: [],
    };
  },
  computed: {
    additionalDetails: {
      get: function () {
        return this.value;
      },
      set: function ({ key, value}) {
        let newObject = { ...this.value };
        newObject[key] = value;
        this.newAdditionalDetails = newObject
      },
    },
  },
  methods: {},
  beforeMount() {},
};
</script>

CodePudding user response:

v-model should be same type of value you want to track, in this case an object, but actually because of the v-for an array of objects, initialized with the values you expect the checkboxes to hold/emit. The v-checkbox component will also need to be explicitely told what object key-value equals 'truthy' vs 'falsy'. Another tip: since you're also looping over object properties, a third alias in the v-for will give you the index. Something like this will work:

<template>
  <div>
    <v-checkbox
      v-for="(value, key, index) in initValues" :key=index
      :label=key
      v-model=checkboxes[index]
      :value="{ key: key, value: value }"
      :false-value="{ key: key, value: false }"
      :true-value="{ key: key, value: true }"
      @change="log(checkboxes[index])"
    ></v-checkbox>
  </div>
</template>

<script>
export default {
  data: () => ({
    initValues: {
      'hi': true,
      'bye': false,
      'ok': true
    },
    checkboxes: []
  }),
  methods: {
    log(newValue) {
      console.log(newValue)
    }
  },
  created() {
    // initialize array of objects where each object is a key-value pair from initValues
    this.checkboxes = Object.entries(this.initValues).map(( [k, v] ) => ({ [k]: v }))
  }
};
</script>

It's a bit tricky, and is honestly not how I would've done it. A simpler solution would be to track just the value and create/send the key-value pair as the checkbox input changes, e.g.

<template>
  <div>
    <v-checkbox
      v-for="(value, key, index) in initValues" :key=index
      :label="key"
      v-model=checkboxes[index]
      @change="log(key, checkboxes[index])"
    ></v-checkbox>
  </div>
</template>

<script>
export default {
  data: () => ({
    initValues: {
      'hi': true,
      'bye': false,
      'ok': true
    },
    checkboxes: []
  }),
  methods: {
    log(key, newValue) {
      console.log({ [key]: newValue })
    }
  },
  created() {
    this.checkboxes = Object.values(this.initValues)
  }
};
</script>

CodePudding user response:

Instead of writing this much complex logic, You can simply achieve that by binding object property in v-model as per the additionalDetails.

Live Demo :

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data () {
    return {
      additionalDetails: [{
        property1: true
      }, {
        property2: false
      }]
    }
  },
  methods: {
    getChecboxValues() {
      console.log('additionalDetails', JSON.stringify(this.additionalDetails))
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://unpkg.com/@mdi/[email protected]/css/materialdesignicons.min.css"/>
<div id="app">
  <v-app id="inspire">
    <v-container
      
      fluid
    >
      <v-checkbox
        v-for="(value, key) in additionalDetails"
        :key="key"          
        :label="Object.keys(value)[0]"
        v-model="value[Object.keys(value)[0]]"          
      ></v-checkbox>
      <v-btn depressed color="primary" @click="getChecboxValues">
        Submit
      </v-btn>
    </v-container>
  </v-app>
</div>

CodePudding user response:

Finally what I did I converted to an array the initail object (that comes in stringified by the way here) and added the checked prop to update in the v-model. I also had to add a method to set the new object (The example code below is a bit different from the original one sorry for that) Somehow the setter of the computed additionalDetails never triggers I have no clue why, if someone has, thanks in advance for sharing toughts.

<template>

          <div >
            <div >
              <v-checkbox  ref="additionalDetails" v-for="(prop, index) in additionalDetails" type="checkbox" :label="prop.label" :key="index" :dataIndex="index" v-model="prop.checked" @change="setAdditionalDetails(prop)"><template v-slot:label><span >{{ prop.label }} </span>
                    </template></v-checkbox>
</div>
</div>

</template>

<script>
  export default {
    name: "additional-details",
    props: {
      value: Object,
    },
    computed: {
      additionalDetails: {
        get: function() {
          if (this.value.JsonAdditionalFields !== null) {
            let res = [];
            let parsedJsonAdditionalFields = JSON.parse(
              this.value.JsonAdditionalFields
            );
            for (const [key, value] of Object.entries(
                parsedJsonAdditionalFields
              )) {
              res = [
                ...res,
                {
                  [key]: value,
                  checked: value,
                  label: "label"
                },
              ];
            }
            return res;
          } else {
            return [];
          }
        },
      },
    },

    methods: {
      setAdditionalDetails(val) {
        let newObject = { ...this.value
        };
        newObject.JsonAdditionalFields = JSON.parse(
          newObject.JsonAdditionalFields
        );
        newObject.JsonAdditionalFields[Object.keys(val)[0]] = val.checked;
        this.value.JsonAdditionalFields = JSON.stringify(
          newObject.JsonAdditionalFields
        );
      },
    },
    watch: {
      additionalDetails: {
        handler(newVal) {
          console.log("additionalDetails new Value:", newVal);
        },
        deep: true,
      },
    },
  };
</script>

  • Related