Search code examples
vue.jsfrontendvuetify.jsvee-validatev-autocomplete

How to bind vee-validate field to Vuetify's v-autocomplete without showing [object Object]?


When binding a vee-validate field to a v-autocomplete component, the input displays [object Object] whenever an option is selected. On blurring the input, the correct value is displayed, the issue only occurs when the focus is on the input field.

The v-autocomplete component is configured with return-object, which is necessary in this specific use case because there may be duplicate titles with different ID's, so the ID needs to remain associated with the title at all times.

Is there a modification that can be made here so that the title of the item is rendered correctly while the input is focused?

<script setup>
import { ref } from 'vue';
import { useForm, Form, Field } from 'vee-validate';
import * as yup from 'yup';

const schema = yup.object({
  tags: yup
    .object()
    .shape({
      // make C invalid to demo that validation works as expected
      title: yup.string().oneOf(['A', 'B']),
      value: yup.string().oneOf(['id-a', 'id-b']),
    })
    .required()
    .label('Tag'),
});

const tags = [
  { title: 'A', value: 'id-a' },
  { title: 'B', value: 'id-b' },
  { title: 'C', value: 'id-c' },
];
const tag = ref('');
</script>

<template>
  <Form :validation-schema="schema">
    <Field v-model="tag" name="tags" v-slot="{ field, errors, value }">
      <v-autocomplete
        id="tags"
        :items="tags"
        v-bind="field"
        clearable
        return-object
        :errorMessages="errors"
        placeholder="Select a tag"
      ></v-autocomplete>
    </Field>
  </Form>
</template>

Simple reproduction here: https://stackblitz.com/edit/vee-validate-v4-vuetify-5o9oev?file=src%2FApp.vue

I expect that when selecting a value from the dropdown, the title of that value is displayed in the input box. However this is only true after blurring the input, while it is focused it displays [object Object] instead


Solution

  • The field slot prop contains a value property, which through v-bind ends up on the input. Remove it from the slot props to get rid of the issue:

    <Field v-slot="{field: {value, ...fieldWithoutValue}, errors}" ...>
      <v-autocomplete
        v-bind="fieldWithoutValue"
        ...
    

    The expression {field: {value, ...fieldWithoutValue} destructures value into its own variable and puts all other properties into a new object, accessible through a new variable fieldWithoutValue (you can also call it field again).

    Here is the updated stackblitz