Ok so I’will post here the code, it’s really simple use it !
It was developed by @yisrael-wix on a my simple idea and of David - skeptisch.net .
Next I tuned the code in order to make it modular. You ca use it for one or more dropdown menu.
-
So you need in the principal Page of one (or more) text_input and a repeater (to realize the menu). In the repeated elements of repeater you need: one text box and one container box (to realize the background of the field).
-
In the page you have to write a really simple page routine to set the variables and to invoke the main routine in /public/menu_input.js
-
in /pubblic the main routine menu_input.js
-
a collection in the database, OR set an array static data
PAGE ROUTINE
import {menu_input} from 'public/menu_input.js'
$w.onReady( function () {
/****************************************/
/* set repeater (liste dinamiche) */
/****************************************/
let input1 =$w('#input1')
let repeater1 =$w('#repeater1')
// le seguenti voci non usano $w() perchè andranno richiamate con $item() in menu_input.js
let container1 = '#container1'
let voce1 = '#text1'
let sfondo1 = '#box1'
/**********************************/
/* set the input collections */
/**********************************/
// crea i riferimenti della collezione nel dbase
let collezione1 = 'Producers'
let campo1 = 'nominativo'
/********************************************************/
/* invoke the same function for the different repeaters */
/********************************************************/
menu_input (input1,repeater1,container1,voce1,sfondo1,collezione1,campo1)
});
MAIN ROUTINE /public/menu_input.js
import wixData from 'wix-data';
/********************************************************/
/******* FUNZIONE MENU SEARCH & NAVIGATOR ARRAY ****/
/********************************************************/
// This project was inspired by a recent forum discussion, Highlight an item Repeater - autocomplete menu,
// between amazing users: Mauro Vento Avyno and David - skeptisch.net.
// and the principal contributor the Master Yisrael(Wix)
// Di seguito la funzione 'menu_input', richiamata dalla Home-page, è destinata a popolare i repeater dei menu a tendina con le voci ricavate dalla collezione
// I primi cinque parametri costituiscono la struttura del menu a tendina
// input == la casella di input testo
// repeater == è il nome del repeater usato per costruire il menu (liste dinamiche)
// container == è il nome del riquadro contenitore
// voce == è la singola voce del menu a tendina
// sfondo == il nome della box che da sfondo alla voce
// collezione== il nome del database || oppure una [matrice] di valori sui quali effettuare la ricerca
// campo == il nome del campo del database sul quale si effettua la ricerca (ex. 'nominativo')
export async function menu_input (input,repeater,container,voce,sfondo,collezione, campo) {
let options={suppressAuth:true,suppressHokks:true}
const HL_COLOR = "rgba(190,190,250)";
const REG_COLOR = "rgba(222,222,222)";
let listSize;
let currIndex = -1;
$w(sfondo).style.backgroundColor = REG_COLOR;
repeater.collapse()
//*********************************************************/
/* CREA 'ArraY' come l'array di elementi (_id, campo) con il quale lavorare */
//*********************************************************/
// verifica se 'collezione' contiene il nome di un dbase e se questo esiste
if (typeof(collezione)==="string" && wixData.query(collezione)) {
console.log("Esiste la collezione nel database: ",collezione)
// interroga la collezione e crea l'elemento 'ArraY'
await wixData.query(collezione)
.find()
.then( (res) => { ArraY = res.items})
}
else if
// oppure se 'collezione' è in effetti esso stesso un Array semplice, cioè se un elemento di esso è una stringa invece di un oggetto,
// in tal caso crea 'ArraY' formato da oggetti del tipo (_id, valore)
(Array.isArray(collezione) && typeof(collezione[0])==="string") {
var ArraY=[], i=0, ARRAY=[];
// predispone 'ArraY'
collezione.forEach( (el) => { ArraY.push( { [campo]:el,"_id":String(i) }); ++i })
console.log("'collezione' è un array semplice di valori",collezione)
}
// oppure se 'collezione' è un Array i cui elementi sono oggetti
else if ( Array.isArray(collezione) && typeof(collezione[0])==="object" ) {
console.log("È un oggetto: ", collezione)
var ArraY = collezione, i=0, ARRAY=[];
}
else {console.log("'collezione' non è ne un riferimento ad un database, ne un array semplice, ne una collezione di record/items")}
/*********************************************************/
/* popola le voci del menu
/* in pratica i dati ricavati */
/*********************************************************/
// carica l'array nel repeater
repeater.data=ArraY;
// appena repeater.data sarà stato caricato
// gli $item saranno pronti, sono i singoli elementi ripetuti del repeater,
// gli itemData saranno i dati caricati dall'array
// non ci resta che assegnare i singoli valori (ex. itemData.nominativo --> $w(#text1).text )
repeater.onItemReady( ($item, itemData, index) => {
$item(voce).text = itemData[campo];
console.log('ciao');
//*****************************************************/
// verifica il clik del MOUSE sull'elemento ripetuto */
//*****************************************************/
$item(container).onClick (()=>{
console.log('hai cliccato',itemData[campo]);
input.value=itemData[campo];
repeater.collapse()
})
})
//*********************************************************/
//**** CONTROLLO DELL'INPUT DA TASTIERA E DEL REPEATER */
//*********************************************************/
// aggiunge un *gestore di eventi tramite codice* alla casella input
// chiude il menu al passaggio del mouse
input.onMouseIn(() => {repeater.collapse()})
// chiude il menu all'uscita da input
input.onBlur( () => {repeater.collapse()})
// controlla ogni singolo input da tastiera e popola il menu
input.onKeyPress((event) => {
console.log(event.key)
setTimeout(() => {
if (input.value.length === 0) {
currIndex = -1;
repeater.collapse()
} else {
switch (event.key) {
case "Tab":
repeater.collapse()
break;
// Per ogni pressione del tasto freccia verrà incrementato di 1 il contatore currIndex
// Altrettanto partirà un ciclo con forEachItem(index) tra tutte le voci presenti nel repeater
// Agendo sul componente 'sfondo' la voce corrispondente al currIndex si illuminerà di un colore diverso
//***** purtoppo .style.backgroundColor NON agisce sull'elemento container ******/
case "ArrowRight":
case "ArrowDown":
if (currIndex < listSize - 1) {
currIndex += 1;
repeater.forEachItem(($item, itemData, index) => {
if (index === currIndex) {
$item(sfondo).style.backgroundColor = HL_COLOR;
} else {
$item(sfondo).style.backgroundColor = REG_COLOR;
}
});
}
else { currIndex = -1}
break;
case "ArrowLeft":
case "ArrowUp":
if (currIndex > 0) {
currIndex -= 1;
repeater.forEachItem(($item, itemData, index) => {
if (index === currIndex) {
$item(sfondo).style.backgroundColor = HL_COLOR;
} else {
$item(sfondo).style.backgroundColor = REG_COLOR;
}
});
}
else { currIndex = listSize}
break;
case "Escape":
//input.value = '';
//currIndex = -1;
repeater.collapse()
break;
//
case "Enter":
try {
console.log(repeater.data)
if (currIndex === -1) {input.value = repeater.data[0][campo]}
else {input.value = repeater.data[currIndex][campo];}
console.log("IL dato esiste")
repeater.collapse()
} catch (err) { console.log("Il dato non esiste", err)}
break;
// popola il repeater con i risultati della ricerca
default:
ARRAY=[];
currIndex = -1;
// passa in rassegna gli elementi 'valore' dell'Array
// e seleziona quelli contenenti una parte di stringa da 'input'
ArraY.forEach( (el) => { if( el[campo].toLowerCase().includes(input.value.toLowerCase()) ) {ARRAY.push(el) } } )
console.log("ARRAY = ",ARRAY)
repeater.data = [];
repeater.data = ARRAY;
listSize = ARRAY.length;
repeater.expand();
break;
}
}
}, 50) // chiude SetTimeOut
}); // chiude onKeyPress event
}
Unfortunely $item(container).onClick (()=>{… doesn’t work on PC, only on Mobile!
BUT if you replace it with for example with $item(container).onMouseIn works very well. I Believe it’s an API bug !
Anyway this is an image of the Page, let me know if it works ! Ciao 