vuetify2 v-autocomplete, multiple selection modulable so I can chose multiple or only single items

57 Views Asked by At

I have a v-autocomplete with the multiple props and the possibility to select all or unselect all. It works perfectly. Now i want to have the option to allow the user to only select 1 item at the time, if the user select another item, it unselect the current item and select the new one.

The data used in the items props is comming from the parent component. It's an array of object of users.

<v-autocomplete
            v-model="selected"
            dense
            :search-input.sync="search"
            :items="data || []"
            :label="label"
            :loading="pending"
            item-text="displayName"
            item-value="id"
            multiple
            clearable
            return-object
            @input="search = ''"
          >
            <template #item="utilisateur">
              <template v-if="!utilisateur.item.codeService">
                <v-row no-gutters @click="toggle(utilisateur.item)">
                  <v-icon>
                    {{ $icons[`${icones(utilisateur.item)}`] }}
                  </v-icon>
                  <v-list-item-content v-text="utilisateur.item.displayName" />
                </v-row>
              </template>
              <template v-else>
                {{ utilisateur.item.displayName }}
              </template>
            </template>

            <template #selection="{ item, index }">
              <span v-if="index === 0">{{ item.displayName }}</span>
              <span v-if="index === 1" class="grey--text text-caption">
                (+{{ selected.length - 1 }})
              </span>
            </template>
          </v-autocomplete>

These are the methods that allow me to select all and unselect all.

toggle(item) {
        this.$nextTick(() => {
          if (!item.codeService) {
            this.selected = this.selected.filter(
              (e) => e.displayName !== item.displayName
            )
            if (this.allSelected(item.displayName)) {
              this.removeGroup(item.displayName)
            } else {
              this.addGroup(item.displayName)
            }
          }
        })
      },
      allSelected(name) {
        return (
          this.selected.filter((u) => u.codeService === name).length ===
          this.utilisateurs.filter((u) => u.codeService === name).length
        )
      },
      someSelected(name) {
        return (
          this.selected.filter((u) => u.codeService === name).length > 0 &&
          !this.allSelected(name)
        )
      },
      removeGroup(name) {
        this.selected = this.selected.filter((el) => !(el.codeService === name))
      },
      addGroup(name) {
        const temp = this.selected.filter((el) => !(el.codeService === name))
        this.selected = temp.concat(
          this.utilisateurs.filter((el) => el.codeService === name)
        )
      }

This is what it looks like today, we have 3 items selected: enter image description here

But i don't have a single idea of how to do it.

I tried to edit the multiple props depending of a boolean but it don't return the item. Tried to works with an array of 1 object but same.

Someone has debut of idea ? Thanks !

1

There are 1 best solutions below

0
Moritz Ringler On

An easy approach is throw out the old items when a new one is selected. You can do this easily when using :value and @input instead of the shorthand v-if:

<v-autocomplete
  :value="selected"
  @input="selectedItems => selected = selectedItems.slice(-1)"
  ...
/>

You can easily turn this off with a condition.

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  template: `
    <v-app><v-container>
    <v-autocomplete
      :value="selected"
      @input="selectedItems => selected = selectedItems.slice(-1)"
      placeholder="Select Item"
      :items="items"
      multiple
      clearable
    />
    </v-container></v-app>
  `,
  data() {
    return {
      selected: [],
      items: Array.from({length: 5}, (_,i) => 'Item '+i)
    };
  },
  methods: {
    clearOldItems(){
      if (this.selected.length < 1){
        return
      }
      this.selected = this.selected.slice(-1)
    }
  }
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">

<div id="app"></div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>