vue.jsvuejs3

how to make v-model optional in my component (keep reactivity of default value)


I have a custom component which uses the VDataTable from Vuetify inside, although it's not the root DOM object. I want to expose the v-model (row selection) functionality of VDataTable as my own v-model:selected. Looking on the internet, I found the only solution to create a computed value with a setter like this:

const selected = computed({
    get() { return props.selected }
    set(value) { emit('update:selected', value) }
});

And then pass it into the VDataTable's v-model. And this works, as long as my component has the v-model set. But if I do not pass it, the reactivity is broken and things stop working (item selection works, but selecting all doesn't etc).

However, the original VDataTable works like that correctly even if it is not given any v-model. How is it done? I tried looking at their source code but couldn't understand it. I have tried extracting the selected prop using toRef(props, 'selected') but it didn't help, as well as setting the default prop value to ref([])

Minimalistic reproduction


Solution

  • I don't know how it works internally either but the "select all" checkbox must expect a way to set the v-model if v-model is provided. For the case where you don't provide a v-model your setter function does not set any value, which must be causing the problem.

    Try this work-around of using a local variable in the case where the prop is null:

    const props = defineProps({
      selected: {
        type: Array,
        default: () => null, // null by default
      },
    })
    
    
    const defaultSelected = ref([])
    const selected = computed({
      get() {
        return props.selected ?? defaultSelected.value
      },
      set(val) {
        if (props.selected) {
          emit('update:selected', val)
        } else {
          defaultSelected.value = val
        }
      },
    })
    

    updated Vuetify Playground