Last active
August 27, 2021 05:31
-
-
Save dragg/963a90c448f23ebfb1f3d9c78493bb91 to your computer and use it in GitHub Desktop.
Vue Components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<select :name="name" class="form-control"> | |
<slot></slot> | |
</select> | |
</template> | |
<script> | |
import 'select2-bootstrap-theme/dist/select2-bootstrap.css'; | |
export default { | |
props: { | |
value: [String, Number, Boolean, Array], | |
name: String, | |
initConfig: { | |
type: Object, | |
default: () => { | |
return {}; | |
} | |
}, | |
/** | |
* Must pass next object with next properties: | |
* url | |
* handler - function that receive item and return object with id and text properties OR pass as object with mapping of properties id and text | |
* lengthPerPage - Number | |
* | |
* For example | |
* url: '/tags', | |
* handler: {id: 'id', text: 'title'} or handler: (tag) => { return {id: tag.id, text: tag.title};} | |
* lengthPerPage: 15 | |
*/ | |
ajax: { | |
type: Object, | |
default: () => { | |
return null; | |
}, | |
}, | |
}, | |
data() { | |
return { | |
optionsObserver: null, | |
}; | |
}, | |
watch: { | |
value: function (value) { | |
this.update(value); | |
}, | |
}, | |
mounted: function () { | |
this.initialize(); | |
this.setOptionsObserver(); | |
}, | |
beforeDestroy: function () { | |
this.destroyOptionsObserver(); | |
this.destroy(); | |
}, | |
methods: { | |
initialize() { | |
let self = this; | |
let config = self.getConfig(); | |
$(this.$el) | |
.select2({ | |
theme: 'bootstrap', | |
width: '100%', | |
dropdownAutoWidth: true, | |
...config, | |
}) | |
.val(this.value) | |
.trigger('change') | |
.on('change', (event) => { | |
if (self.initConfig.multiple) { | |
let selectedOptions = [].map.call(event.target.selectedOptions, function (option) { | |
return option.value; | |
}); | |
self.$emit('input', selectedOptions); | |
} else { | |
self.$emit('input', event.target.value); | |
} | |
self.$emit('change', event); | |
}); | |
}, | |
getConfig() { | |
let config = { | |
...this.initConfig, | |
}; | |
if (this.ajax) { | |
let ajaxConfig = {}; | |
ajaxConfig.url = this.ajax.url; | |
let handlerIsCallable = typeof this.ajax.handler === "function"; | |
let handler = handlerIsCallable ? this.ajax.handler(item) : (item) => { | |
return { | |
id: item[this.ajax.handler.id], | |
text: item[this.ajax.handler.text] | |
} | |
}; | |
ajaxConfig.processResults = (data, params) => { | |
let items = data.data; | |
let page = params.page || 1; | |
return { | |
results: items.map(item => { | |
return handler(item); | |
}), | |
pagination: { | |
more: (page * this.ajax.lengthPerPage) < data.recordsFiltered | |
} | |
}; | |
}; | |
ajaxConfig.data = function (params) { | |
return { | |
...params, | |
page: params.page || 1 | |
}; | |
}; | |
config.ajax = ajaxConfig; | |
} | |
return config; | |
}, | |
update(value) { | |
if (this.initConfig.multiple && $(this.$el).select2('data').length !== value.length) { | |
let self = this; | |
// ToDo: need resolve if this is ajax then we can have a case when selected item not loaded! | |
// Handle options only on next vue tick if an option was delete but still not redraw | |
// Added here because '.val(value)' not worked in all cases. ToDo: need recheck it! | |
Vue.nextTick(() => { | |
// Find all value's options and check that it's selected | |
value.forEach(oneValue => { | |
let foundOption; | |
for (let i = 0, option; option = $(self.$el)[0].options[i]; i++) { | |
if ($(option).val() == oneValue) { | |
foundOption = option; | |
break; | |
} | |
} | |
if (!$(foundOption).is(':selected')) { | |
$(foundOption).attr('selected', 'selected'); | |
} | |
}); | |
// ToDo: need add removing individually selected options | |
// Handle if need reset all selected options | |
if (value.length === 0) { | |
// for (let i = 0, option; option = $(self.$el.options[i]); i++) { | |
// option.removeAttr('selected'); | |
// } | |
} | |
$(this.$el).val(value).trigger('change'); | |
}); | |
return; | |
} | |
if (!this.initConfig.multiple && $(this.$el).select2('data').length === 1) { | |
let selectedOption = $(this.$el).select2('data')[0]; | |
if (selectedOption.id !== value) { | |
$(this.$el).val(value); | |
$(this.$el).trigger('change'); | |
} | |
} | |
}, | |
destroy() { | |
$(this.$el).off().select2('destroy'); | |
}, | |
setOptionsObserver() { | |
this.optionsObserver = new MutationObserver(() => { | |
this.destroy(); | |
this.initialize(); | |
}); | |
// Setup the observer | |
this.optionsObserver.observe($(this.$el)[0], {childList: true}); | |
}, | |
destroyOptionsObserver() { | |
this.optionsObserver.disconnect(); | |
this.optionsObserver = null; | |
}, | |
} | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment