An autocomplete function with minimal dependencies is a goal. js-autocomplete is an interesting candidate. However, in testing, the functions do not appear to be firing.
The controller defines @municipals = Municipal.all.pluck(:name)
for the source data to be autocompleted.
The page includes:
<div id= "search-data" class="form-search search-data" data-municipals="<%= @municipals.to_json %>">
<%= text_field_tag :q, nil, autocomplete: :off, class: "form-control search-input", placeholder: "Search by municipality..." %>
<%= submit_tag "Search", class: "btn btn-primary button-home" %>
</div>
and at the bottom invokes <%= javascript_pack_tag 'autocomplete.js' %>
autocomplete.js is as follows
import 'js-autocomplete/auto-complete.css';
import autocomplete from 'js-autocomplete';
const autocompleteSearch = function() {
const municipals = JSON.parse(document.getElementById('search-data').dataset.municipals)
const searchInput = document.getElementById('q');
if (municipals && searchInput) {
new autocomplete({
selector: searchInput,
minChars: 1,
source: function(term, suggest){
term = term.toLowerCase();
const choices = municipals;
const matches = [];
for (let i = 0; i < choices.length; i++)
if (~choices[i].toLowerCase().indexOf(term)) matches.push(choices[i]);
suggest(matches);
},
});
}
};
export { autocompleteSearch };
and is rendered HTML does with a complied pack (abbreviated here for SO limits)
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
[...]
//# sourceMappingURL=autocomplete-b628393645bbcc3d2739.js.map
an array of municipalities is rendered in the text_field_tag
<div id= "search-data" class="form-search search-data" data-municipals="["Ajdovščina","Ankaran (Ancarano)","Apače","Beltinci","Benedikt","Bistrica ob Sotli","Bled","Bloke","Bohinj","Borovnica" [...] ;]">
<input type="text" name="q" id="q" autocomplete="off" class="form-control search-input" placeholder="Search by municipality..." />
But entering data is not firing the autocomplete.
Two questions arise:
This is not an answer that is consistent with Rails philosophy of convention over configuration.
Buut... the goal is to minimise dependencies. And the library does so.
So simply adding to the bottom of the page the script (1/6 of the weight), and the user case script for that given page
<script>
// JavaScript autoComplete v1.0.4
// https://github.com/Pixabay/JavaScript-autoComplete
[...]
</script>
<script>
var demo1 = new autoComplete({
selector: '#user_municipal_other',
minChars: 1,
source: function(term, suggest){
term = term.toLowerCase();
var choices = <%= raw @municipals %>;
var suggestions = [];
for (i=0;i<choices.length;i++)
if (~choices[i].toLowerCase().indexOf(term)) suggestions.push(choices[i]);
suggest(suggestions);
}
});
</script>
activates the script without impeding others.
The issue of quotes was a much longer process to pin down. The controller has to generate json
@municipals = Municipal.order(name: :asc).all.pluck(:name).to_json
then the javascript call raw
on the resulting array.
var choices = <%= raw @municipals %>;
Hope this helps at some point.