livewire-select2-adapter
Version:
Enables seamless integration between Select2 and Laravel Livewire.
223 lines (197 loc) • 6.71 kB
JavaScript
/**
* Livewire Select2 Adapter (xdn27)
* Version: 1.2.2
* Enables seamless integration between Select2 and Laravel Livewire.
*
* @author
* xdn27 - https://github.com/xdn27
*
* @license MIT
*/
(function (factory) {
if (typeof define === "function" && define.amd) {
define(["jquery", "select2"], factory);
} else if (typeof exports === "object") {
module.exports = factory(require("jquery"), require("select2"));
} else {
factory(jQuery, window.jQuery.fn.select2);
}
})(function ($, select2) {
"use strict";
if (!$.fn.select2) {
console.error("[LivewireSelect2Adapter] Select2 is not loaded!");
return;
}
var ArrayAdapter = $.fn.select2.amd.require("select2/data/array");
function LivewireModelAdapter($element, options) {
ArrayAdapter.call(this, $element, options);
this._defaultEventName = "select2-results";
this._defaultEmitName = "select2-query";
this.livewireConfig = $.extend(
{
eventName: this._defaultEventName,
emitName: this._defaultEmitName,
eventOnSelect: "model",
delay: 300,
},
options.get("livewire") || {}
);
this._element = $element;
this._wireModel =
$element.attr("wire:model") || $element.attr("wire:model.live");
this._registeredEventName = this.livewireConfig.eventName;
if (
this._registeredEventName === this._defaultEventName &&
this._wireModel
) {
this._registeredEventName += "-" + this._wireModel;
}
this._initLivewireListener();
this._attachLivewireReinit();
}
LivewireModelAdapter.prototype = Object.create(ArrayAdapter.prototype);
LivewireModelAdapter.prototype.constructor = LivewireModelAdapter;
LivewireModelAdapter.prototype.current = function (callback) {
var data = [];
this._element.find(":selected").each(function () {
var $option = $(this);
data.push({
id: $option.val(),
text: $option.text(),
selected: true,
});
});
callback(data);
};
LivewireModelAdapter.prototype._initLivewireListener = function () {
var self = this;
this._eventHandler = function (e) {
if (self._pendingCallback) {
self._pendingCallback({
results: e.detail[0].results,
});
self._pendingCallback = null;
}
};
window.addEventListener(this._registeredEventName, this._eventHandler);
if (self._element.prop("multiple")) {
// Not supported yet
} else {
this._element.on("select2:select", function (e) {
self._handleSelection(e);
});
}
this._observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.removedNodes.forEach(function (node) {
if (node.contains(self._element[0])) {
self.destroy();
}
});
});
});
this._observer.observe(document.body, { childList: true, subtree: true });
};
LivewireModelAdapter.prototype._handleSelection = function (e) {
var self = this;
if (self.livewireConfig.eventOnSelect === "model") {
var model = self._wireModel;
if (model && window.Livewire) {
var componentRoot = e.target.closest("[wire\\:id]");
var componentId = componentRoot
? componentRoot.getAttribute("wire:id")
: null;
if (componentId) {
var component = window.Livewire.find(componentId);
if (component) {
var isDeferred = !model.includes(".live");
var value = e.params.data.id;
component.set(model, value, isDeferred);
}
}
}
} else if (self.livewireConfig.eventOnSelect) {
if (window.Livewire) {
if (typeof window.Livewire.dispatch === "function") {
window.Livewire.dispatch(
self.livewireConfig.eventOnSelect,
e.params.data
);
} else if (typeof window.Livewire.emit === "function") {
window.Livewire.emit(
self.livewireConfig.eventOnSelect,
e.params.data
);
} else {
console.error(
"[LivewireSelect2Adapter] Livewire emit/dispatch is not available."
);
}
}
}
};
LivewireModelAdapter.prototype._attachLivewireReinit = function () {
if (!window.__livewire_select2_reinit_hook_attached) {
window.__livewire_select2_reinit_hook_attached = true;
document.addEventListener("livewire:init", function () {
if (window.Livewire && window.Livewire.hook) {
window.Livewire.hook("morphed", function () {
$("[data-select2-livewire]").each(function () {
var $el = $(this);
if ($el.data("select2")) {
var config = $el.data("select2").options.options;
$el.select2(config);
}
});
});
}
});
}
};
LivewireModelAdapter.prototype.query = function (params, callback) {
var self = this;
clearTimeout(this._queryTimeout);
this._queryTimeout = setTimeout(function () {
self._pendingCallback = callback;
if (window.Livewire) {
var emitName = self.livewireConfig.emitName;
if (emitName === self._defaultEmitName && self._wireModel) {
emitName += "-" + self._wireModel;
}
if (typeof window.Livewire.dispatch === "function") {
window.Livewire.dispatch(emitName, params);
} else if (typeof window.Livewire.emit === "function") {
window.Livewire.emit(emitName, params);
} else {
console.error(
"[LivewireSelect2Adapter] Livewire emit/dispatch is not available."
);
}
} else {
console.error("[LivewireSelect2Adapter] Livewire is not available.");
}
}, this.livewireConfig.delay);
};
LivewireModelAdapter.prototype.destroy = function () {
if (this._eventHandler) {
window.removeEventListener(this._registeredEventName, this._eventHandler);
this._eventHandler = null;
}
if (this._observer) {
this._observer.disconnect();
this._observer = null;
}
if (this._element) {
this._element.off("select2:select");
}
};
LivewireModelAdapter.prototype.render = function () {
return ArrayAdapter.prototype.render.call(this);
};
LivewireModelAdapter.prototype.bind = function (container, $container) {
return ArrayAdapter.prototype.bind.call(this, container, $container);
};
window.select2 = window.select2 || {};
window.select2.LivewireModelAdapter = LivewireModelAdapter;
window.select2.LivewireModelAdapterVersion = "1.2.0";
});