multiple-select-js
Version:
Simple js library for html5 multiple select
108 lines (85 loc) • 2.98 kB
JavaScript
import Container from './components/Container'
import Store from './store/Store'
import './scss/multiple-select.scss'
var selectMultipleContainerId = 0
class MultipleSelect {
constructor(elId, options) {
selectMultipleContainerId++
const defaultOptions = {
placeholder: 'Select'
}
this.$store = new Store()
let { el, select, isMultiple, items, selectedItems } = this._buildRootElement(elId)
this.$el = el
this.$select = select
this.$options = { ...defaultOptions, ...options }
this.$store.isMultiple = isMultiple
this.$store.items = items
this.$store.selectedItems = selectedItems
this.$container = new Container({
root: this
})
// syncing with the actual select
this.$store.on('selectedItemsChange', (selectedItems) => {
this.$select.querySelectorAll('option').forEach(option => {
if (selectedItems.find(item => item.value === option.value)) {
option.setAttribute('selected', true)
} else {
option.removeAttribute('selected')
}
})
if (selectedItems.length < 1) {
this.$select.value = ''
}
const changeEvent = document.createEvent('HTMLEvents')
changeEvent.initEvent('change', true, true)
const inputEvent = document.createEvent('HTMLEvents')
inputEvent.initEvent('input', true, true)
this.$select.dispatchEvent(changeEvent)
this.$select.dispatchEvent(inputEvent)
})
// when the container is done rendered, the dropdown
// will automatically focused
let observer = new MutationObserver(() => {
if (this.$el.classList.contains('opened')) {
this.$container.$dropdownSelect.$input.focus()
}
})
observer.observe(this.$el, { attributes: true, childList: true });
}
/**
* Creating `<div>` for root element right after the `<select>` element.
* And then hide the `<select>` element.
*
* @param {*} elId
* @returns {*}
* @memberof MultipleSelect
*/
_buildRootElement (elId) {
let select = document.querySelector(elId)
let root = document.createElement('div')
let items = []
let selectedItems = []
root.setAttribute('id', `multiple-select-container-${selectMultipleContainerId}`)
root.style.position = 'relative'
select.querySelectorAll('option').forEach(option => {
items.push({
value: option.value,
label: option.innerText.trim(),
disabled: option.disabled
})
})
// get the already selected items
select.querySelectorAll('option[selected]').forEach(option => {
selectedItems.push({ value: option.value, label: option.innerText.trim() })
})
let isMultiple = select.multiple
select.insertAdjacentElement('afterend', root)
select.hidden = true
return {
select, el: root, isMultiple, items, selectedItems
}
}
}
window.MultipleSelect = MultipleSelect
export default MultipleSelect