1

Using Vue's v-bind syntax, we can bind a number of checkboxes with different value attributes to the same array, which will then contain the corresponding values of all checked checkboxes. See the example: https://vuejs.org/guide/essentials/forms.html#checkbox

Is it possible to achieve the same with custom components? Let's say I define a component CheckBox.vue as follows:

<script lang="ts" setup>
import { ref } from "vue";

const modelValue = ref(false);

const emit = defineEmits<{ "update:modelValue": [modelValue: boolean] }>();

function handle() {
  modelValue.value = !modelValue.value;

  emit("update:modelValue", modelValue.value);
}
</script>

<template>
  <label>
    <button type="button" @click="handle">
      <span v-if="modelValue">✔️</span>
    </button>
  </label>
</template>

Now I can use v-model to synchronize a variable with the value of my custom checkbox. How can I make it so that I can also use a number of these checkboxes and bind them to an array?

Simply using the component as it is defined in the question in combination with v-bind and an array does the following: The first checkbox will add a single item to the array, which will change between true and false when clicking the checkbox. The other boxes have no effect on the array. Setting the value attribute on the button does not change this behavior.

1 Answer 1

0

Vue SFC Playground

You have to use value property as for <input type="checkbox">:

App.vue

<script setup>
import { ref } from 'vue'
import Checkbox from './Checkbox.vue';

const arr = ref([]);

</script>

<template>

  <checkbox v-model="arr" name="first" />
  <checkbox v-model="arr" name="second" />
  <checkbox v-model="arr" name="third" />
  <div> {{ arr }} </div>
</template>

Checkbox.vue

<script setup>
import { computed } from "vue";

const props = defineProps({name: String, modelValue: [Array, Boolean]});
const emit = defineEmits(['update:modelValue']);

const value = computed({
  get(){
    return props.modelValue?.includes?.(props.name) ?? props.modelValue;
  }, set(val){
    emit('update:modelValue', Array.isArray(props.modelValue) ? 
    props.modelValue.includes(props.name) ?  props.modelValue.filter(item => item !== props.name) : [...props.modelValue, props.name]
    : val);
}});


</script>

<template>
  <label>
    <button type="button" @click.prevent="value = !value">
      <span v-if="value">✔️</span>
      <span v-else>&nbsp;</span>
    </button>
  </label>
</template>

You can though keep Checkbox.vue as simple as handling a boolean value only. For that you use computed to get the same array from an object properties bound to the checkboxes:

Vue SFC Playground

App.vue

<script setup>
import { ref } from 'vue'
import Checkbox from './Checkbox.vue';

const arr = ref([]);

</script>

<template>

  <checkbox v-model="arr" value="first" />
  <checkbox v-model="arr" value="second" />
  <checkbox v-model="arr" value="third" />
  <div> {{ arr }} </div>
</template>

Checkbox.vue could be left the same (handling both arrays and booleans) but could be simplified in this scenario:

<script setup>
import { computed } from "vue";

const props = defineProps({value: String, modelValue: [Array, Boolean]});
const emit = defineEmits(['update:modelValue']);

const value = computed({
  get(){
    return props.modelValue?.includes?.(props.value) ?? props.modelValue;
  }, set(val){
    emit('update:modelValue', Array.isArray(props.modelValue) ? 
    props.modelValue.includes(props.value) ?  props.modelValue.filter(item => item !== props.value) : [...props.modelValue, props.value]
    : val);
}});


</script>

<template>
  <label>
    <button type="button" @click.prevent="value = !value">
      <span v-if="value">✔️</span>
      <span v-else>&nbsp;</span>
    </button>
  </label>
</template>
Sign up to request clarification or add additional context in comments.

2 Comments

That means that there is no built-in way to do this for custom components, and instead I'd have to recreate the functionality like you did?
@Piet, yes, have to, not so complex though, you can make a generic composable to handle Array/Boolean models like in the Checkbox.vue. If this answers your question, please accept my answer (the checkbox)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.