autocomplete: switch autocomplete.js
Turns out implementing a autocomplete widget from scratch is more tricky than expected. It's a shame no such widget has been implemented part of the HTML standart :(
This commit is contained in:
parent
68434bf446
commit
d0715b0d15
2 changed files with 75 additions and 121 deletions
|
@ -15,6 +15,8 @@
|
|||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
|
||||
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.02.min.css">
|
||||
|
||||
<title>Aquilenet: Éligibilité FTTH</title>
|
||||
<style>
|
||||
|
@ -63,13 +65,9 @@
|
|||
<div id="methodAddress" class="collapse testMethods">
|
||||
<h2 class="text-center form-title">Test d'éligibilité par adresse</h2>
|
||||
<form id="formAddressTest" method="post" action="/test/address">
|
||||
<div class="form-group" id="communeForm">
|
||||
<label class="form-label" for="communeInput">Commune</label>
|
||||
<input autocomplete="off" type="text" list="communes" name="commune" class="form-control"
|
||||
id="communeInput" ondblclick="this.focus();this.select()" aria-describedby="communeHelp"
|
||||
placeholder="Nom de la commune ou code postal">
|
||||
<datalist id="communes">
|
||||
</datalist>
|
||||
<div class="form-group row" id="communeForm">
|
||||
<label class="form-label col-sm-2 my-1" for="commune-autocomplete">Commune</label>
|
||||
<input id="commune-autocomplete" class="col-sm-9" type="search" dir="ltr" spellcheck=false autocorrect="off" autocomplete="off" class="form-control" autocapitalize="off"/>
|
||||
</div>
|
||||
<div class="form-row collapse" id="voieForm">
|
||||
<div class="col-sm-3 my-1">
|
||||
|
@ -79,12 +77,9 @@
|
|||
oninvalid="this.setCustomValidity('Veuillez renseigner le numéro de voie')"
|
||||
oninput="setCustomValidity('')">
|
||||
</div>
|
||||
<div class="col-sm-9 my-1">
|
||||
<label class="form-label" for="voieInput">Nom de voie</label>
|
||||
<input autocomplete="off" type="text" name="voie" list="voies" class="form-control" id="voieInput"
|
||||
aria-describedby="voieHelp" placeholder="Nom de voie">
|
||||
<datalist id="voies">
|
||||
</datalist>
|
||||
<div class="col-sm-7 my-1">
|
||||
<label class="form-label" for="fantoir-autocomplete">Nom de voie</label>
|
||||
<input id="fantoir-autocomplete" class="form-control" type="search" dir="ltr" spellcheck=false autocorrect="off" autocomplete="off" autocapitalize="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -131,94 +126,6 @@
|
|||
return inputStr;
|
||||
}
|
||||
|
||||
// Function to update list of communes (calls backend API)
|
||||
function updateCommunes(search = '') {
|
||||
var api = "addresses/communes?limit=15";
|
||||
if (search != '') {
|
||||
api += "&s=" + search;
|
||||
}
|
||||
fetch(api, { signalCommunes })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
valueMatch=false;
|
||||
if (JSON.stringify(data) !== JSON.stringify(communes)) {
|
||||
$("#communes").empty();
|
||||
communes = data
|
||||
communes.forEach(commune => {
|
||||
value=commune.codeZip + ' ' + commune.nom
|
||||
$("#communes").append("<option codeInsee=" + commune.codeInsee + " value='" +
|
||||
value + "'></option>");
|
||||
if (value === search) {
|
||||
valueMatch=true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (communes.length == 1 || valueMatch) {
|
||||
codeInsee = communes[0].codeInsee;
|
||||
$('#voieForm').collapse('show');
|
||||
} else {
|
||||
$('#voieInput').val('');
|
||||
$('#voieForm').collapse('hide');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("Error fetching communes:", err)
|
||||
})
|
||||
}
|
||||
|
||||
// Function to update list of voies (calls backend API)
|
||||
function updateVoies(search = '') {
|
||||
var api = "addresses/fantoirvoies/" + codeInsee + '?limit=15';
|
||||
if (search != '') {
|
||||
api += "&s=" + search;
|
||||
}
|
||||
fetch(api, { signalVoies })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
valueMatch=false;
|
||||
if (JSON.stringify(data) !== JSON.stringify(voies)) {
|
||||
$("#voies").empty();
|
||||
voies = Object.entries(data);
|
||||
let voie;
|
||||
for (i in voies) {
|
||||
voie = voies[i]
|
||||
$("#voies").append("<option value='" +
|
||||
voie[0] + "'></option>");
|
||||
if (voie[0] === search) {
|
||||
valueMatch=true;
|
||||
}
|
||||
}
|
||||
if (voies.length == 1 || valueMatch) {
|
||||
$('#btnTestAdresse').collapse('show');
|
||||
voie = voies[0]
|
||||
codeRivoli = voie[1]
|
||||
$("#voieInput").val(voie[0]);
|
||||
$('#btnTestAdresse').focus();
|
||||
} else {
|
||||
$('#btnTestAdresse').collapse('hide');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("Error fetching communes:", err)
|
||||
})
|
||||
}
|
||||
|
||||
function fetchWithBackoff (fetchFn, timeout, input) {
|
||||
if(timeout !== null) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
if (input.length < 3) {
|
||||
return null;
|
||||
}
|
||||
timeout = setTimeout(() => {
|
||||
const cleanInput = sanitizeInputStr(input);
|
||||
fetchFn(cleanInput);
|
||||
}, 100);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
$('#methodAddress').on('show.bs.collapse', function () {
|
||||
$('#communeInput').trigger('input')
|
||||
$('#communeInput').trigger('keyup')
|
||||
|
@ -234,26 +141,69 @@
|
|||
$('#numeroVoieInput').focus();
|
||||
});
|
||||
|
||||
let timeoutCommune = null;
|
||||
$('#communeInput').on('input', function () {
|
||||
controllerCommunes.abort();
|
||||
timeoutCommune = fetchWithBackoff(updateCommunes, timeoutCommune, $(this).val());
|
||||
});
|
||||
|
||||
$('#communeInput').on('input', function () {
|
||||
if ($(this).val() === '') {
|
||||
$('#voieForm').collapse('hide');
|
||||
const autoCompleteCommune = new autoComplete({
|
||||
selector: "#commune-autocomplete",
|
||||
placeHolder: "Code postal/nom de commune...",
|
||||
data: {
|
||||
src: async (query) => {
|
||||
const api = "addresses/communes?limit=100";
|
||||
const reqUrl = query === '' ? api : api + "&s=" + query
|
||||
const source = await fetch(reqUrl, { signalCommunes });
|
||||
const data = await source.json();
|
||||
return data;
|
||||
},
|
||||
keys: [ "codeZip", "nom" ],
|
||||
},
|
||||
resultList: {
|
||||
element: (list, data) => {
|
||||
}
|
||||
},
|
||||
resultItem: {
|
||||
highlight: true
|
||||
},
|
||||
debounce: 300,
|
||||
events: {
|
||||
input: {
|
||||
selection: (event) => {
|
||||
const selection = event.detail.selection.value;
|
||||
autoCompleteCommune.input.value = selection.codeZip + " - " + selection.nom ;
|
||||
codeInsee = selection.codeInsee;
|
||||
$("#voieForm").collapse("show");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let timeoutVoie = null;
|
||||
$('#voieInput').on('input', function () {
|
||||
controllerVoies.abort();
|
||||
timeoutVoie = fetchWithBackoff(updateVoies, timeoutVoie, $(this).val());
|
||||
});
|
||||
$('#voieInput').on('input', function () {
|
||||
if ($(this).val() === '') {
|
||||
$('#btnTestAdresse').collapse('hide');
|
||||
const autoCompleteFantoir = new autoComplete({
|
||||
selector: "#fantoir-autocomplete",
|
||||
placeHolder: "Nom de la voie...",
|
||||
data: {
|
||||
src: async (query) => {
|
||||
const api = "addresses/fantoirvoies/" + codeInsee + "?limit=100";
|
||||
const reqUrl = query === '' ? api : api + "&s=" + query
|
||||
const source = await fetch(reqUrl, { signalVoies });
|
||||
const data = await source.json();
|
||||
return Object.entries(data).map(e => {return {"name": e[0], "value": e[1]}; });
|
||||
},
|
||||
keys: [ "name" ],
|
||||
},
|
||||
resultList: {
|
||||
element: (list, data) => {
|
||||
}
|
||||
},
|
||||
resultItem: {
|
||||
highlight: true
|
||||
},
|
||||
debounce: 300,
|
||||
events: {
|
||||
input: {
|
||||
selection: (event) => {
|
||||
const selection = event.detail.selection.value;
|
||||
autoCompleteFantoir.input.value = selection.name;
|
||||
codeRivoli = selection.value;
|
||||
$('#btnTestAdresse').collapse('show');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -72,6 +72,10 @@ body {
|
|||
text-shadow: dimgray 0 1px 1px;
|
||||
background-image: linear-gradient(to bottom, #ffd38c 0%, #ffedd0 51%, #e0e0e0 100%);
|
||||
}
|
||||
|
||||
/* Autocomplete */
|
||||
|
||||
|
||||
/* #fda085 51%, */
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue