1
votes

I'm trying to add a divider between the list-items of v-autocomplete. I've used the item slot to override the default component, and replaced it with a v-list-item of my own definition. When I add a v-divider to the slot it does not appear. Inspecting with Vue Devtools also shows that Vuetify nests the v-list-items. When I add the v-divider to the list item itself, it's positioned next to the content, instead of between the items. Here's my current code, also available in https://jsfiddle.net/k0vn2zd7/19/

// template

<div id="app">
  <v-app>
    <v-autocomplete v-model="formData.itemId" :items="items" solo clearable prepend-inner-icon="mdi-hammer-screwdriver" type="text" item-value="id">
      <template #item="{ item, on, attrs }">
        <v-list-item two-line v-bind="attrs" v-on="on">
          <v-list-item-avatar class="elevation-1" size="64">
            {{ item.id }}
          </v-list-item-avatar>
          <v-list-item-content>
            <v-list-item-title> {{ item.text }} </v-list-item-title>
            <v-list-item-subtitle> {{ item.id }} </v-list-item-subtitle>
          </v-list-item-content>
        </v-list-item>
        <v-divider inset />
      </template>
    </v-autocomplete>
  </v-app>
</div>

// script

new Vue({
  el: "#app",
  vuetify: new Vuetify(),
  data: {
    items: [
      { text: "Learn JavaScript", id:"1" },
      { text: "Learn Vue", id:"2" },
      { text: "Play around in JSFiddle", id:"3" },
      { text: "Build something awesome", id:"4" }
    ],
    formData: {
        itemId: "",
    }
  },
})

In vuetify's examples, they add pseudo-items in the original array, containing a 'divider' property with v-if/v-else statements that check for the presence of the key 'divider', but my items are fed from an API and I'd rather not pollute the data. I've attempted using a computed property which adds { divider: true } in between each item, but that messes up when filtering the items, as shown in https://jsfiddle.net/k0vn2zd7/31/

// template

<div id="app">
  <v-app>
    <v-autocomplete v-model="formData.itemId" :filter="filterItems" :items="itemsWithDividers" solo clearable prepend-inner-icon="mdi-hammer-screwdriver" type="text" item-value="id">
      <template #item="{ item, on, attrs }">
      <v-divider v-if="item.divider"> </v-divider>
        <v-list-item v-else v-bind="attrs" v-on="on">
          <v-list-item-avatar class="elevation-1" size="64">
            {{ item.id }}
          </v-list-item-avatar>
          <v-list-item-content>
            <v-list-item-title> {{ item.text }} </v-list-item-title>
            <v-list-item-subtitle> {{ item.id }} </v-list-item-subtitle>
          </v-list-item-content>
        </v-list-item>
      </template>
    </v-autocomplete>
  </v-app>
</div>

// script

new Vue({
  el: "#app",
  vuetify: new Vuetify(),
  computed: {
    itemsWithDividers() {
    const itemsWithDividers = [];
      this.items.forEach((x, index, array) => {
        itemsWithDividers.push(x);
        if (index !== array.length - 1) {
          itemsWithDividers.push({
            divider: true,
          });
        }
      });
      return itemsWithDividers;
    },
  },
  data: {
    items: [
      { text: "Learn JavaScript", id:"1" },
      { text: "Learn Vue", id:"2" },
      { text: "Play around in JSFiddle", id:"3" },
      { text: "Build something awesome", id:"4" }
    ],
    formData: {
        itemId: "",
    }
  },
  methods: {
    filterItems(item, queryText, itemText) {
      if (item.divider) return;
      const { text, id } = item;
      const texts = [text, id];
      return texts.some((text) => text.indexOf(queryText) > -1);
    },
  }
})

What would be the recommended way of adding a divider to the v-list inside v-autocomplete, preferably without having to modify the array? Using Vuetify 2.2.12.

1

1 Answers

0
votes

I ended up fixing it by using the divider inside the v-list-item and then using a full width 0 height div to push the divider down in the flexbox of the list-item. Inspired by How to specify line breaks in a multi-line flexbox layout?.

<template #item="{ item, on, attrs }">
        <v-list-item
          two-line
          class="flex-wrap"
          v-bind="attrs"
          v-on="on"
        >
          <v-list-item-avatar
            class="elevation-1"
            color="#eeeeee"
            size="64"
          >
            <img :src="item.preferredImageUrl">
          </v-list-item-avatar>
          <v-list-item-content>
            <v-list-item-title> {{ item.name }} </v-list-item-title>
            <v-list-item-subtitle> {{ item.code }} </v-list-item-subtitle>
          </v-list-item-content>
          <div style="width: 100%; height: 0;" aria-hidden="true" />
          <v-divider
            v-if="items.indexOf(item) !== items.length - 1"
            inset
          />
        </v-list-item>
      </template>