Autocomplete with Style
In my quest looking for an alternative to Select2 (which has not been updated in 5 years, leaving a pending release candidate no longer compatible with jQuery 4) I've found autoComplete.js, an autocomplete JS library with a mundane name but with wide margins for customization.
The only problem is that I've not found a ready-to-use Bootstrap theme for autoComplete.js, and I had to figure out how to place proper CSS classes in the proper configuration attributes and functions. The following is an annotation for future myself needing to use this component again.
With this addictional CSS, I provide to configure the wrapping HTML node (provided by autoComplete.js):
.autoComplete_wrapper {
position: relative;
.list-group-item {
cursor: pointer;
}
}The relevant initialization JS:
let target_selector = '.my-target-css-class';
new autoComplete({
selector: target_selector,
data: {
src: async (query) => {
try {
// Get the URL from an HTML attribute.
// In this example, it returns something like:
// {
// "results": [
// {
// "id": 1,
// "text": "foo",
// },
// {
// "id": 2,
// "text": "bar",
// }
// ]
// }
let url = $(target_selector).attr('data-remote-url');
const source = await fetch(url + '?term=' + query);
const data = await source.json();
return data.results;
}
catch (error) {
return error;
}
},
keys: ['text'],
results: (list) => {
// Remove duplicates. Here "text" is the part to be compared
const filteredResults = Array.from(new Set(list.map((value) => value.text))).map((prev) => {
return list.find((value) => value.text === prev);
});
return filteredResults;
}
},
resultsList: {
// The list is in position:absolute but the wrapping
// .autoComplete_wrapper needs to be in position:relative
class: 'list-group position-absolute w-100',
},
resultItem: {
class: 'list-group-item p-2',
highlight: 'active',
selected: 'active',
element: (item, data) => {
item.innerHTML = data.value.text;
},
},
});
// To do something when an item is selected
$(target_selector).on('selection', (e) => {
$(e.currentTarget).val(e.originalEvent.detail.selection.value.text);
console.log(e.originalEvent.detail.selection.value);
});The target HTML is as obvious as:
<input type="text" class="form-control my-target-css-class" data-remote-url="/my/endpoint" />