Forum

Vue.js

Issue with array prop and update:modelValue

Hello,

I am still in the process of refactoring everything to use Composition API, I'm getting there. I am trying to refactor a category checkbox which is responsible for filtering stuff. The problem is that it doesn't not work with an array prop. I found this post on SO, and while it's exactly what I am looking for, none of the examples provided (not tried #3 though surely it should work without having to use a custom handler) work.

https://stackoverflow.com/questions/70101927/why-is-vue-v-model-not-working-for-an-array-prop

const selectedCategories = ref([]);
<Category v-model="selectedCategories" :category="category" />

Category.vue:

script setup

    defineProps({
        modelValue: Array,
        category: Object,
    });

    let emit = defineEmits([
        "update:modelValue",
    ]);

    const updateSelectedCategories = (e) => {
        emit("update:modelValue", e.target.value.slug); // it doesn't matter what type of value I give, I even tried wrapping it inside an array []
    };
<input :id="category.id" :name="category.id" :value="category.slug" class="h-4 w-4 border-black rounded text-black focus:ring-black" type="checkbox" v-on:change="updateSelectedCategories">
Haz
Moderator
0
3
586
Haz
Moderator

Just tried #3 from the SO post, still no dice. I'm clearly doing something wrong, I just don't see it.

I can get it working by doing this, but I don't know, it just doesn't feel "right"?

    const updateSelectedCategories = (e) => {
        emit("update:modelValue", [...props.modelValue, e.target.value]);
    };

Vue dev tools

Haz
Moderator

I guess this is solved, though it would be good to understand why I need to do this, since I didn't have to do this when using the Options API. @alex 👀

0
Haz
Moderator
Solution

Solved, solution at bottom of thread!

OK, this isn't actually solved. Let's try again. Note: I also posted this in the Vue Discord in hopes it can get some attention.

Hey, I am in the process of moving over to the Composition API (getting there), though I have become slgihtly stuck. I have a simple Category component, the component emits data to the parent, the problem is I'm facing weird behaviour that I've not seen seen before (might be related to Composition API?). Hopefully someone can help get me unstuck!

(simplified, no classes, no non-related code)

<script setup>
    defineProps({
        modelValue: Array,
        category: Object,
    });

    let emit = defineEmits([
        "update:modelValue",
    ]);
</script>

<template>
    <div>
        <p v-text="modelValue"></p>

        <label :for="category.id" class="text-sm text-black">
            <input :id="category.id" :name="category.id" :value="category.id" type="checkbox" v-on:change="emit('update:modelValue', $event.target.value)">

            <span class="ml-3">{{ category.name }}</span>
        </label>

        <div v-for="child in category.children" class="ml-4">
            <Category :category="child" />
        </div>
    </div>
</template>

The problem with this is that modelValue doesn't respect that it's an array, checking a checkbox overrides the previous value

Some hacky attempt to resolve it:

v-on:change="emit('update:modelValue', [...modelValue, $event.target.value])"

This works to some extent, but doesn't respect unchecking, I don't want to continue down this rabbit hole where I'm having to continually hack at it by first checking if it exists or not - That's just not right, I need to understand what's exactly going on and how I can implement a fix.

Here's the related snippet for the parent component...

<div v-for="category in categories" :key="category.id">
    <Category v-model="selectedCategories" :category="category" />
</div>

Any help is highly appreciated!

https://i.imgur.com/E3p1XWl.png

https://i.imgur.com/j1tGbPD.png

Solution:

Huge thanks to skirtle who helped me sort it on the Vue Discord.

https://i.imgur.com/dOaComa.png

In case anyone was wondering how the code looks:

    const selectedCategories = computed({
        get() {
            return props.modelValue;
        },

        set(newSelectedCategories) {
            emit("update:modelValue", newSelectedCategories);
        },
    });
  • Remove v-on:change from the input
  • Add v-model to the input v-model="selectedCategories"