Gå til innhold

Adressesøk (address-autocomplete)

Gjenbrukbar, presentasjonell søkefelt-komponent for verdensomspennende sted-/firma-/ adressesøk via Google Places, bygget for docs/address-autocomplete/ADDRESS_AUTOCOMPLETE_PLAN.md. Brukeren søker på et firmanavn (f.eks. «Bruusgaard AS»), et sted, eller en gateadresse hvor som helst i verden. Ved valg av et treff løser komponenten hele adressen og emitterer et parset resultat — verten (host) mapper feltene inn i sitt eget skjema.

Komponenten er presentasjonell og skrivebeskyttet: den skriver aldri direkte til ePortal. Google-oppslaget går gjennom en server-side proxy (GooglePlacesController, Slice S1) — Google- API-nøkkelen når aldri nettleseren. Autocomplete er strengt additiv: manuell utfylling av vertens egne felt fungerer alltid, uavhengig av om Google-søket er slått på for tenanten.

Status per Slice S2 (2026-07-18): komponenten, den rene parseren og toAlpha3()-hjelperen er levert og enhetstestet. Den er ikke koblet inn i leveringsadresse-velgeren eller CRM- adresseskjemaene ennå — det er planens Slice S3 (masterordre) og S4 (CRM), som per plan §14 også må levere sin egen alpha-3-persistens-test (§6.4) uavhengig av rekkefølge.


Feature-tabell

Komponent Selector Hovedfunksjon Import
AddressAutocompleteComponent app-address-autocomplete Debounced søkefelt mot Google Places (proxy), viser treff, løser full adresse ved valg og emitterer et parset resultat Standalone

Kildefiler

Del Sti
Komponent ui/ePortal.ui/src/app/components/shared/address-autocomplete/address-autocomplete.component.ts
Mal ui/ePortal.ui/src/app/components/shared/address-autocomplete/address-autocomplete.component.html
Ren parser ui/ePortal.ui/src/app/components/shared/address-autocomplete/address-autocomplete.helpers.ts
Tester address-autocomplete.component.spec.ts, address-autocomplete.helpers.spec.ts (samme mappe)
Frontend-klient mot proxyen ui/ePortal.ui/src/app/services/google-places.service.ts
Modelltype AutocompleteAddress i ui/ePortal.ui/src/app/shared/models.ts
Alpha-2 → alpha-3-hjelper toAlpha3() i ui/ePortal.ui/src/app/components/shared/delivery-address-picker/delivery-address-picker.helpers.ts (mirror av eksisterende toAlpha2() — samlet ett sted for å unngå duplikat)
Backend-proxy (Slice S1) api/ePortal.API/ePortal.API/Controllers/GooglePlacesController.csGET capability, POST autocomplete, POST details

Komponenten er standalone — importer klassen direkte i vertens imports. Den bruker ng-select (appendTo="body") for treff-nedtrekket, samme mønster som leveringsadresse-velgeren og Brønnøysund-søket i CRM-kundeskjemaet.


Bruk

<app-address-autocomplete
  [label]="'Module.searchAddressLabel' | translate"
  (addressSelected)="onAutocomplete($event)"
  (searchCleared)="onAutocompleteCleared()">
</app-address-autocomplete>
onAutocomplete(addr: AutocompleteAddress): void {
  // Host maps the emitted fields into its own form — the component never writes anything itself.
  this.manualDraft = {
    ...this.manualDraft,
    name: addr.name ?? this.manualDraft.name,
    line1: addr.line1,
    line2: addr.line2,
    postalCode: addr.postalCode,
    city: addr.city,
    countryCode: addr.countryCode   // alpha-2 — convert with toAlpha3() for an alpha-3 column
  };
}

Inputs

Input Type Standard Beskrivelse
disabled boolean false Deaktiverer feltet (f.eks. mens verten lagrer).
placeholder string \| null null Overstyrer standard-placeholder (AddressAutocomplete.searchPlaceholder).
label string \| null null Valgfri feltetikett. Uten den brukes en usynlig (visually-hidden) etikett for skjermlesere.
countryRestriction string[] \| null null Reservert for en fremtidig utvidelse — se «Kjente fallgruver» under. Har ingen effekt i dag, fordi S1-proxyens autocomplete-forespørsel ikke tar imot en landrestriksjon per kall (kun tenant-innstillingen Integrations.GooglePlaces.CountryRestriction, eksponert read-only via capability).

Outputs

Output Type Beskrivelse
addressSelected EventEmitter<AutocompleteAddress> Emitteres én gang når brukeren velger et treff og Place Details er løst opp.
searchCleared EventEmitter<void> Emitteres når feltet tømmes — lar verten nullstille avhengig UI.

Modelltype

// shared/models.ts
interface AutocompleteAddress {
  name: string | null;              // firma-/stednavn — kun satt for et establishment-treff
  line1: string | null;             // "<gate> <husnummer>" i norsk rekkefølge
  line2: string | null;             // subpremise/etasje — aldri diktet opp
  postalCode: string | null;
  city: string | null;              // postal_town -> locality -> sublocality, første tilstede
  countryCode: string | null;       // ISO 3166-1 alpha-2 (Google country.shortText)
  latitude?: number | null;
  longitude?: number | null;
  placeId?: string | null;          // reservert for fremtidig audit/dedupe
  formattedAddress?: string | null; // Googles ferdigformaterte adresse — kun visning/debug
}

