Skip to content

Instantly share code, notes, and snippets.

@moritzjacobs
Last active July 3, 2018 11:48
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 moritzjacobs/7a8d8de0e700bcd2aafce06a18ea5286 to your computer and use it in GitHub Desktop.
Save moritzjacobs/7a8d8de0e700bcd2aafce06a18ea5286 to your computer and use it in GitHub Desktop.
($ => {
/**
* jQuery.selectToggler
*
* replaces a <select><option>… structure with a simple toggle structure
*
* $("select.foobar").selectToggler(function(el){
* el.addClass("foobar-toggler");
* el.find("> *").addClass("foobar-toggles");
* })
*
* @version 1.0.0
* @param {function} a callback function to put the output through
* @return {jQuery} this for chaining
*/
$.fn.selectToggler = function(renderFn = false) {
let wrapped = [];
this.toArray().forEach(el => {
const instance = new jQuerySelectToggler(el, renderFn);
if (instance !== false) {
wrapped.push(instance);
}
});
let ret = $();
$.each(wrapped, (i, o) => {
ret = ret.add(o)
});
return ret;
};
/**
* plugin class
*/
class jQuerySelectToggler {
/**
* constructor
* @param {HTMLElement} el the <select> element
* @param {object} options options
* @return {jQuery} the created wrapper for chaining
*/
constructor(el, renderFn = false) {
// fields
this.el = el;
this.renderFn = renderFn;
this.$el = $(el);
// error handling
if ($(el).length < 1) {
return false;
}
if (el.nodeName.toLowerCase() !== "select") {
return false;
}
if (this.$el.hasClass("select-toggler-hidden")) {
return false;
}
if (typeof this.renderFn !== "function") {
this.renderFn = x => x;
}
this.init();
return this.wrapper;
}
/**
* Init function
* @return {void}
*/
init() {
this.wrapper = this.insertNextTo();
this.hide();
this.observe();
}
/**
* hide the select dropdown
* @return {void}
*/
hide() {
this.$el.addClass("select-toggler-hidden");
this.$el.hide();
}
/**
* insert the created UI next to the select element
* @return {void}
*/
insertNextTo() {
const wrapper = $("<span/>");
wrapper.addClass("select-toggler-wrapper");
$(this.el).after(wrapper);
return wrapper;
}
/**
* convert select>option structure to obj structure
* @return {object} all options
*/
parseOptions() {
const options = this.$el.find("> *");
const selectedValue = this.$el.val();
let parsed = [];
options.each((i, option) => {
const value = $(option).attr("value");
const selected = value === selectedValue;
const label = $(option).html();
parsed.push({ value, label, selected });
});
return parsed;
}
/**
* create single toggle element
* @param {object} o toggle options
* @return {jQuery} single toggle element
*/
makeToggle(o) {
const toggle = $("<span/>");
toggle.addClass("select-toggler-item");
toggle
.attr("data-jqst-value", o.value)
.addClass(o.selected === true ? "is-selected" : "not-selected")
.html(o.label)
.click(e => {
e.preventDefault();
this.select(toggle);
});
return toggle;
}
/**
* (re-)render all the toggles
* @return {[type]} [description]
*/
makeToggles() {
// remove old toggles
if (this.toggles !== undefined) {
this.toggles.remove();
}
// new toggles
this.toggles = $("<span class='select-toggler-items'/>").appendTo(this.wrapper);
// helper class
if (this.$el.val().length <= 0) {
this.toggles.addClass("is-none-selected");
}
const options = this.parseOptions(this.el);
options.forEach(o => {
this.makeToggle(o).appendTo(this.toggles);
});
// run through custom render function, if there is one
const rendered = this.renderFn(this.wrapper);
this.wrapper.replaceWith(rendered);
}
/**
* select dropwdion item by toggle item
* @param {jQuery} item the selected item
* @return {void}
*/
select(item) {
this.el.value = $(item).attr("data-jqst-value");
this.$el.change();
this.toggles.find("*").removeClass("is-selected");
item.addClass("is-selected");
}
/**
* Add mutation observer
* @return {void}
*/
observe() {
const observer = new MutationObserver(() => {
// if anything changes, rerender!
this.makeToggles();
});
observer.observe(this.el, { attributes: true, childList: true });
}
}
})(jQuery);
@moritzjacobs
Copy link
Author

jQuery.selectToggler

jQuery plugin to replace a <select><option>… structure with a simple toggle structure while maintaing all event handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment