Skip to content

Commit

Permalink
add prop required to prevent form submission if no options selected (c…
Browse files Browse the repository at this point in the history
…loses #42)
  • Loading branch information
janosh committed Feb 21, 2022
1 parent 39516a1 commit f8812c3
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 15 deletions.
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Full list of props/bindable variables for this component:
| `input` | `undefined` | Handle to the `<input>` DOM node. |
| `id` | `undefined` | Applied to the `<input>` element for associating HTML form `<label>`s with this component for accessibility. Also, clicking a `<label>` with same `for` attribute as `id` will focus this component. |
| `name` | `id` | Applied to the `<input>` element. If not provided, will be set to the value of `id`. Sets the key of this field in a submitted form data object. Not useful at the moment since the value is stored in Svelte state, not on the `<input>`. |
| `required` | `false` | Whether forms can be submitted without selecting any options. Aborts submission, is scrolled into view and shows help "Please fill out" message when true and user tries to submit with no options selected. |
| `autoScroll` | `true` | `false` disables keeping the active dropdown items in view when going up/down the list of options with arrow keys. |
| `allowUserOptions` | `false` | Whether users are allowed to enter values not in the dropdown list. `true` means add user-defined options to the selected list only, `'append'` means add to both options and selected. |
| `loading` | `false` | Whether the component should display a spinner to indicate it's in loading state. Use `<slot name='spinner'>` to specify a custom spinner. |
Expand Down
36 changes: 21 additions & 15 deletions src/components/Example.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,27 @@

<label for="fruit-select">Custom renderers for options and/or selected items</label>

<MultiSelect
id="fruit-select"
options={[`Banana`, `Watermelon`, `Apple`, `Dates`, `Mango`]}
{placeholder}
allowUserOptions="append"
>
<span let:idx let:option slot="option">
{idx + 1}. {option.label}
{option.label === `Mango` ? `🎉` : ``}
</span>
<span let:idx let:option slot="selected">
#{idx + 1}
{option.label}
</span>
</MultiSelect>
<form>
<MultiSelect
id="fruit-select"
options={[`Banana`, `Watermelon`, `Apple`, `Dates`, `Mango`]}
{placeholder}
allowUserOptions="append"
required
>
<span let:idx let:option slot="option">
{idx + 1}. {option.label}
{option.label === `Mango` ? `🎉` : ``}
</span>
<span let:idx let:option slot="selected">
#{idx + 1}
{option.label}
</span>
</MultiSelect>
<button style="border: none; border-radius: 2pt; margin: 5pt 5pt 8pt 0;"
>submit</button
> (form submission will abort if Multiselect is empty)
</form>
</section>

<style>
Expand Down
16 changes: 16 additions & 0 deletions src/lib/MultiSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
export let allowUserOptions: boolean | 'append' = false
export let autoScroll = true
export let loading = false
export let required = false
if (maxSelect !== null && maxSelect < 0) {
console.error(`maxSelect must be null or positive integer, got ${maxSelect}`)
Expand All @@ -53,6 +54,10 @@
})
let wiggle = false
// formValue binds to input.form-control to prevent form submission if required
// prop is true and no options are selected
$: formValue = selectedValues.join(`,`)
const dispatch = createEventDispatcher<DispatchEvents>()
function isObject(item: unknown) {
Expand Down Expand Up @@ -225,6 +230,8 @@ display above those of another following shortly after it -->
use:onClickOutside={() => setOptionsVisible(false)}
use:onClickOutside={() => dispatch(`blur`)}
>
<!-- invisible input, used only to prevent form submission if required=true and no options selected -->
<input {required} bind:value={formValue} tabindex="-1" class="form-control" />
<ExpandIcon style="min-width: 1em; padding: 0 1pt;" />
<ul class="selected {ulSelectedClass}">
{#each selected as option, idx}
Expand Down Expand Up @@ -395,6 +402,15 @@ display above those of another following shortly after it -->
font-size: calc(16px + 0.1vw);
color: var(--sms-text-color, inherit);
}
:where(div.multiselect > input.form-control) {
width: 2em;
position: absolute;
background: transparent;
border: none;
outline: none;
z-index: -1;
opacity: 0;
}
:where(div.multiselect > ul.options) {
list-style: none;
Expand Down

0 comments on commit f8812c3

Please sign in to comment.