Oppførsel

  • Debounced søk (~300 ms), min. 3 tegn før et Autocomplete-kall sendes — matcher Brønnøysund-søket i CRM-kundeskjemaet (initializeBrregTypeahead).
  • Kapabilitetssjekk ved oppstart: komponenten kaller GET GooglePlaces/capability i ngOnInit. Til svaret kommer tilbake er feltet skjult (fail-safe). Resolver kapabiliteten enabled:false (funksjonen av eller uten nøkkel for tenanten), eller feiler kallet, rendres hele komponenten som ingenting — vertens vanlige manuelle felt er den eneste input-flaten.
  • Session-token: komponenten genererer ett token per søkesesjon (crypto.randomUUID()), gjenbruker det på tvers av alle debounced Autocomplete-kall i samme søk, sender det med det ene Details-kallet ved valg, og nullstiller det etter et valg eller ved tømming — én ny Google-faktureringssesjon per faktiske søk (planens §4.3).
  • Delvis feil (ikke hard av): hvis et enkelt Autocomplete- eller Details-kall svarer enabled:false (f.eks. kvote nådd) eller feiler nettverksmessig, vises en dempet «adressesøk utilgjengelig»-hint under feltet — komponenten skjules ikke, og manuell utfylling er upåvirket.
  • Ren parser: parseGooglePlaceDetails() i address-autocomplete.helpers.ts mapper Google Place Details → AutocompleteAddress uten sideeffekter. Norske treff har ofte både postal_town og localitypostal_town foretrekkes (feil by ellers for mange norske postnummerområder).
  • Land — ingen automatisk konvertering i komponenten: countryCode emitteres alpha-2 rett fra Google. Skriver verten inn i en alpha-3-kolonne (f.eks. CRM-adressekortets wv_ActorAdr.actaCountry char(3)), MÅ verten kalle toAlpha3() før patchValue()app-country-select.writeValue() løser kun opp for visning, den skriver aldri den normaliserte koden tilbake til skjemaets modellverdi.
  • Manuelt overstyr vinner alltid: alle felt forblir redigerbare etter et valg — søket bistår, det låser aldri et felt (planens §6.5).

i18n

Alle brukerrettede tekster ligger under AddressAutocomplete.* i både no.json og en.json (blokken er en-speilet). Sentrale nøkler:

"AddressAutocomplete": {
  "searchLabel":        "Søk etter adresse, sted eller firma",
  "searchPlaceholder":  "Søk etter adresse, sted eller firma …",
  "typeToSearchHint":   "Skriv minst 3 tegn for å søke",
  "poweredByGoogle":    "Søket bruker Google Places",
  "searchUnavailable":  "Adressesøk er ikke tilgjengelig akkurat nå — skriv adressen manuelt"
}

Tilgjengelighet og mobil

  • ng-select med appendTo="body" — tastaturnavigasjon og søk som standard, klippes ikke av skuff-/modal-scrolling.
  • Uten en gitt label-input rendres en visually-hidden etikett for skjermlesere, og ng-select får [attr.aria-label] satt til samme tekst.
  • Den dempede «Google-powered»/«utilgjengelig»-hinten er ren tekst, ingen dekorativ farge som strider mot fargereglene i CLAUDE.md.

Kjente fallgruver

Fallgruve Riktig mønster
Anta at countryRestriction-inputen faktisk begrenser søket Den er reservert for en fremtidig backend-utvidelse — S1-proxyens autocomplete-forespørsel tar i dag kun input/sessionToken. Kun tenant-innstillingen (Integrations.GooglePlaces.CountryRestriction) virker per nå.
La komponenten skrive direkte til et skjema Den er ren/skrivebeskyttet — verten lytter på addressSelected og mapper feltene selv.
Patch en alpha-3-kolonne med addr.countryCode uten konvertering countryCode er alltid alpha-2. Kall toAlpha3() (fra delivery-address-picker.helpers.ts) før patchValue() på en alpha-3-kontroll.
Stole på at Google-nøkkelen er tilgjengelig i nettleseren Den er det aldri — alt går via GooglePlacesController-proxyen (Slice S1).
Vise komponenten uten kapabilitetssjekk enabled starter som null (skjult) til capability-kallet svarer; ikke render feltet før det er avklart.

Verifiseringspunkter

  1. Med Integrations.GooglePlaces.Enabled = false (eller ingen nøkkel) for tenanten: importer komponenten på en testside — feltet skal ikke rendres i det hele tatt.
  2. Med funksjonen slått på: søk på et firmanavn — treffene skal vise primær-/sekundærtekst; velg et treff — addressSelected skal emitteres med parsede felt og countryCode alpha-2.
  3. Skriv under 3 tegn — ingen nettverkskall skal utløses (GooglePlacesService.autocomplete kalles ikke).
  4. Simuler et kvote-/feilsvar fra proxyen — feltet skal forbli synlig med en dempet «utilgjengelig»-hint, ikke skjules eller kaste en feil.

Relaterte sider