Files
openfoodnetwork/app/webpacker/controllers/tom_select_controller.js

93 lines
2.3 KiB
JavaScript

import { Controller } from "stimulus";
import TomSelect from "tom-select/dist/esm/tom-select.complete";
export default class extends Controller {
static values = {
options: Object,
placeholder: String,
remoteUrl: String,
};
connect(options = {}) {
let tomSelectOptions = {
maxItems: 1,
maxOptions: null,
plugins: ["dropdown_input"],
allowEmptyOption: true, // Show blank option (option with empty value)
placeholder: this.placeholderValue || this.#emptyOption(),
onItemAdd: function () {
this.setTextboxValue("");
},
...this.optionsValue,
...options,
};
if (this.remoteUrlValue) {
this.#addRemoteOptions(tomSelectOptions);
}
this.control = new TomSelect(this.element, tomSelectOptions);
}
disconnect() {
if (this.control) this.control.destroy();
}
// private
#emptyOption() {
const optionsArray = [...this.element.options];
return optionsArray.find((option) => [null, ""].includes(option.value))?.text;
}
#buildUrl(query, page = 1) {
const url = new URL(this.remoteUrlValue, window.location.origin);
url.searchParams.set("q", query);
url.searchParams.set("page", page);
return url.toString();
}
#fetchOptions(query, callback) {
const url = this.control.getUrl(query);
fetch(url)
.then((response) => response.json())
.then((json) => {
/**
* Expected API shape:
* {
* results: [{ value, label }],
* pagination: { more: boolean }
* }
*/
if (json.pagination?.more) {
const currentUrl = new URL(url);
const currentPage = parseInt(currentUrl.searchParams.get("page") || "1");
const nextUrl = this.#buildUrl(query, currentPage + 1);
this.control.setNextUrl(query, nextUrl);
}
callback(json.results || []);
})
.catch(() => {
callback();
});
}
#addRemoteOptions(options) {
options.firstUrl = (query) => {
return this.#buildUrl(query, 1);
};
options.load = this.#fetchOptions.bind(this);
options.onFocus = function () {
this.control.load("", () => {});
}.bind(this);
options.valueField = "value";
options.labelField = "label";
options.searchField = "label";
}
}