Skip to content

Commit 39e84de

Browse files
committed
feat(MultiSelect): allows to append the dropdown to a specific element
1 parent 46d447a commit 39e84de

File tree

3 files changed

+51
-9
lines changed

3 files changed

+51
-9
lines changed

docs/content/forms/multi-select.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ const mulitSelectList = mulitSelectElementList.map(mulitSelectEl => {
277277
| Name | Type | Default | Description |
278278
| --- | --- | --- | --- |
279279
| `cleaner`| boolean| `true` | Enables selection cleaner element. |
280+
| `container` | string, element, false | `false` | Appends the dropdown to a specific element. Example: `container: 'body'`. |
280281
| `disabled` | boolean | `false` | Toggle the disabled state for the component. |
281282
| `invalid` | boolean | `false` | Toggle the invalid state for the component. |
282283
| `multiple` | boolean | `true` | It specifies that multiple options can be selected at once. |

js/src/multi-select.js

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import SelectorEngine from './dom/selector-engine.js'
1313
import {
1414
defineJQueryPlugin,
1515
getNextActiveElement,
16+
getElement,
1617
isVisible,
1718
isRTL
1819
} from './util/index.js'
@@ -80,6 +81,7 @@ const CLASS_NAME_TAG_DELETE = 'form-multi-select-tag-delete'
8081

8182
const Default = {
8283
cleaner: true,
84+
container: false,
8385
disabled: false,
8486
invalid: false,
8587
multiple: true,
@@ -100,6 +102,7 @@ const Default = {
100102

101103
const DefaultType = {
102104
cleaner: 'boolean',
105+
container: '(string|element|boolean)',
103106
disabled: 'boolean',
104107
invalid: 'boolean',
105108
multiple: 'boolean',
@@ -179,6 +182,12 @@ class MultiSelect extends BaseComponent {
179182
EventHandler.trigger(this._element, EVENT_SHOW)
180183
this._clone.classList.add(CLASS_NAME_SHOW)
181184
this._clone.setAttribute('aria-expanded', true)
185+
186+
if (this._config.container) {
187+
this._menu.style.minWidth = `${this._clone.offsetWidth}px`
188+
this._menu.classList.add(CLASS_NAME_SHOW)
189+
}
190+
182191
EventHandler.trigger(this._element, EVENT_SHOWN)
183192

184193
this._createPopper()
@@ -199,6 +208,11 @@ class MultiSelect extends BaseComponent {
199208
this._onSearchChange(this._searchElement)
200209
this._clone.classList.remove(CLASS_NAME_SHOW)
201210
this._clone.setAttribute('aria-expanded', 'false')
211+
212+
if (this._config.container) {
213+
this._menu.classList.remove(CLASS_NAME_SHOW)
214+
}
215+
202216
EventHandler.trigger(this._element, EVENT_HIDDEN)
203217
}
204218

@@ -220,6 +234,7 @@ class MultiSelect extends BaseComponent {
220234
this._config = this._getConfig(config)
221235
this._options = this._getOptions()
222236
this._selected = this._getSelectedOptions(this._options)
237+
this._menu.remove()
223238
this._clone.remove()
224239
this._element.innerHTML = ''
225240
this._createNativeOptions(this._element, this._options)
@@ -534,6 +549,7 @@ class MultiSelect extends BaseComponent {
534549
}],
535550
placement: isRTL() ? 'bottom-end' : 'bottom-start'
536551
}
552+
537553
this._popper = Popper.createPopper(this._togglerElement, this._menu, popperConfig)
538554
}
539555

@@ -575,7 +591,13 @@ class MultiSelect extends BaseComponent {
575591

576592
dropdownDiv.append(optionsDiv)
577593

578-
this._clone.append(dropdownDiv)
594+
const { container } = this._config
595+
if (container) {
596+
// this._clone.parentNode.insertBefore(dropdownDiv, this._clone.nextSibling)
597+
getElement(container).append(dropdownDiv)
598+
} else {
599+
this._clone.append(dropdownDiv)
600+
}
579601

580602
this._createOptions(optionsDiv, this._options)
581603
this._optionsElement = optionsDiv
@@ -649,7 +671,7 @@ class MultiSelect extends BaseComponent {
649671
}
650672

651673
const value = String(element.dataset.value)
652-
const { text } = this._options.find(option => option.value === value)
674+
const { text } = this._findOptionByValue(value)
653675

654676
if (this._config.multiple && element.classList.contains(CLASS_NAME_SELECTED)) {
655677
this._deselectOption(value)
@@ -666,6 +688,23 @@ class MultiSelect extends BaseComponent {
666688
}
667689
}
668690

691+
_findOptionByValue(value, options = this._options) {
692+
for (const option of options) {
693+
if (option.value === value) {
694+
return option
695+
}
696+
697+
if (option.options && Array.isArray(option.options)) {
698+
const found = this._findOptionByValue(value, option.options)
699+
if (found) {
700+
return found
701+
}
702+
}
703+
}
704+
705+
return null
706+
}
707+
669708
_selectOption(value, text) {
670709
if (!this._config.multiple) {
671710
this.deselectAll()
@@ -860,7 +899,7 @@ class MultiSelect extends BaseComponent {
860899
}
861900

862901
_filterOptionsList() {
863-
const options = SelectorEngine.find(SELECTOR_OPTION, this._clone)
902+
const options = SelectorEngine.find(SELECTOR_OPTION, this._menu)
864903
let visibleOptions = 0
865904

866905
for (const option of options) {
@@ -884,8 +923,8 @@ class MultiSelect extends BaseComponent {
884923
}
885924

886925
if (visibleOptions > 0) {
887-
if (SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._clone)) {
888-
SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._clone).remove()
926+
if (SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._menu)) {
927+
SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._menu).remove()
889928
}
890929

891930
return
@@ -896,8 +935,8 @@ class MultiSelect extends BaseComponent {
896935
placeholder.classList.add(CLASS_NAME_OPTIONS_EMPTY)
897936
placeholder.innerHTML = this._config.searchNoResultsLabel
898937

899-
if (!SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._clone)) {
900-
SelectorEngine.findOne(SELECTOR_OPTIONS, this._clone).append(placeholder)
938+
if (!SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._menu)) {
939+
SelectorEngine.findOne(SELECTOR_OPTIONS, this._menu).append(placeholder)
901940
}
902941
}
903942
}

scss/forms/_form-multi-select.scss

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
.form-multi-select {
1+
.form-multi-select,
2+
*:not(.form-multi-select) > .form-multi-select-dropdown {
23
// scss-docs-start form-multi-select-css-vars
34
--#{$prefix}form-multi-select-zindex: #{$form-multi-select-zindex};
45
--#{$prefix}form-multi-select-font-family: #{$form-multi-select-font-family};
@@ -326,7 +327,8 @@ select.form-multi-select {
326327
@include box-shadow(var(--#{$prefix}form-multi-select-dropdown-box-shadow));
327328
@include elevation(4);
328329

329-
.form-multi-select.show & {
330+
.form-multi-select.show &,
331+
&.show {
330332
display: block;
331333
}
332334
}

0 commit comments

Comments
 (0)