Vue Select Multiple Allow Same Option Selection for Vue 3 - vue.js

Is it possible to allow same option selection using Vue Select library? Let's say I have 2 options Canada and United States, then wanted to select that option many times. That would be like:
<v-select multiple v-model="selected" :options="['Canada','United States']" />
Also tried Vue-multiselect library, but it seems that the custom selection template is not working for Vue 3 with version ^3.0.0-alpha.2. This is the repository for Vue 3 compatability. Meanwhile, the code below is for version 2:
<multiselect v-model="value" :options="options" :multiple="true" :close-on-select="false" :clear-on-select="false" :preserve-search="true" placeholder="Pick some" label="name" track-by="name" :preselect-first="true">
<template slot="selection" slot-scope="{ values, search, isOpen }">
<span class="multiselect__single" v-if="values.length && !isOpen">{{ values.length }} options selected</span>
</template>
</multiselect>
How to achieve this behavior?

Related

Vue-multiselect - Vue3 - Slots not working

I'm trying to recreate the following example from Vue-multiselect document in Vue 3 but I can't seem to make it work.
<multiselect
v-model="value"
:options="options"
:multiple="true"
:close-on-select="false"
:clear-on-select="false"
:preserve-search="true"
placeholder="Pick some"
label="name"
track-by="name"
:preselect-first="true">
<template slot="selection" slot-scope="{ values, search, isOpen }">
<span
class="multiselect__single"
v-if="values.length"
v-show="!isOpen">
{{ values.length }} options selected
</span>
</template>
</multiselect>`
The documentation states that "Documentation for v3.0.0 is the same as for v2.x as it is mostly backward compatible." As there's no specific examples or notes about using slots in Vue 3 I thought that if I changed the component name from 'multiselect' to 'VueMultiselect' it would work but it's not.
The select part is working just fine but when I close the dropdown the custom template doesn't show. It's just the normal tags.
Am I missing something or is the feature not fully migrated to Vue 3?
VueMultiselect's documentation concerning named slots is out of date when it comes to Vue 3 syntax. slot and slot-scope attributes were deprecated in Vue 2.6 (but will continue to be supported in Vue 2.x going forward), and have been completely removed in Vue 3. Your slot in Vue 3 should be written like so:
<template v-slot:selection="{ values, search, isOpen }">
or short-hand:
<template #selection="{ values, search, isOpen }">
Documentation with more information: Named Scoped Slots in Vue 3

VueJS Multiselect change default for all selects

Im using the vue-multiselect.js (https://vue-multiselect.js.org/).
Atm I need to translate all text to german. Atm Im doing it with customs inside the multiselect
<multiselect id="account-selected" #input="selectParent" v-model="account.parent_account" placeholder="Tippen um Suche zu starten" :multiple="false" ... :options="optionsParents">
<span slot="noResult">Suche ergab keine Treffer</span>
<span slot="noOptions">Keine Optionen</span>
</multiselect>
Its working fine, but Im using these multiselects frequently. So its a pain to maintain it. I need to change it at every multiselect in every component. Is there a way to define these "noResult", "noOptions", "placeholder" etc globally? So its the same for every multiselect in every component?
You can make your own Multiselect component based on vue-multiselect
Here is the demonstration I make in codesandbox for your reference:
https://codesandbox.io/s/dazzling-yonath-pjsxt?file=/src/components/CustomMultiSelect.vue
The idea is to make a vue component which only have vue-multiselect and set all fixed settings there, like placeholder, slot. For all dynamic value, it can be retrieved by value/event ($attrs, $listeners) pass though provided by vue.
CustomMutliSelect.vue
<template>
<multiselect
v-bind="$attrs"
v-on="$listeners"
placeholder="Tippen um Suche zu
starten"
>
<span slot="noResult">Suche ergab keine Treffer</span>
<span slot="noOptions">Keine Optionen</span>
<!-- Below template for Testing -->
<template slot="singleLabel" slot-scope="{ option }"
><strong>{{ option }}</strong> is written in<strong>
{{ option }}</strong
></template
>
</multiselect>
</template>
App.vue
<CustomMultiSelect
id="account-selected"
v-model="value"
:multiple="false"
:options="options"
/>
With CustomMultSelect, you can apply it everywhere without duplicating placeholder and slots.

v-select validate not working in Internet Explorer 11

Good day, how can i make v-select validate work on IE 11?
i added require('es6-promise').polyfill(); on my vue script but till i encounter error Failed to generate render function.
<v-select :options="books" label="title" v-model="selected">
<template #search="{attributes, events}">
<input
class="vs__search"
:required="!selected"
v-bind="attributes"
v-on="events"
/>
</template>
</v-select>
Solve by accessing the slot directly and binding the required attributes
<v-select :options="books" label="title" v-model="selected">
<template #search="{attributes, events}">
<input :required="!selected" aria-label="Search for option" role="combobox" type="search" autocomplete="off" class="vs__search">
</template>
</v-select>

Vuejs nested slots: how to pass slot to grandchild

I use different vuetify components, for example v-menu. It has a template like this:
<v-menu>
<a slot="activator">menu</a>
<v-list>
<v-list-tile>Menu Entry 1</v-list-tile>
<v-list-tile>Menu Entry 2</v-list-tile>
</v-list>
</v-menu>
Suppose I want to add another wrapper around it. That is my special menu component that has some predefined menu options. And I want it to has an activator slot as well. And the last should be somehow assigned to the original v-menu activator slot. Is it possible?
Example:
// index.vue:
<template>
<my-special-menu>
<button>My special menu trigger</button>
</my-special-menu>
</template>
// MySpecialMenu.vue
<template>
<v-menu>
<slot slot="activator"/> <-- I don't know how to write this line
<v-list>...</v-list>
</v-menu>
</template>
<slot slot="activator"> is an incorrect equation. The goal is to pull the content from the parent (that is <button>..</button> in the example), and use it as slot="activator" in v-menu.
I can write it like this:
<v-menu>
<a slot="activator"><slot/></a>
...
</v-menu>
But this case the result template will be:
<div class="v-menu__activator">
<a>
<button>My special menu trigger</button>
</a>
</div>
That's not exactly what I want. Is it possible to get rid off <a> wrapper here?
Update:
We can use a construction like <template slot="activator"><slot name="activator"/></template> to throw some slot to a grand child. But what if we have multiple slots and we want to proxy them all? That's like inheritAttrs and v-bind="$attrs" for slots. Is it currently possible?
For example, there's <v-autocomplete> component in vuetify that has append, prepend, label, no-data, progress, item, selection etc slots. I write some wrapper component around this, it currently looks like:
<template>
<v-autocomplete ..>
<template slot="append"><slot name="append"/></template>
<template slot="prepend"><slot name="prepend"/></template>
<template slot="label"><slot name="label"/></template>
...
<template slot="item" slot-scope="props"><slot name="item" v-bind="props"/></template>
</v-autocomplete>
</template>
Is it possible to avoid all slots enumeration here?
If you put the slot attribute on a html element, that html element is passed to the child component to fill the slot with that name. If you don't want to pass along a html element, you can use slot on a template tag within your component. A template tag groups elements, but does not render to a html element, which is perfect here. You can use template tags also for other things, such as to group elements in a v-if for example, or to repeat multiple elements with a v-for.
// App.vue
<template>
<div id="app">
<test>
<template slot="activator">
Click <b>me</b>!
</template>
</test>
</div>
</template>
// Test.vue
<template>
<div class="wrapper">
<grand-child>
<template slot="activator">
<slot name="activator"></slot>
</template>
</grand-child>
This is some text
</div>
</template>
// GrandChild.vue
<template>
<div>
<a href="#" #click="toggle = !toggle">
<slot name="activator">Default</slot>
</a>
<div v-if="toggle">This appears and disappears</div>
</div>
</template>
Edit: If you want to do this for arbitrary slots, this is also possible. this.$slots contains the slots and their content, so with something like the following, you can pass the slot content to a slot with the same name:
<grand-child>
<template v-for="(_, slot) in $slots">
<template :slot="slot">
<slot :name="slot"></slot>
</template>
</template>
</grand-child>
For completeness sake, scoped slots can be accessed through $scopedSlots and be propagated like so:
<grand-child>
<template v-for="(_, slot) in $scopedSlots" v-slot:[slot]="props">
<slot :name="slot" v-bind="props" />
</template>
</grand-child>
source and comment
I had EsLint errors because of the depreciated :slot and $scopedSlots attributes.
So I combined both of #Sumurai8 answers like this and it works great:
<template v-for="(_, slot) in $slots" v-slot:[slot]>
<slot :name="slot"></slot>
</template>
If you have both named and unnamed slots with props:
Vue 3
<template v-for="(_, name) in $slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}" />
</template>
Typescript version
<template v-for="(_, name) in ($slots as {})" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}" />
</template>

Vue js multiselect hide triangle with empty

I'm using the vue-multiselect library. How can I hide this triangle if the data is empty?
<multiselect v-model="user.majors" id="majorsSearch" label="name" track-by="id" placeholder="Search majors..." select-label="Select" :options="majorsBag" :multiple="true" :loading="isLoadingMajors" :internal-search="false" :clear-on-select="true" :close-on-select="true" #search-change="asyncFindMajors">
<template slot="tag" scope="props"></template>
</multiselect>
You can replace the default dropdown button by providing the caret slot; in your situation you can use an empty <span>, try something like this:
<multiselect v-model="user.majors">
<span slot="caret" v-if="!user.majors.length"></span>
</multiselect>