From b7c4e580c4cf84dc10fe955b5eecbd8ec23a13b7 Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Sun, 11 Oct 2026 21:05:05 +0100 Subject: [PATCH] fix: only show the server's results for the current query in searchable dropdowns --- pipeline/source_assets/js/autocompleter.js | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/pipeline/source_assets/js/autocompleter.js b/pipeline/source_assets/js/autocompleter.js index eb0870f9..dcc5261a 100644 --- a/pipeline/source_assets/js/autocompleter.js +++ b/pipeline/source_assets/js/autocompleter.js @@ -70,18 +70,28 @@ function initPicker(select) { }; if (url) { + // The server does the searching. Tom Select keeps every option it has ever loaded, so remember which + // ones the server returned for each query and only show those (otherwise results for "a" and "al" + // linger in the dropdown when searching for "ali hassan"). + var results = {}; + var normalise = function (query) { return query.trim().toLowerCase(); }; + Object.assign(settings, { - // Results come from the server so don't filter them locally - score: function () { return function () { return 1; }; }, + score: function (query) { + var ids = results[normalise(query)]; + return function (option) { return ids && ids.has(String(option.value)) ? 1 : 0; }; + }, shouldLoad: function (query) { return query.length > 0; }, load: function (query, callback) { var separator = url.indexOf('?') === -1 ? '?' : '&'; fetch(url + separator + 'q=' + encodeURIComponent(query), {credentials: 'same-origin'}) .then(function (response) { return response.json(); }) .then(function (data) { - callback(data.map(function (item) { + var options = data.map(function (item) { return {value: item.pk, text: item.text, update_url: item.update}; - })); + }); + results[normalise(query)] = new Set(options.map(function (option) { return String(option.value); })); + callback(options); }) .catch(function () { callback(); }); } @@ -94,6 +104,14 @@ function initPicker(select) { }); var ts = new TomSelect(select, settings); + if (url) { + // Emptying the search box shouldn't list everything loaded so far (selected options are kept) + ts.on('type', function (query) { + if (query === '') { + ts.clearOptions(); + } + }); + } Object.keys(update_urls).forEach(function (value) { if (ts.options[value]) { ts.options[value].update_url = update_urls[value];