Home > Mobile >  Vuetify Combobox add new item as object instead of string
Vuetify Combobox add new item as object instead of string

Time:02-08

I am building a new/edit item form using Vuetify(v2.6.3). My form has multiple combobox's that pull their items from a backend API as objects. I would like to be able to add new items, which the combobox is able to do. However, when I add a new item it's added as a string. Is there a way to add that new item as an object instead?

I only need the new object to have a name key in order to send it to the API to be created

Desired New item from v-combobox:

{
  name: 'New Item',
}

Simplified list of items returned from API and available as combobox choices:

[
  { 
    id: 1, 
    name: 'Item 1', 
    createdAt: '2020-01-01', 
    updatedAt: '2020-01-01' 
  },
  { 
    id: 2, 
    name: 'Item 2', 
    createdAt: '2020-01-01', 
    updatedAt: '2020-01-01' 
  },
  { 
    id: 3, 
    name: 'Item 3', 
    createdAt: '2020-01-01', 
    updatedAt: '2020-01-01' 
  }
]

Here is a simplified version of my Form:

<template>
  <v-card>
    <v-card-title>
      <span >Edit Item</span>
    </v-card-title>
    <v-card-text>
      <v-container>
        <v-row>
          <v-col>
            <v-combobox
              v-model="item"
              :items="items"
              item-text="name"
              item-value="id"
              label="ComboBox"
              return-object
            ></v-combobox>
          </v-col>
        </v-row>
      </v-container>
    </v-card-text>
  </v-card>
</template>
<script>
export default {
  name: 'TestForm',
  data() {
    return {
      item: null,
      items: [
        {
          id: 1,
          name: 'Item 1',
          createdAt: '2020-01-01',
          updatedAt: '2020-01-01',
        },
        {
          id: 2,
          name: 'Item 2',
          createdAt: '2020-01-01',
          updatedAt: '2020-01-01',
        },
        {
          id: 3,
          name: 'Item 3',
          createdAt: '2020-01-01',
          updatedAt: '2020-01-01',
        },
      ],
    }
  },
}
</script>

In my method which sends the form to the API, I could check the value of each combobox and convert to an object if needed, but I am wondering if it's possible to handle it in the combobox component.

CodePudding user response:

VComboBox doesn't seem to support that, but you could workaround it by using the component's change-event to add a new object with the entry if needed:

  1. Add a change-event handler (e.g., named onChange) on the v-combobox.

  2. In onChange(), lookup the entry in items by name (i.e., corresponding to the VComboBox's item-text prop).

  3. If found, set item to the existing item.

  4. Otherwise, create a new object with that entry, and set item to the newly created object. Note the new object's id (i.e., corresponding to VComboBox's item-value prop) must be unique for VComboBox to create and track it.

<v-combobox
  v-model="item"
  @change="onChange" 1️⃣
/>
let nextId = 1

export default {
  ⋮
  methods: {
    addItem(name) {
      const newItem = {
        id: nextId  ,
        name,
      }
      this.items.push(newItem)
      return newItem
    },
    1️⃣
    onChange(entry) {
      if (typeof entry === 'string' && entry.trim()) {
        2️⃣
        const item = this.items.find(item => item.name === entry)
        if (item) {
          3️⃣
          this.item = item
        } else {
          4️⃣
          this.item = this.addItem(entry)
        }
      }
    },
  },
}

demo

CodePudding user response:

It does not appear that a ComboBox can directly return an object when adding a new item. However it looks like you can leverage the input event of the component to run a method that converts to an object.

Here is how I call the method on the component's input event:

<v-combobox
  v-model="item"
  :items="items"
  item-text="name"
  item-value="id"
  label="ComboBox"
  return-object
  @input="makeObject"
></v-combobox>

@input="makeObject" listens for the component's input event and calls the makeObject method and passes the currently selected item

Then I was able to write a method which checks if the combobox value is a string. If so then it converts it to an object

<script>
export default {
  name: "TestForm",
  data() {
    return {
      item: null
      // Remaining code omitted for readability
    }
  }
  methods: {
    makeObject(val) {
      if (typeof val === "string") {
        this.item = {
          name: val,
        };
      }
    },
  },
};
</script>

Here is my full component:

<template>
  <v-card>
    <v-card-title>
      <span >Edit Item</span>
    </v-card-title>
    <v-card-text>
      <v-container>
        <v-row>
          <v-col>
            <v-combobox
              v-model="item"
              :items="items"
              item-text="name"
              item-value="id"
              label="ComboBox"
              return-object
              @input="makeObject"
            ></v-combobox>
          </v-col>
        </v-row>
      </v-container>
    </v-card-text>
    <v-card-text>
      {{ item }}
    </v-card-text>
  </v-card>
</template>
<script>
export default {
  name: "TestForm",
  data() {
    return {
      item: null,
      items: [
        {
          id: 1,
          name: "Item 1",
          createdAt: "2020-01-01",
          updatedAt: "2020-01-01",
        },
        {
          id: 2,
          name: "Item 2",
          createdAt: "2020-01-01",
          updatedAt: "2020-01-01",
        },
        {
          id: 3,
          name: "Item 3",
          createdAt: "2020-01-01",
          updatedAt: "2020-01-01",
        },
      ],
    };
  },
  methods: {
    makeObject(val) {
      if (typeof val === "string") {
        this.item = {
          name: val,
        };
      }
    },
  },
};
</script>

sandbox link

  •  Tags:  
  • Related