Ale
Ale

Reputation: 236

Check only one check box in Vue 3

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>

Example code

Upvotes: 1

Views: 3669

Answers (1)

MinorFourChord
MinorFourChord

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!

Vuetify Radio Buttons

<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

Related Questions