Vue-multiselect - Vue3 - Slots not working - vuejs2

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

Related

How to remove slot-scope in vue2.7

I upgraded my vue application to vue2.7 and I want to remove slot-scope from my application as it is removed in vue3. So in the examples, I see this for vue2:
<ItemList>
<template slot="heading" slot-scope="slotProps">
<h1>My Heading for {{ slotProps.items.length }} items</h1>
</template>
</ItemList>
In Vue 3 it is changed to this:
<ItemList>
<template v-slot:heading="slotProps">
<h1>My Heading for {{ slotProps.items.length }} items</h1>
</template>
</ItemList>
So in my application slot-scope is used in default:
<template slot-scope="scope">
...
</template>
So how can I remove slot-scope from my application and also for vue2.7, will it be supported?
slot-scope was deprecated in Vue2 and will never return back (even in Vue3), the syntax has just changed.
So rather than writing this: slot-scope="slotProps" you need to have the following #default="slotProps".
All the details are available here: https://v2.vuejs.org/v2/guide/components-slots.html#Scoped-Slots-with-the-slot-scope-Attribute
# being a shorthand for v-slot as explained here: https://v2.vuejs.org/v2/guide/components-slots.html#Named-Slots-Shorthand

Vue Select Multiple Allow Same Option Selection for Vue 3

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?

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.

Passing slots through from Parent to Child Components

I have built a user-defined component (async-select) on top of another component (vue mutliselect) like this:
https://jsfiddle.net/2x7n4rL6/4/
Since the original vue-multiselect component offers a couple of slots, I don't want to loose the chance to use them. So my goal is to make these slots available from inside my custom component. In other words, I want to something like this:
https://jsfiddle.net/2x7n4rL6/3/
But that code oes not work.
However, if I add the slot to the child component itself, it works just fine (which you can see from the fact that options become red-colored).
https://jsfiddle.net/2x7n4rL6/1/
After surfing the web, I have come across this article, but it does not seem to work
Is there any way in VueJS to accomplish this ?
Slots can be confusing!
First, you need a template element to define the slot content:
<async-select :value="value" :options="options">
<template v-slot:option-tmpl="{ props }">
<div class="ui grid">
<div style="color: red">{{ props.option.name }}</div>
</div>
</template>
</async-select>
Then, in the parent component, you need a slot element. That slot element itself can be inside of another template element, so its contents can be put in a slot of its own parent.
<multiselect
label="name"
ref="multiselect"
v-model="localValue"
placeholder="My component"
:options="options"
:multiple="false"
:taggable="false">
<template slot="option" slot-scope="props">
<slot name="option-tmpl" :props="props"></slot>
</template>
</multiselect>
Working Fiddle: https://jsfiddle.net/thebluenile/ph0s1jda/

How to make a component use v-for have dynamic slots

I have a child component that uses v-for. I want to be able to have the parent pass down a slot, or something similar of how it wants each item in the v-for display. However, the problem is that the parent does not have access to each individual item in the v-for as it's rendered.
Some things i've tried is passing a slot with specific keys. e.g.
<child-comp :items="items">
<div v-text="item.text" slot="body"/>
</child-comp>
Basic code may look like this for what i'm trying (though it doesn't work)
Parent component would look something like
<template>
<child-comp :items="items>
<div v-text="item.text"
</child-comp>
</template>
items = [{ text: 'hello'}]
Child would look something like this
<template>
<div>
<span v-for="item in items">
<slot></slot>
</span>
</div>
</template>
Note this has to be dynamic because one item might do v-text, another may do something like add more html such as an image, and another may do something completely different.
I believe you're looking for scoped slots.
https://v2.vuejs.org/v2/guide/components-slots.html#Scoped-Slots
Note that the preferred syntax for using scoped slots changed in Vue 2.6.0 so the exact way you write this will depend on which version you're using.
Your child would pass the item to the slot, like this:
<template>
<div>
<span v-for="item in items">
<slot :item="item"></slot>
</span>
</div>
</template>
The parent would look like this for Vue 2.6.0+:
<template>
<child-comp :items="items">
<template v-slot:default="slotProps">
<!-- The parent can put whatever it needs here -->
{{ slotProps.item }}
</template>
</template>
</child-comp>
</template>
Any props passed to the slot by the child will be included in the slotProps. There's no need to call it slotProps and in practice it is usually destructured (see the docs for more details).
For Vue 2.5 you'd use slot-scope instead:
<template>
<child-comp :items="items">
<template slot-scope="slotProps">
<!-- The parent can put whatever it needs here -->
{{ slotProps.item }}
</template>
</template>
</child-comp>
</template>
Prior to Vue 2.5.0 slot-scope was called scope.