Créer une saisie semi-automatique d'adresse
Quelqu'un remplit une adresse de livraison. Vous voulez qu'il tape quatre caractères et choisisse le bon bâtiment, et vous voulez le résultat en parties que vous pouvez stocker plutôt qu'une seule chaîne à analyser plus tard.
import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({ key: "um_live_..." });
const results = await unmap.geocoder.autocomplete("rue sainte-cath", { limit: 5, lang: "fr" });Le code ci-dessous est du TypeScript ordinaire. Pour le câblage React, Next.js, Vue ou Nuxt,
partez des recettes par cadriciel, ou copiez le composant terminé avec
npx shadcn add @unmap/geocoder.
Envoyez tout le champ, à chaque frappe
La saisie semi-automatique est faite pour cela. Tous les mots sauf le dernier doivent correspondre à un jeton entier, et le dernier est traité comme le préfixe en cours de frappe : la requête est donc tout le champ, pas le dernier mot.
const suggestions = await unmap.geocoder.autocomplete("1000 rue sainte-cath", {
limit: 5,
lang: "fr",
});Trois caractères ou moins répondent avec des lieux seulement : villes, provinces et points d'intérêt. Les adresses et les rues arrivent au quatrième caractère, délibérément, parce qu'à trois caractères presque personne ne tape un bâtiment.
Ne courez pas contre vous-même
Deux choses tournent mal dans toute saisie semi-automatique écrite à la main, et les deux produisent le même symptôme : la liste revient par à-coups à une réponse plus ancienne pendant la frappe.
Temporisez, pour ne pas interroger à chaque touche. Entre 120 et 200 ms suffisent à couper la plupart des requêtes sans que le champ paraisse lent.
Jetez les réponses dont vous ne voulez plus. Une requête pour mont peut revenir après une
requête pour montreal, et l'afficher met la mauvaise liste à l'écran. Annulez avec un
AbortSignal, et gardez aussi un compteur de génération, car une annulation qui perd la course
doit quand même être ignorée.
import type { GeocodeResult } from "@unmap/geocoding";
function makeSuggester(render: (results: GeocodeResult[]) => void) {
let generation = 0;
let inFlight: AbortController | undefined;
return async function suggest(query: string): Promise<void> {
inFlight?.abort();
const controller = new AbortController();
inFlight = controller;
const mine = ++generation;
const results = await unmap.geocoder.autocomplete(query, {
limit: 5,
signal: controller.signal,
});
// Une réponse tardive pour une frappe antérieure est jetée plutôt qu'affichée.
if (mine !== generation) return;
render(results);
};
}Annuler ne défacture pas la requête. L'annulation vous évite d'attendre la réponse; le serveur a peut-être déjà fait le travail. C'est la temporisation qui réduit le nombre d'appels. L'annulation ne fait que garder la liste correcte.
Prenez les parties, pas le libellé
La raison d'utiliser un géocodeur ici plutôt qu'un champ de texte ordinaire, c'est ce qui revient
quand quelqu'un choisit une suggestion. address porte les composants; lng et lat sont le
point.
import type { GeocodeResult } from "@unmap/geocoding";
function toFormFields(choice: GeocodeResult) {
return {
line1: [choice.address?.housenumber, choice.address?.street].filter(Boolean).join(" "),
unit: choice.address?.unit ?? "",
city: choice.address?.city ?? "",
region: choice.address?.region ?? "",
postalCode: choice.address?.postcode ?? "",
lng: choice.lng,
lat: choice.lat,
};
}Tous les champs sauf lng et lat peuvent être absents, et la raison honnête tient aux données
plutôt qu'à l'API : toutes les sources ne publient pas d'unité ni de code postal, et un résultat
de localité n'a aucune rue. Stockez ce qui est revenu; ne reconstituez pas les parties en
découpant name.
Gardez le clavier fonctionnel
Une saisie semi-automatique qui ne fonctionne qu'à la souris est cassée pour beaucoup de gens et
échoue à toute revue d'accessibilité. En bref : le champ garde le focus et porte
aria-activedescendant; la liste est un listbox et chaque ligne une option; les flèches haut
et bas déplacent l'option active; Entrée la choisit; Échap ferme la liste sans choisir. Le
composant du registre (npx shadcn add @unmap/geocoder) fait déjà tout cela, ce qui est
l'argument pour le copier plutôt que le réécrire.
Orientez la recherche vers l'utilisateur
Si vous savez à peu près où il se trouve, dites-le. focus rapproche le classement d'un point
sans rien exclure : un utilisateur de Halifax qui tape main st voit d'abord celle de Halifax et
peut toujours atteindre celle de Vancouver.
const nearMe = await unmap.geocoder.autocomplete("main st", {
focus: [-63.5752, 44.6488],
limit: 5,
});Utilisez plutôt bbox quand vous voulez vraiment dire « rien en dehors de cette zone ». La
différence n'est pas cosmétique : focus privilégie, bbox exclut.
Là où cette approche se trompe
- Les unités sont rarement dans les données. Une requête qui en nomme une revient
habituellement sans, et le résultat indique
unit_not_verifieddansmatch_reasons. Collectez l'unité dans votre propre champ. - Les routes rurales ne sont pas géocodables.
RR 2est un circuit de facteur, pas un lieu. L'API retire les termes de distribution et répond avec la communauté; voir couverture. - La saisie semi-automatique ne corrige pas les fautes de frappe. Il n'y a pas de passe floue
ici, volontairement : elle coûterait de la latence à chaque touche.
searchréessaie avec une passe tolérante aux fautes quand la passe exacte revient vide, donc un état « aucune suggestion » peut s'y replier.
Voir aussi
- API de géocodage pour les paramètres et la forme des résultats.
- Métadonnées de résultat pour
match_typeetprecision. - Recherche structurée quand vous avez déjà les parties et voulez les valider plutôt que les suggérer.