2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-16 09:10:33 +03:00

nuxt setup, tailwind

This commit is contained in:
Jeff Sagal
2021-07-28 09:46:15 -07:00
parent 335920b586
commit 3399ecbd9a
86 changed files with 5656 additions and 4359 deletions
+64
View File
@@ -0,0 +1,64 @@
Vue Select aims to follow the WAI-ARIA best practices for the
[combobox](https://www.w3.org/TR/wai-aria-practices-1.1/#combobox) and
[listbox](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox) widgets.
The UX of the component is designed around the HTML `<select>` element, while following the WAI-ARIA
specifications and best practices for creating accessible components.
## Combobox
- [WAI-ARIA Combobox - Best Practices](https://www.w3.org/TR/wai-aria-practices-1.1/#combobox)
- [WAI-ARIA Combobox - Specification](https://www.w3.org/TR/wai-aria-1.1/#combobox)
## Listbox
- [WAI-ARIA Listbox - Best Practices](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox)
### Autocomplete
WAI-ARIA suggests four forms of autocomplete for Comboboxes. Vue Select can be configured to provide
these use cases.
1. **No autocomplete**
> When the popup is triggered, the suggested values it contains are the same regardless of the
characters typed in the textbox.
```html
<v-select :filterable="false" :options="['No Autocomplete', 'List Autocomplete']" />
```
<v-select :filterable="false" :options="['No Autocomplete', 'List Autocomplete']" />
2. **List autocomplete with manual selection**
> When the popup is triggered, it presents suggested values that complete or logically
correspond to the characters typed in the textbox. The character string the user has
typed will become the value of the textbox unless the user selects a value in the popup.
```html
<v-select taggable :options="['No Autocomplete', 'List Autocomplete']" />
```
<v-select taggable :options="['No Autocomplete', 'List Autocomplete']" />
3. **List autocomplete with automatic selection**
> When the popup is triggered, it presents suggested values that complete or logically
correspond to the characters typed in the textbox, and the first suggestion is automatically
highlighted as selected. The automatically selected suggestion becomes the value of the textbox
when the combobox loses focus unless the user chooses a different suggestion or changes the
character string in the textbox.
```html
<v-select :options="['No Autocomplete', 'List Autocomplete']" />
```
<v-select :options="['No Autocomplete', 'List Autocomplete']" />
4. **List with inline autocomplete**
> This is the same as list with automatic selection with one additional feature. The portion of
the selected suggestion that has not been typed by the user, a completion string, appears inline
after the input cursor in the textbox. The inline completion string is visually highlighted and
has a selected state.
🚧 Vue Select does not yet support this configuration, but it is on the roadmap
[#865](https://github.com/sagalbot/vue-select/issues/865). 🚧
+72
View File
@@ -0,0 +1,72 @@
## Loading Options with AJAX
The `search` event provides a hook to load options from a parent component
when the search text is updated. It is emitted with two parameters:
**Search Event Parameters**
- `search {String}` The current search string
- `loading {Function}` Accepts a boolean parameter to toggle the loading state
```html
<v-select @search="fetchOptions" />
```
```js
/**
* Triggered when the search text changes.
*
* @param search {String} Current search text
* @param loading {Function} Toggle loading class
*/
fetchOptions (search, loading) {
// ... do some asynchronous stuff!
},
```
The `loading` function accepts a boolean parameter that will be assigned
to the vue-select internal `loading` property. Call `loading(true)` to set the
`loading` property to `true` - toggling the loading spinner. After your
asynchronous operation completes, call `loading(false)` to toggle it off.
## Disabling Filtering
When loading server side options, it can be useful to disable the
client side filtering. Use the `filterable` prop to disable filtering.
```js
/**
* When true, existing options will be filtered
* by the search text. Should not be used in
* conjunction with taggable.
*
* @type {Boolean}
*/
filterable: {
type: Boolean,
default: true
},
```
## Loading Spinner
Vue Select includes a default loading spinner that appears when the loading class is present. The
`spinner` slot allows you to implement your own spinner.
```html
<div class="spinner" v-show="spinner">Loading...</div>
```
## Library Agnostic
Since Vue.js does not ship with ajax functionality as part of the core library, it's up to you to
process the ajax requests in your parent component.
I recommend using [axios](https://github.com/axios/axios) for creating your applications HTTP layer,
or [`fetch()`](https://github.com/github/fetch) for simple requests.
## Example
The [codepen example](https://codepen.io/sagalbot/pen/POMeOX) wraps up all the above concepts and
searches GitHub repositories. It also uses scoped slots to add some custom templating.
<CodePen url="POMeOX" height="400"/>
+83
View File
@@ -0,0 +1,83 @@
### Prop: `components` `{Object}`
---
Vue Select utilizes child components throughout, and exposes an API to overwrite these components
with your own, using the `components` `{Object}` prop. The object provided to the `components` prop
will be merged with Vue Select's default components.
<<< @/../src/components/childComponents.js{4-7}
You can override the value of any of these keys with your own components.
## Deselect <Badge text="v3.1.0+" />
You may wish to roll your own deselect button. `Deselect` is used within tags on
`multiple` selects, and serves as the clear button for single selects. Maybe you just want to use
a simple `<button>Clear</button>` instead.
```html
<v-select :components="{Deselect}" />
```
```js
export default {
data: () => ({
Deselect: {
render: createElement => createElement('span', '❌'),
},
}),
};
```
<ClearButtonOverride />
The same approach applies for `multiple` selects:
<MultipleClearButtonOverride />
## OpenIndicator <Badge text="v3.1.0+" />
The `OpenIndicator` component is the 'caret' used within the component that adjusts orientation
based on whether the dropdown is open or closed.
```html
<v-select :components="{OpenIndicator}" />
```
```js
export default {
data: () => ({
selected: ['Canada'],
OpenIndicator: {
render: createElement => createElement('span', {class: {'toggle': true}}),
},
}),
};
```
<OpenIndicatorOverride />
## Setting Globally at Registration
If you want all instances of Vue Select to use your custom components throughout your app, while
only having to set the implementation once, you can do so when registering Vue Select as a component.
```js
import Vue from 'vue';
import vSelect from 'vue-select';
// Set the components prop default to return our fresh components
vSelect.props.components.default = () => ({
Deselect: {
render: createElement => createElement('span', '❌'),
},
OpenIndicator: {
render: createElement => createElement('span', '🔽'),
},
});
// Register the component
Vue.component(vSelect)
```
<CustomComponentRegistration />
+58
View File
@@ -0,0 +1,58 @@
Vue Select offers many APIs for customizing the look and feel from the component. You can use
[scoped slots](../api/slots.md), [custom child components](components.md), or modify the built in
SCSS variables.
::: tip
Support for CSS variables (custom properties) is currently on the road map for those
that are not using sass in their projects.
:::
## SCSS Variables
Variables are leveraged in as much of the component styles as possible. If you really want to dig
into the SCSS, the files are located in `src/scss`. The variables listed below can be found at
[`src/scss/global/_variables`](https://github.com/sagalbot/vue-select/blob/master/src/scss/global/_variables.scss).
All variables are implemented with `!default` in order to make them easier to override in your
application.
<<< @/../src/scss/global/_variables.scss
## Overriding Default Styles
Vue Select takes the approach of using selectors with a single level of specificity, while using
classes that are very specific to Vue Select to avoid collisions with your app.
All classes within Vue Select use the `vs__` prefix, and selectors are generally a single classname
unless there is a state being applied to the component.
In order to override a default property in your app, you should add one level of specificity.
The easiest way to do this, is to add `.v-select` before the `vs__*` selector if you want to adjust
all instances of Vue Select, or add your own classname if you just want to affect one.
<CssSpecificity />
<<< @/.vuepress/components/CssSpecificity.vue
## Dropdown Transition
By default, the dropdown transitions with a `.15s` cubic-bezier opacity fade in/out. The component
uses the [VueJS transition system](https://vuejs.org/v2/guide/transitions.html). By default, the
transition name is `vs__fade`. There's a couple ways to override or change this transition.
1. Use the `transition` prop. Applying this prop will change the name of the animation classes and
negate the default CSS. If you want to remove it entirely, you can set it to an empty string.
```html
<v-select transition="" />
```
2. You can also override the default CSS for the `vs__fade` transition. Again, if you
wanted to eliminate the transition entirely:
```css
.vs__fade-enter-active,
.vs__fade-leave-active {
transition: none;
}
```
+4
View File
@@ -0,0 +1,4 @@
### Codepen Collection
I've put together a collection of examples, including all the examples
from this documentation site on [Codepen](https://codepen.io/collection/nrkgxV/#).
+19
View File
@@ -0,0 +1,19 @@
Vue Select provides two props accepting `functions` that can be used to implement custom filtering
algorithms.
- `filter` <Badge text="v2.5.0+" />
- `filterBy` <Badge text="v2.5.0+" />
By default, the component will perform a very basic check to see if an options label includes
the current search text. If you're using scoped slots, you might have information within the
option templates that should be searchable. Or maybe you just want a better search algorithm that
can do fuzzy search matching.
## Filtering with Fuse.js
You can use the `filter` and `filterBy` props to hook right into something like
[Fuse.js](https://fusejs.io/) that can handle searching multiple object keys with fuzzy matchings.
<FuseFilter />
<<< @/.vuepress/components/FuseFilter.vue
+23
View File
@@ -0,0 +1,23 @@
Vue Select doesn't ship with first party support for infinite scroll, but it's possible to implement
by hooking into the `open`, `close`, and `search` events, along with the `filterable` prop, and the
`list-footer` slot.
Let's break down the example below, starting with the `data`.
- `observer` - a new `IntersectionObserver` with `infiniteScroll` set as the callback
- `limit` - the number of options to display
- `search` - since we've disabled Vue Selects filtering, we'll need to filter options ourselves
When Vue Select opens, the `open` event is emitted and `onOpen` will be called. We wait for
`$nextTick()` so that the `$ref` we need will exist, then begin observing it for intersection.
The observer is set to call `infiniteScroll` when the `<li>` is completely visible within the list.
Some fancy destructuring is done here to get the first `ObservedEntry`, and specifically the
`isIntersecting` & `target` properties. If the `<li>` is intersecting, we increase the `limit`, and
ensure that the scroll position remains where it was before the list size changed. Again, it's
important to wait for `$nextTick` here so that the DOM elements have been inserted before setting
the scroll position.
<InfiniteScroll />
<<< @/.vuepress/components/InfiniteScroll.vue
+60
View File
@@ -0,0 +1,60 @@
## Yarn / NPM
Install with yarn:
```bash
yarn add vue-select
# or, using NPM
npm install vue-select
```
Then, import and register the component:
```js
import Vue from 'vue'
import vSelect from 'vue-select'
Vue.component('v-select', vSelect)
```
The component itself does not include any CSS. You'll need to include it separately:
```js
import 'vue-select/dist/vue-select.css';
```
Alternatively, you can import the scss for complete control of the component styles:
```scss
@import "vue-select/src/scss/vue-select.scss";
```
## In the Browser
vue-select ships as an UMD module that is accessible in the browser. When loaded
in the browser, you can access the component through the `VueSelect.VueSelect`
global variable. You'll need to load Vue.js, vue-select JS & vue-select CSS.
```html
<!-- include VueJS first -->
<script src="https://unpkg.com/vue@latest"></script>
<!-- use the latest vue-select release -->
<script src="https://unpkg.com/vue-select@latest"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-select@latest/dist/vue-select.css">
<!-- or point to a specific vue-select release -->
<script src="https://unpkg.com/vue-select@3.0.0"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-select@3.0.0/dist/vue-select.css">
```
Then register the component in your javascript:
```js
Vue.component('v-select', VueSelect.VueSelect);
```
<CodePen url="dJjzeP" />
## Vue Compatibility
- If you're on Vue `1.x`, use vue-select `1.x`.
- The `1.x` branch has not received updates since the 2.0 release.
+73
View File
@@ -0,0 +1,73 @@
### Customizing Keydown Behaviour
---
## selectOnKeyCodes <Badge text="v3.3.0+" />
`selectOnKeyCodes {Array}` is an array of keyCodes that will trigger a typeAheadSelect. Any keyCodes
in this array will prevent the default event action and trigger a typeahead select. By default,
it's just `[13]` for return. For example, maybe you want to tag on a comma keystroke:
<TagOnComma />
<<< @/.vuepress/components/TagOnComma.vue
## mapKeyDown <Badge text="v3.3.0+" />
Vue Select provides the `map-keydown` Function prop to allow for customizing the components response to
keydown events while the search input has focus.
```js
/**
* @param map {Object} Mapped keyCode to handlers { <keyCode>:<callback> }
* @param vm {VueSelect}
* @return {Object}
*/
(map, vm) => map,
```
By default, the prop is a noop returning the same object `map` object it receives. This object
maps keyCodes to handlers: `{ <keyCode>: <callback> }`. Modifying this object can override default
functionality, or add handlers for different keys that the component doesn't normally listen for.
Note that any keyCodes you've added to `selectOnKeyCodes` will be passed to `map-keydown` as well,
so `map-keydown` will always take precedence.
**Default Handlers**
```js
// delete
8: e => this.maybeDeleteValue()
// tab
9: e => this.onTab()
// enter
13: e => {
e.preventDefault();
return this.typeAheadSelect();
}
// esc
27: e => this.onEscape()
// up
38: e => {
e.preventDefault();
return this.typeAheadUp();
}
// down
40: e => {
e.preventDefault();
return this.typeAheadDown();
}
```
### Example: Autocomplete Email Addresses
This is example listens for the `@` key, and autocompletes an email address with `@gmail.com`.
<CustomHandlers />
<<< @/.vuepress/components/CustomHandlers.vue
+45
View File
@@ -0,0 +1,45 @@
## Right to Left
Vue Select supports RTL using the standard HTML API using the `dir` prop.
```html
<v-select dir="rtl"></v-select>
```
The `dir` prop accepts the same values as the [HTML spec](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir):
- `rtl`
- `ltr`
- `auto`
## Component Text
All of the text within the component has been wrapped within [slots](https://vuejs.org/v2/guide/components.html#Content-Distribution-with-Slots) and can be replaced in your app.
### Loading Spinner
*Slot Definition:*
```html
<slot name="spinner">
<div class="spinner" v-show="mutableLoading">Loading...</div>
</slot>
```
*Implementation:*
```html
<v-select>
<i slot="spinner" class="icon icon-spinner"></i>
</v-select>
```
### No Options Text
*Slot Definition:*
```html
<slot name="no-options">Sorry, no matching options.</slot>
```
*Implementation:*
```html
<v-select>
<div slot="no-options">No Options Here!</div>
</v-select>
```
For a full list of component slots, view the [slots API docs](../api/slots.md).
+17
View File
@@ -0,0 +1,17 @@
### Using Vue Select in v-for Loops
---
There may be times that you are including Vue Select within loops of data, such as a table. This can
pose some challenges when emitting events from the component, as you won't know which Vue Select
instance emitted it. This can make it difficult to wire up with things like Vuex.
Fortunately, you can solve this problem with an anonymous function. The example below doesn't use
Vuex just to keep things succinct, but the same solution would apply. The `@input` is handled
with an inline anonymous function, allowing the selected country to be passed to the `updateCountry`
method with the `country` and the `person` object.
<LoopedSelect />
<<< @/.vuepress/components/LoopedSelect.vue
View File
+54
View File
@@ -0,0 +1,54 @@
## Options Prop
`vue-select` accepts arrays of primitive values or objects to use as options through the `options` prop:
```html
<!-- array of strings or numbers -->
<v-select :options="['Canada', 'United States']"></v-select>
```
<v-select :options="['Canada', 'United States']"></v-select>
```html
<!-- or, an array of objects -->
<v-select :options="[{label: 'Canada', code: 'ca'}]"></v-select>
```
<v-select :options="[{label: 'Canada', code: 'ca'}]"></v-select>
## Option Labels
#### Options as Primitives (strings, numbers, boolean)
When `options` contains strings or numbers, they'll be used as the label for the option within the
component. No further configuration is necessary.
#### Options as Objects
When `options` is an array of objects, the component must generate a label to be shown as the
options text. By default, `vue-select` will attempt to render `option.label` as the option label.
You might not have a `label` key in your objects, so you can set your own label to match your
source data using the `label {String}` prop.
For example, consider an object with `countryCode` and `countryName` properties:
```json
{
countryCode: "CA",
countryName: "Canada"
}
```
If you wanted to display `Canada` in the dropdown, you'd use the `countryName` key:
```html
<v-select label="countryName" :options="countries"></v-select>
```
<country-select />
## Null / Empty Options
`vue-select` requires the `options` prop to be an `array`. If you are using Vue in development
mode, you will get warnings attempting to pass anything other than an `array` to the `options` prop.
If you need a `null`/`empty` value, use an empty array `[]`.
+18
View File
@@ -0,0 +1,18 @@
::: tip <Badge text="3.8.0+" />
Pagination is supported using slots available with Vue Select 3.8 and above.
:::
Pagination can be a super helpful tool when working with large sets of data. If you have 1,000
options, the component is going to render 1,000 DOM nodes. That's a lot of nodes to insert/remove,
and chances are your user is only interested in a few of them anyways.
To implement pagination with Vue Select, you can take advantage of the `list-footer` slot. It
appears below all other options in the drop down list.
To make pagination work properly with filtering, you'll have to handle it yourself in the parent.
You can use the `filterable` boolean to turn off Vue Select's filtering, and then hook into the
`search` event to use the current search query in the parent component.
<Paginated />
<<< @/.vuepress/components/Paginated.vue
+33
View File
@@ -0,0 +1,33 @@
## Default
With the default CSS, Vue Select uses absolute positioning to render the dropdown menu. The root
`.v-select` container (the components `$el`) is used as the `relative` parent for the dropdown. The
dropdown will be displayed below the `$el` regardless of the available space.
This works for most cases, but you might run into issues placing into a modal or near the bottom of
the viewport. If you need more fine grain control, you can use calculated positioning.
## Calculated <Badge text="v3.7.0+" />
If you want more control over how the dropdown is rendered, or if you're running into z-index issues,
you may use the `appendToBody` boolean prop. When enabled, Vue Select will append the dropdown to
the document, outside of the `.v-select` container, and position it with Javscript.
When `appendToBody` is true, the positioning will be handled by the `calculatePosition` prop. This
function is responsible for setting top/left absolute positioning values for the dropdown. The
default implementation places the dropdown in the same position that it would normally appear.
## Popper.js Integration <Badge text="v3.7.0+" />
[Popper.js](https://popper.js.org/) is an awesome, 3kb utility for calculating positions of just
about any DOM element relative to another.
By using the `appendToBody` and `calculatePosition` props, we're able to integrate directly with
popper to calculate positioning for us.
<PositionedWithPopper />
Check out the [Popper Docs](https://popper.js.org/docs/v2/modifiers/) to see the full `modifiers`
API being used below.
<<< @/.vuepress/components/PositionedWithPopper.vue{25-59}
+44
View File
@@ -0,0 +1,44 @@
## Selectable Prop <Badge text="v3.3.0+" />
The `selectable` prop determines if an option is selectable or not. If `selectable` returns false
for a given option, it will be displayed with a `vs__dropdown-option--disabled` class. The option
will be disabled and unable to be selected.
```js
selectable: {
type: Function,
/**
* @param {Object|String} option
* @return {boolean}
*/
default: option => true,
},
```
### Example
Here `selectable` is used to prevent books by a certain author from being chosen. In this case,
the options passed to the component are objects:
```json
{
title: "Right Ho Jeeves",
author: { firstName: "P.D", lastName: "Woodhouse" },
}
```
This object will be passed to `selectable`, so we can check if the author should be selectable or not.
<UnselectableExample />
<<< @/.vuepress/components/UnselectableExample.vue{6}
## Limiting the Number of Selections
`selectable` can also be used a bit more creatively to limit the number selections that can be made
within the component. In this case, the user can select any author, but may only select a maximum
of three books.
<LimitSelectionQuantity />
<<< @/.vuepress/components/LimitSelectionQuantity.vue{8}
+32
View File
@@ -0,0 +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
[API Docs for Slots](../api/slots.md) in the meantime while a good guide is put together.
:::
### 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>
```
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
+119
View File
@@ -0,0 +1,119 @@
## `index` prop replaced with `reduce`
- v2.x provided the `index` `{String}` prop to return a single key from a selected object
- v3.x removes the `index` prop, replacing it with the `reduce` `{Function}` prop.
Using a function instead of a string provides a whole lot more flexibility, allowing for things like
deeply nested values, and really cleaned up the code internally.
```js
const options = [{country: 'Canada', code: 'CA'},];
```
```html
<!-- v2: using index --->
<v-select :options="options" label="country" index="code" />
<!-- v3: using reduce --->
<v-select :options="options" label="country" :reduce="country => country.code" />
```
View the full [documentation for `reduce`](values.md#returning-a-single-key-with-reduce).
## Events instead of Callbacks
Three function callbacks have been removed in favor of using events.
- `onChange`
- `onInput`
- `onSearch`
While this is a breaking change, the change in your application should be as simple as swapping the
prop you were using for an event.
### `onChange` & `onInput`
In v2.x, Overwriting `onChange` in an application was more likely to break vue-select's internals
and cause issues. The `input` event provides identical functionality and can be swapped out in your
application.
```html
<!-- version 2: -->
<v-select :on-change="doSomething" />
<!-- version 3: -->
<v-select @input="doSomething" />
```
Additionally, the `change` event has been removed. This event was redundant, `input` should be used
instead.
```html
<!-- version 2: -->
<v-select @change="doSomething" />
<!-- version 3: -->
<v-select @input="doSomething" />
```
### `onSearch`
The `onSearch` prop was removed for the same reason as `onChange` and `onInput`. The `search` event
has always provided the same parameters and can be used in it's place.
```html
<!-- version 2: -->
<v-select :on-search="doSomeAjax" />
<!-- version 3: -->
<v-select @search="doSomeAjax" />
```
### `@search` with null search string
The `@search` event is now fired anytime the search string changes. In v2.x, the component
would first check if the search string was empty, and only emit the event if it had at least one
character. This was a design mistake, as it should be the consumers decision if a search should be
run on an empty string.
## Separated CSS
CSS was removed from the JS bundle in favor of a separate CSS file to support SSR and easier
customization.
```js
@import vSelect from 'vue-select`;
@import 'vue-select/dist/vue-select.css';
```
## New Class Selector Prefix
In order to avoid CSS collisions and allow for low specificity overrides of CSS, all classes have
been renamed to include the `vs__` prefix. The full list of renamed classes are listed below:
| original | renamed |
| ------- | --------- |
| `.open-indicator` | `.vs__open-indicator` |
| `.dropdown-toggle` | `.vs__dropdown-toggle` |
| `.dropdown-menu` | `.vs__dropdown-menu` |
| `.clear` | `.vs__clear` |
| `.selected-tag` | `.vs__selected` |
| `.no-options` | `.vs__no-options` |
| `.spinner` | `.vs__spinner` |
| `.close` | `.vs__deselect` |
| `.active` | `.vs__active` |
## Internal State
**The changes listed below are very unlikely to break your apps** unless you've been hooking into
vue-select internal values. [#781](https://github.com/sagalbot/vue-select/pull/781)
(thanks [@owenconti!](https://github.com/owenconti)) introduced a number of optimizations to the
way that the component handles internal state.
- `value`: the `value` prop is undefined by default. vue-select no longer maintains an internal `mutableValue` state when a `value` prop has been passed. When `:value` or `v-model` is not used, vue-select will maintain internal state using the `_value` property.
- `mutableOptions` has been removed in favor of an `optionList` computed property.
## Misc
- `fade` transition renamed to `vs__fade`
- Removed `a` element that was serving as the click handler within dropdown options
+24
View File
@@ -0,0 +1,24 @@
## Required
If you need to ensure that a selection is made before a form is submitted, you can
use the `required` attribute in combination with the `search` scoped slot in order
to do so.
However, the `search` input within the component does not actually store a value, so
simply adding the `required` attribute won't work. Instead, we'll bind the attribute
dynamically, so that it's only present if we don't have a selection.
<ValidationRequired />
```html
<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>
```
+176
View File
@@ -0,0 +1,176 @@
## Getting and Setting
### `v-model`
The most common use case for vue-select is to have the chosen value synced with a parent component. vue-select
takes advantage of the `v-model` syntax to sync values with a parent. The `v-model` syntax works with
primitives and objects.
```html
<v-select v-model="selected" />
```
Note that when using the `multiple` prop, the `v-model` value will always be an array.
### Props and Events
Sometimes `v-model` might not fit your use case. For example, when working with [Vuex](https://vuex.vuejs.org),
you'll need to trigger a mutation rather than mutating a value directly. In that case, maybe you need
to bind a pre-selected value, and trigger a mutation when it changes.
vue-select exposes the `value` prop and an `input` event to enable this. This combo of props and
events is also how Vue wires up the `v-model` syntax internally.
#### Prop: `value`
The `value` prop lets vue-select know what value is currently selected. It will accept strings,
numbers or objects. If you're using a `multiple` v-select, you'll want to pass an array.
```html
<v-select :value="selected" />
```
::: tip 🤓
Anytime you bind the `value` prop directly, you're responsible for updating the bound variable
in your code using the `@input` event.
:::
#### Event: `input`
The `input` event is triggered anytime the value state changes, and is emitted with the `value`
state as it's only parameter.
#### Vuex Support
The `value` prop and `emit` event are very useful when using a state management tool, like Vuex.
You can bind the selected value with `:value="$store.myValue"`, and use the `input` event to
trigger a mutation, or dispatch an action or anything else you might need to do when the selection
changes.
```html
<v-select :value="$store.myValue" @input="setSelected" />
```
```js
methods: {
setSelected(value) {
// trigger a mutation, or dispatch an action
}
}
```
## Transforming Selections
When the `options` array contains objects, vue-select returns the whole object as dropdown value
upon selection. This approach makes no assumptions about the data you need, and provides a lot of
flexibility. However, there will be situations where maybe you just need to return a single key
from an object.
### Returning a single key with `reduce`
If you need to return a single key, or transform the selection before it is synced, vue-select
provides a `reduce` callback that allows you to transform a selected option before it is passed to
the `@input` event. Consider this data structure:
```js
let options = [{code: 'CA', country: 'Canada'}];
```
If we want to display the `country`, but return the `code` to `v-model`, we can use the `reduce`
prop to receive only the data that's required.
```html
<v-select :options="options" :reduce="country => country.code" label="country" />
```
### Deep Nested Values
The `reduce` property also works well when you have a deeply nested value:
```
{
country: 'canada',
meta: {
code: 'ca'
provinces: [...],
}
}
```
```html
<v-select :options="options" :reduce="country => country.meta.code" label="country" />
```
<reducer-nested-value />
## Single/Multiple Selection
By default, vue-select supports choosing a single value. If you need multiple values, use the
`multiple` boolean prop, much the same way you would on an HTML `<select>` element. When `multiple`
is true, `v-model` and `value` must be an array.
```html
<v-select multiple v-model="selected" :options="['Canada','United States']" />
```
<v-select multiple :options="['Canada','United States']" />
## Tagging
To allow input that's not present within the options, set the `taggable` prop to true.
```html
<v-select taggable multiple />
```
<v-select taggable multiple />
If you want added tags to be pushed to the options array, set `push-tags` to true.
```html
<v-select taggable multiple push-tags />
```
<v-select taggable multiple push-tags />
### Using `taggable` & `reduce` together
When combining `taggable` with `reduce`, you must define the `createOption` prop. The
`createOption` function is responsible for defining the structure of the objects that Vue Select
will create for you when adding a tag. It should return a value that has the same properties as the
rest of your `options`.
If you don't define `createOption`, Vue Select will construct a simple object following this structure:
`{[this.label]: searchText}`. If you're using `reduce`, this is probably not what your options look
like, which is why you'll need to set the function yourself.
**Example**
We have a taggable select for adding books to a collection. We're just concerned about getting the
book title added, and our server side code will add the author details in a background process. The
user has already selected a book.
```js
const options = [
{
title: "HTML5",
author: {
firstName: "Remy",
lastName: "Sharp"
}
}
];
```
```html
<v-select
taggable
multiple
label="title"
:options="options"
:create-option="book => ({ title: book, author: { firstName: '', lastName: '' } })"
:reduce="book => `${book.author.firstName} ${book.author.lastName}`"
/>
```
+16
View File
@@ -0,0 +1,16 @@
### Using the `input` Event with Vuex
`vue-select` emits the `input` event any time the internal `value` is changed.
This is the same event that allow the for the `v-model` syntax. When using
Vuex for state management, you can use the `input` event to dispatch an
action, or trigger a mutation.
```html
<v-select
@input="myAction"
:options="$store.state.options"
:value="$store.state.selected"
></v-select>
```
<CodePen url="aJQJyp" height="350"/>