mirror of
https://github.com/tenrok/vue-select.git
synced 2026-05-17 02:29:37 +03:00
feat: scope the no-options slot (#1083)
Resolves #1071, Resolves #1081 https://vue-select.org/guide/slots.html#improving-the-default-no-options-text
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template v-slot:no-options="{ search, searching }">
|
||||
<template v-if="searching">
|
||||
No results found for <em>{{ search }}</em>.
|
||||
</template>
|
||||
<em style="opacity: 0.5;" v-else>Start typing to search for a country.</em>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BetterNoOptions',
|
||||
};
|
||||
</script>
|
||||
+69
-22
@@ -7,13 +7,16 @@ Slots can be used to change the look and feel of the UI, or to simply swap out t
|
||||
|
||||
### `selected-option`
|
||||
|
||||
#### Scope:
|
||||
#### Scope:
|
||||
|
||||
- `option {Object}` - A selected option
|
||||
|
||||
```html
|
||||
<slot name="selected-option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
<slot
|
||||
name="selected-option"
|
||||
v-bind="(typeof option === 'object')?option:{[label]: option}"
|
||||
>
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
```
|
||||
|
||||
@@ -27,16 +30,32 @@ Slots can be used to change the look and feel of the UI, or to simply swap out t
|
||||
- `multiple {Boolean}` - If the component supports the selection of multiple values
|
||||
|
||||
```html
|
||||
<slot v-for="option in valueAsArray" name="selected-option-container"
|
||||
:option="(typeof option === 'object')?option:{[label]: option}" :deselect="deselect" :multiple="multiple" :disabled="disabled">
|
||||
<span class="selected-tag" v-bind:key="option.index">
|
||||
<slot name="selected-option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
<button v-if="multiple" :disabled="disabled" @click="deselect(option)" type="button" class="close" aria-label="Remove option">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</span>
|
||||
<slot
|
||||
v-for="option in valueAsArray"
|
||||
name="selected-option-container"
|
||||
:option="(typeof option === 'object')?option:{[label]: option}"
|
||||
:deselect="deselect"
|
||||
:multiple="multiple"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<span class="selected-tag" v-bind:key="option.index">
|
||||
<slot
|
||||
name="selected-option"
|
||||
v-bind="(typeof option === 'object')?option:{[label]: option}"
|
||||
>
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
<button
|
||||
v-if="multiple"
|
||||
:disabled="disabled"
|
||||
@click="deselect(option)"
|
||||
type="button"
|
||||
class="close"
|
||||
aria-label="Remove option"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</span>
|
||||
</slot>
|
||||
```
|
||||
|
||||
@@ -44,28 +63,56 @@ Slots can be used to change the look and feel of the UI, or to simply swap out t
|
||||
|
||||
### `spinner`
|
||||
|
||||
#### Scope:
|
||||
|
||||
- `loading {Boolean}` - if the component is in a loading state
|
||||
|
||||
```html
|
||||
<slot name="spinner">
|
||||
<div class="spinner" v-show="mutableLoading">Loading...</div>
|
||||
<slot name="spinner" v-bind="scope.spinner">
|
||||
<div class="vs__spinner" v-show="mutableLoading">Loading...</div>
|
||||
</slot>
|
||||
```
|
||||
|
||||
### `no-options`
|
||||
### `open-indicator`
|
||||
|
||||
```html
|
||||
<slot name="no-options">Sorry, no matching options.</slot>
|
||||
```js
|
||||
attributes : {
|
||||
'ref': 'openIndicator',
|
||||
'role': 'presentation',
|
||||
'class': 'vs__open-indicator',
|
||||
}
|
||||
```
|
||||
|
||||
```vue
|
||||
<slot name="open-indicator" v-bind="scope.openIndicator">
|
||||
<component :is="childComponents.OpenIndicator" v-if="!noDrop" v-bind="scope.openIndicator.attributes"/>
|
||||
</slot>
|
||||
```
|
||||
|
||||
## Dropdown
|
||||
|
||||
### `option`
|
||||
|
||||
#### Scope:
|
||||
|
||||
- `option {Object}` - The currently iterated option from `filteredOptions`
|
||||
|
||||
```html
|
||||
<slot name="option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
<slot
|
||||
name="option"
|
||||
v-bind="(typeof option === 'object')?option:{[label]: option}"
|
||||
>
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
```
|
||||
|
||||
### `no-options`
|
||||
|
||||
The no options slot is displayed in the dropdown when `filteredOptions.length === 0`.
|
||||
|
||||
- `search {String}` - the current search text
|
||||
- `searching {Boolean}` - if the component has search text
|
||||
|
||||
```vue
|
||||
<slot name="no-options" v-bind="scope.noOptions">
|
||||
Sorry, no matching options.
|
||||
</slot>
|
||||
```
|
||||
|
||||
+18
-8
@@ -1,22 +1,32 @@
|
||||
::: tip 🚧
|
||||
This section of the guide is a work in progress! Check back soon for an update.
|
||||
Vue Select currently offers quite a few scoped slots, and you can check out the
|
||||
Vue Select currently offers quite a few scoped slots, and you can check out the
|
||||
[API Docs for Slots](../api/slots.md) in the meantime while a good guide is put together.
|
||||
:::
|
||||
|
||||
#### Scoped Slot `option`
|
||||
### Scoped Slot `option`
|
||||
|
||||
vue-select provides the scoped `option` slot in order to create custom dropdown templates.
|
||||
|
||||
```html
|
||||
<v-select :options="options" label="title">
|
||||
<template v-slot:option="option">
|
||||
<span :class="option.icon"></span>
|
||||
{{ option.title }}
|
||||
</template>
|
||||
</v-select>
|
||||
```
|
||||
<template v-slot:option="option">
|
||||
<span :class="option.icon"></span>
|
||||
{{ option.title }}
|
||||
</template>
|
||||
</v-select>
|
||||
```
|
||||
|
||||
Using the `option` slot with props `"option"` provides the current option variable to the template.
|
||||
|
||||
<CodePen url="NXBwYG" height="500"/>
|
||||
|
||||
### Improving the default `no-options` text
|
||||
|
||||
The `no-options` slot is displayed in the dropdown when `filteredOptions === 0`. By default, it
|
||||
displays _Sorry, no matching options_. You can add more contextual information by using the slot
|
||||
in your own apps.
|
||||
|
||||
<BetterNoOptions />
|
||||
|
||||
<<< @/.vuepress/components/BetterNoOptions.vue
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
</li>
|
||||
<li v-if="!filteredOptions.length" class="vs__no-options" @mousedown.stop="">
|
||||
<slot name="no-options">Sorry, no matching options.</slot>
|
||||
<li v-if="filteredOptions.length === 0" class="vs__no-options" @mousedown.stop="">
|
||||
<slot name="no-options" v-bind="scope.noOptions">Sorry, no matching options.</slot>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
@@ -1013,6 +1013,10 @@
|
||||
spinner: {
|
||||
loading: this.mutableLoading
|
||||
},
|
||||
noOptions: {
|
||||
search: this.search,
|
||||
searching: this.searching,
|
||||
},
|
||||
openIndicator: {
|
||||
attributes: {
|
||||
'ref': 'openIndicator',
|
||||
|
||||
@@ -56,4 +56,20 @@ describe('Scoped Slots', () => {
|
||||
|
||||
expect(Select.find({ref: 'dropdownMenu'}).text()).toEqual('onetwothree');
|
||||
});
|
||||
|
||||
it('noOptions slot receives the current search text', async () => {
|
||||
const noOptions = jest.fn();
|
||||
const Select = mountDefault({}, {
|
||||
scopedSlots: {'no-options': noOptions},
|
||||
});
|
||||
|
||||
Select.vm.search = 'something not there';
|
||||
Select.vm.open = true;
|
||||
await Select.vm.$nextTick();
|
||||
|
||||
expect(noOptions).toHaveBeenCalledWith({
|
||||
search: 'something not there',
|
||||
searching: true,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user