Skip to content

Instantly share code, notes, and snippets.

@halivert
Last active November 16, 2019 07:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save halivert/b34c22aa06007ead9b05df857e7ad1b6 to your computer and use it in GitHub Desktop.
Save halivert/b34c22aa06007ead9b05df857e7ad1b6 to your computer and use it in GitHub Desktop.
Select for use with Vue.js
<template>
<div>
<select v-bind="$attrs" v-model="selectedId" v-on="selectListeners">
<option
v-if="$attrs.placeholder"
:value="placeholderId"
:disabled="!enablePlaceholder"
>
{{ $attrs.placeholder }}
</option>
<option
v-for="(element, index) in elements"
:key="index"
:value="getElementId(element)"
>
{{ getElementDisplay(element) }}
</option>
</select>
</div>
</template>
<script>
export default {
name: "h-select",
inheritAttrs: false,
model: {
event: "change"
},
props: {
displayAttr: { type: String, default: "display" },
enablePlaceholder: Boolean,
idAttr: { type: String, default: "id" },
initialElements: [Array, Object],
old: {},
placeholderId: { type: String, default: "" },
value: {}
},
computed: {
selectListeners() {
var vm = this;
return Object.assign(this.$listeners, {
change: function(evt) {
vm.selectedId = evt.target.value;
}
});
},
firstElement() {
if (
!this.$attrs.placeholder &&
this.elements &&
this.elements.length > 0
) {
return this.getElementId(this.elements[0]);
}
return this.placeholderId;
}
},
data() {
return {
elements: [],
selectedId: this.placeholderId
};
},
watch: {
value(newValue) {
if (newValue) this.selectedId = newValue.toString();
else this.selectedId = newValue;
},
initialElements(newElements) {
this.elements = this.normalizeElements(newElements);
},
selectedId(newValue) {
if (newValue !== this.value) {
this.$emit("change", newValue);
}
},
elements(newElements) {
if (!this.elementsContain(this.selectedId)) {
if (newElements && newElements.length === 1) {
this.selectedId = this.getElementId(newElements[0]);
} else {
this.selectedId = this.firstElement;
}
}
}
},
created() {
var normalized;
if (this.$slots["default"]) {
var f = this.optionFromVNode;
normalized = this.$slots["default"].reduce((a, el) => {
var element = f(el);
if (element) a.push(element);
return a;
}, []);
} else {
normalized = this.normalizeElements(this.initialElements);
}
this.selectedId = this.old;
if (normalized && normalized.length > 0) this.elements = normalized;
},
methods: {
getElementId(element) {
if (
element &&
element.hasOwnProperty(this.idAttr) &&
element[this.idAttr]
) {
return element[this.idAttr].toString();
}
return element;
},
getElementDisplay(element) {
if (
element &&
element.hasOwnProperty(this.displayAttr) &&
element[this.displayAttr]
) {
return element[this.displayAttr].toString();
}
return element;
},
selectElementByIndex(index) {
this.selectedId = this.getElementId(this.elements[index]);
},
elementsContain(id) {
if (this.elements != undefined) {
return (
this.elements.find(
e => this.getElementId(e) === this.getElementId(id)
) !== undefined
);
}
},
getSelected(id) {
if (id == undefined) id = this.selectedId;
return this.elements.find(
e => this.getElementId(e) === this.getElementId(id)
);
},
normalizeElements(obj) {
var idAttr = this.idAttr;
var displayAttr = this.displayAttr;
if (obj instanceof Array) {
return obj;
} else if (obj instanceof Object) {
return Object.keys(obj).reduce((a, k) => {
var newObj = {};
newObj[idAttr] = k;
newObj[displayAttr] = obj[k];
a.push(newObj);
return a;
}, []);
}
},
optionFromVNode(vNode) {
if (vNode.tag === "option") {
var child;
var id, display;
var newObj = {};
var idAttr = this.idAttr;
var displayAttr = this.displayAttr;
if (vNode.children && vNode.children[0]) {
child = vNode.children[0];
}
if (vNode.data) {
if (vNode.data.attrs && vNode.data.attrs.value) {
id = vNode.data.attrs.value.toString();
} else if (vNode.data.domProps && vNode.data.domProps.value) {
id = vNode.data.domProps.value.toString();
}
}
if (child && child.text) {
display = child.text.toString();
if (id === undefined) id = display;
}
newObj[idAttr] = id;
newObj[displayAttr] = display;
return newObj;
}
}
}
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment