dotmindlabs
dotmindlabs

Reputation: 908

Vuetify autocomplete with solo selection and toggle "Select All"

Vuetify newbie here.

My goal is to have a v-autocomplete with solo selection of elements, and a toggle for "Select All".

My approach was by modifying 'v-select__slot' and to change its contents, is this the best approach?

Question: I was not succesfull cleaning previous selections, what is the best way to clean previous selected elements?

Question: After the "Select All" change event, how to close the drop-down?

     <div id="app">
      <v-app id="inspire">
        <v-container fluid>
          
          <v-autocomplete v-model="selectedFruits" :items="fruits" solo ref="selector" :readonly="readonly" @change="changed">
            
            <template v-slot:prepend-item>
              <v-list-item ripple @click="toggle">
                <v-list-item-action>
                  <v-icon :color="selectedFruits.length > 0 ? 'indigo darken-4' : ''">{{ icon }}</v-icon>
                </v-list-item-action>
                <v-list-item-content>
                  <v-list-item-title>Select All</v-list-item-title>
                </v-list-item-content>
              </v-list-item>
              <v-divider />
            </template>
            
          </v-autocomplete>
        </v-container>
        <br/>
        {{selectedFruits}}
      </v-app>
    </div>
  

   new Vue({
      el: '#app',
      vuetify: new Vuetify(),
      data: () => ({
        fruits: [
          'Apples',
          '...',
          'Zucchini',
        ],
        selectedFruits: [],
        readonly: false,
      }),
    
      computed: {
        likesAllFruit () {
          return this.selectedFruits.length === this.fruits.length
        },
        likesSomeFruit () {
          return this.selectedFruits.length > 0 && !this.likesAllFruit
        },
        icon () {
          if (this.likesAllFruit) return 'mdi-close-box'
          if (this.likesSomeFruit) return 'mdi-checkbox-blank-outline'
          return 'mdi-checkbox-blank-outline'
        },
      },
    
      methods: {
        changed () {
          var el = this.$refs.selector.$el.getElementsByClassName('v-select__slot')[0]
          // var add_me = document.createTextNode(this.selectedFruits);
          // el.appendChild(add_me, null);
        },
        toggle () {
          
          this.$nextTick(() => { 
            
            var backup = this.$refs.selector.$el.getElementsByTagName('input')[0]
            var text = "" 
            
            if (this.likesAllFruit) {
              this.selectedFruits = []
              text = "No fruits"
            } else {
              this.selectedFruits = this.fruits.slice()
              text = "All fruits"
            }
            
            var el = this.$refs.selector.$el.getElementsByClassName('v-select__slot')[0]
            el.textContent = ''
            var add_me = document.createTextNode(text);
            el.appendChild(add_me, null);
            el.appendChild(backup, null);
             
          })
        },
      },
      
      created() {
      }
            
    })

Example:

https://codepen.io/dotmindlabs/pen/JjXbQyo?editors=1010

TIA

Upvotes: 0

Views: 4325

Answers (1)

dotmindlabs
dotmindlabs

Reputation: 908

For displaying the toggle selection used a v-slot:label.

Regarding the closing of the drop-down after clicking toggle, it can be achieved with :menu-props="{closeOnClick: true,closeOnContentClick:true}"

Example HTML:

 <div id="app">
  <v-app id="inspire">
    <v-container fluid>
      <v-autocomplete
        v-model="selectedFruits"
        :items="fruits"  
        :menu-props="{ closeOnClick: true, closeOnContentClick: true }"
      >
      
        <template v-slot:label>
          <div class="indigo--text">{{ label }}</div>
        </template>
        
        <template v-slot:selection="{ item, index }">
           <span>{{ item }}&nbsp;</span>
        </template>
        
        <template v-slot:prepend-item>
          <v-list-item
            ripple
            @click="toggle"
          >
            <v-list-item-action>
              <v-icon :color="selectedFruits.length > 0 ? 'indigo darken-4' : ''">{{ icon }}</v-icon>
            </v-list-item-action>
            <v-list-item-content>
              <v-list-item-title>Select All</v-list-item-title>
            </v-list-item-content>
          </v-list-item>
          <v-divider class="mt-2"></v-divider>
        </template>
          
      </v-autocomplete>
    </v-container>
    {{selectedFruits}}
  </v-app>
</div>

Javascript

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    fruits: [
      'Apples',
      '....',
      'Zucchini',
    ],
    selectedFruits: [],
  }),

  computed: {
    likesAllFruit () {
      return this.selectedFruits.length === this.fruits.length
    },
    icon () {
      if (this.likesAllFruit) return 'mdi-close-box'
      if (this.likesSomeFruit) return 'mdi-minus-box'
      return 'mdi-checkbox-blank-outline'
    },
    label (){
      if (typeof this.selectedFruits === "string") { return ""}
      return this.selectedFruits.length > 0 ? "All Fruit" : ""
    }
  },

  methods: {
    toggle () {
        if (this.likesAllFruit) {
          this.selectedFruits = []
        } else {
          this.selectedFruits = this.fruits.slice()
        }
    },
  },
  created(){
    this.selectedFruits = this.fruits.slice()
  }
})

Codepen: https://codepen.io/dotmindlabs/pen/RwapobY?editors=1011

Upvotes: 1

Related Questions