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>