lundi 7 novembre 2022

Vue 3 custom checkbox components bound to array of selected values

I've been trying to create a simple component with a styled checkbox and a corresponding label. The values (strings) of all selected checkboxes should be stored in an array. This works well with plain html checkboxes:


<template>
  <div>
    <div class="mt-6">
      <div>
        <input type="checkbox" value="EVO" v-model="status" /> <label for="EVO">EVO</label>
      </div>
      <div>
        <input type="checkbox" value="Solist" v-model="status" /> <label for="Solist">Solist</label>
      </div>
      <div>
        <input type="checkbox" value="SPL" v-model="status" /> <label for="SPL">SPL</label>
      </div>
    </div>
    <div class="mt-3"></div>
  </div>
</template>

<script setup>
  import { ref } from 'vue'
  
  let status = ref([]);
</script>

It results in the following, desired situation:

Expected result with native checkboxes

Now if I replace those checkboxes with my custom checkbox component, I can't get it to work. If I check a box, it's emitted value seems to replace the status array instead of it being added to or removed from it, resulting in the following:

enter image description here

So all checkboxes are checked by default for some reason, when I click on one of them they all get unchecked and the status value goes to false and clicking any of the checkboxes again will check them all and make status true.

Now I get that returning whether the box is checked or not in the emit returns a true or false value, but I don't get how Vue does this with native checkboxes and how to implement this behaviour with my component.

Here's the code of my checkbox component:

<template>
  <div class="mt-1 relative">
    <input
      type="checkbox"
      :id="id ?? null"
      :name="name"
      :value="value"
      :checked="modelValue ?? false"
      class="bg-gray-200 text-gold-500 rounded border-0 w-5 h-5 mr-2 focus:ring-2 focus:ring-gold-500"
      @input="updateValue"
    />
    
  </div>
</template>

<script setup>
  const props = defineProps({
    id: String,
    label: String,
    name: String,
    value: String,
    errors: Object,
    modelValue: Boolean,
  })
  
  const emit = defineEmits(['update:modelValue'])
  
  const updateValue = function(event) {
    emit('update:modelValue', event.target.checked)
  }
</script>

And the parent component only uses a different template:

<template>
  <div>
    <div class="mt-6">
      <Checkbox v-model="status" value="EVO" label="EVO" name="status"  />
      <Checkbox v-model="status" value="Solist" label="Solist" name="status" />
      <Checkbox v-model="status" value="SPL" label="SPL" name="status" />
    </div>
    <div class="mt-3"></div>
  </div>
</template>

I've tried to look at this answer from StevenSiebert, but it uses an object and I want to replicate the original Vue behaviour with native checkboxes.

I've also referred the official Vue docs on v-model, but can't see why this would work different with native checkboxes than with components.




Aucun commentaire:

Enregistrer un commentaire