Reputation: 236
In Vue 3 I'm trying to keep only one selected checkbox in a checkbox list. Checkbox input is inside the child component, but I need to track/observe changes inside the child component, and if it is selected then update the component tree to keep only one element selected.
Child Component
<template>
<div class="checkbox">
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ name }}</label>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Item",
props: {
name: String,
},
setup() {
const checked = ref(false);
return {
checked,
};
},
};
</script>
Paren component
<template>
<div class="hello">
<item v-for="(item, index) in items" :key="index" :name="item.name"></item>
</div>
</template>
<script>
import Item from "./Item.vue";
export default {
name: "HelloWorld",
components: {
Item,
},
props: {
msg: String,
},
setup() {
return {
items: [
{
name: "Item 1",
},
{
name: "Item 2",
},
{
name: "Item 3",
},
],
};
},
};
</script>
Upvotes: 1
Views: 3669
Reputation: 280
Here is an example with plain Vue, sending props back and forth between parent and child.
I would recommend Vuetify in the future if you're comfortable with a CSS library. Highly recommended!
<template>
<div class="hello">
<item
:passChildSelect="childSelected"
:selectedIndex="ind"
:passedIndex="index"
@pass-the-index="resetIndex"
@child-selected="setChildSelected"
v-for="(item, index) in items"
:key="index"
:name="item.name"
></item>
</div>
</template>
<script>
import Item from "./Item.vue";
export default {
name: "HelloWorld",
components: {
Item,
},
props: {
msg: String,
},
data() {
return {
items: [
{
name: "Item 1",
},
{
name: "Item 2",
},
{
name: "Item 3",
},
],
ind: -1,
childSelected: false,
};
},
methods: {
resetIndex(value) {
this.ind = value;
},
setChildSelected(value) {
this.childSelected = value;
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<template>
<div class="checkbox">
<input
:disabled="this.disable"
type="checkbox"
id="checkbox"
v-model="checked"
/>
<label for="checkbox">{{ name }}</label>
</div>
</template>
<script>
export default {
name: "Item",
props: {
name: String,
passedIndex: Number,
selectedIndex: Number,
passChildSelect: Boolean,
},
data() {
return {
checked: false,
};
},
watch: {
checked: function () {
this.$emit("pass-the-index", this.passedIndex);
this.$emit("child-selected", this.checked);
},
},
computed: {
disable: function () {
if (this.passedIndex === this.selectedIndex) {
return false
} else {
return this.passChildSelect && (this.passedIndex !== this.selectedIndex) ? true : false;
}
}
},
};
</script>
Upvotes: 1