Category Archives: JSON

Vejdirektoratet og kommunerne lancerer nyt KommuneAtlas

​Vejdirektorat og kommunerne har i fællesskab lanceret et digitalt KommuneAtlas med nøgletal om det danske vejnet. Det digitale KommuneAtlas giver alle interesserede mulighed for at danne egne faktakort og trække data inden for udvalgte temaer.

Den primære målgruppe er medarbejdere og ledere i kommunerne og Vejdirektoratet. Hertil kommer det politiske niveau samt borgere og trafikanter, der nås gennem samarbejdet.

Formålet med det digitale KommuneAtlas er at give et helhedsorienteret billede af vejnettet. Det nye digitale KommuneAtlas findes på adressen kommuneatlas.samkom.dk

Applikationen er videreudviklingen af SAMKOM publikationen “KommuneAtlas – kort om veje og trafik”, som er udkommet i 2003, 2004 og 2010.

I Hinnerup Net er vi stolte over resultatet af den tekniske indsats der er leveret i anledningen – og ser frem også at implementere til de udvidelser og forbedringer, der allerede er planlagt.

 

Autocomplete med Ajax på adresse med jQuery og OIO

Indtastning af adresseoplysninger er notorisk noget bøvlet: Der er flere indbyrdes forbundne felter og erfaringsvis opstår der meget hurtigt mangel på sammenhæng – hvilket fører til manuelle processer for opfølgning og fejlretning, for ikke at glemme muligheden for tabte forsendelser.

Heldigvis har den offentlige digitalisering i danmark resulteret i gratis & ubetinget adgang til services, der kan sammensættes til en gevaldig hjælp i forhold til at ramme rigtigt: Med et par kombinationer af jQuery, Ajax, JSONP og autocomplete er det muligt ud fra et delvist vejnavn at få postnummer og bynavn givet, med samt en liste over gyldige vejnumre.

Herunder et eksempel på et sæt adressefelter der hjælper hvor hjælpes kan. Prøv eventuelt først at taste vejnavn og lade autocomplete klare “resten” – og derefter i postnummerfeltet at skrive et nyt/andet postnummer og derefter konstatér, at autocomplete i vejnavne-feltet nu kun giver navne i det pågældende postnummer.









Givet, at de rette inkludes er gjort, kan den fulde funktionalitet af ovenstående implementeres med et kald ala

$().ready(function() {
  $("#streetname").autocompleteAddress();
});

Ovenstående under forudsætning af at der er defineret input felter i HTML’en som herunder.

<div class="ui-widget"> 
	<label for="streetname">Vejnavn: </label> 
	<input type="text" name="streetname" id="streetname"/>
	<label for="streetnumber">Nr.: </label> 
	<input type="text" name="streetnumber" id="streetnumber" size="4" />
</div>
<div class="ui-widget"> 
	<label for="zipcode">Postnummer: </label> 
	<input type="text" name="zipcode" id="zipcode" size="4"  />
	<input type="text" name="city" id="city" size="45" disabled="disabled" />
</div>

Såfremt det ønskes at benytte andre feltnavne/id’er en de her angivne, kan de angives eksplicit:

  $("#streetname").autocompleteAddress({
    streetNumber: "#streetnumber",
    zipCode : "#zipcode",
    city: "#city"
});

Såfremt en eller flere af adresse-felterne ikke kan findes (eller angives med null i argumentet) udelades autocomplete-funktionaliteten for dét. Særligt er tilfældet, hvor det eksempelvis kun ønskes at benytte plugin’et til at lave autocomplete på postnummer/bynavn: Her skal blot sørges for, at instantiere fra et vilkårligt element der IKKE er et input felt (eksempelvis “body”).

Værd at bemærke er også følgende options:

matchAnywhere Default: false
Afgør hvorvidt det indtastede kan matche et vilkårligt sted i vejnavnet (true), eller kun i begyndelsen (false).

maxSuggestions Default: 12
Angiver hvor mange valgmuligheder der maksimalt vises.

De nødvendige inkludes er “de gængse” for brug af jQuery og tilhørende UI, med tilføjelse af en lille smule bogholderi (style) og den til formålet udviklede widget: autocompleteAddress.js.

<link rel="stylesheet" href="http://code.jquery.com/ui/1.8.13/themes/base/jquery-ui.css"> 
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="http://code.jquery.com/ui/1.8.13/jquery-ui.min.js"></script>
<script src="http://www.hinnerup.net/2011/06/oiorest/jquery.ui.plugin_autocompleteAddress.js"></script>
<link rel="stylesheet" href="jquery.ui.plugin_autocompleteAddress.css"> 

Bag kulisserne er der tale om, at jQuery UI’s autocomplete er kædet til JSONP opslag mod “.json”-udgaverne af OIO’s REST-baserede webservices, jævnfør deres dokumentation for henholdsvis Vejnavne, Adresser og Postnummer.

Værd at bemærke er, at OIO’s implementation af vejnavne-servicen returnerer resultater på matches hvorsomhelst i navnet – og i autocomplete sammenhæng er det mest intuitive for de fleste formentlig at det er starten af vejnavnet man søger på. Såfremt matchAnywhere er false, ganges maxSuggestions med to ved opslag til Geoservicen, for at tilstræbe at “have nok”, når overflødige resultater frasorteres (idet Geoservicen kun understøtter søgninger af typen “matchAnywhere”). Det har den uheldige effekt, at idet 2 og 3 bogstavskombinationer forekommer i rigtig mange vejnavne, vil de første (mange) resultater fra OIO ofte IKKE være med matches i begyndelsen – hvorfor autocomplete ikke altid udnyttes af plugin’et. Bemærk, at denne uhensigtsmæssighed vil kunne omgås ved blot at fjerne maxantal begrænsningen på kaldet mod OIO – med performance fald som den eneste pris.

Situationen kan eksemplificeres ved i ovenstående at lave søgning efter eksempelvis “Bygm” og “By” henholdsvis med og uden at have angivet postnummeret “2400”.

Rent praktisk håndteres sagen i koden med kald af .filter og derefter .slice som illustreret herunder.

var serviceUri = "http://geo.oiorest.dk/vejnavne.json";
var serviceArguments = {
	/* Note; Custom filtering on success may reduce this */
	maxantal: matchAnywhere ? maxSuggestions : eStreetName.val().length < 4 ? 20*maxSuggestions : 2*maxSuggestions ,
	vejnavn: request.term
};

if(eZipCode.length) {
	var zipCode = eZipCode.val();
	if(zipCode.length == 4) {
		serviceArguments.postnr = zipCode;
	}
}

$.ajax({
	url: serviceUri,
	dataType: "jsonp",
	data: serviceArguments,
	success: function( data ) {
		if(!matchAnywhere) {
			//Remove matches that are not in the beginning of navn
			data = data.filter(function (vej) {
				var pattern = new RegExp("^" + eStreetName.val(), "i");
				return pattern.test(vej.navn);
			});
		}
		
		//Reduce to max number of suggestions for display
		data = data.slice(0, maxSuggestions); 

		//Map OIO object to label/value for jQuery autocomplete
		data = $.map(data, function( vej ) {
			return {
				label: vej.navn + " (" + vej.postnummer.nr + ")",
				value: vej.navn
			}
		})
		
		response(data);
	}
});

For optimering af brugeroplevelsen benyttes kun et enkelt opslag i forhold til autocomplete af vejnummeret – resultatet caches lokalt. Dette muliggør både en mere logisk sortering end den alfanumeriske (1, 10, 11, 2a, 20 …) som OIO leverer data i. Desuden omgås derved det “problem” der ligger i at adressse-servicen hos OIO matcher eksakt på husnummer-angivelse, og dermed ikke i udgangspunktet er synderligt velegnet til den nærværende autocomplete-anvendelse.

Dette plugin er tilføjet jQuery repository med navnet autocompleteAddress.

Øverst på listen over kommende features står:

  • Version 1.5 (?)
    • Forslag modtages gerne!
  • Version 1.4 (2011-08-22)
    • Sortering på vejnavn/postnummer tilføjet
  • Version 1.3 (2011-07-27)
    • Optimeret mapning og filtrering af vejnavne & numre
    • Optimeret parsning og sortering af vejnumre
    • Optimeret logik omkring maxantal (tilføjet missFactor)
    • Tilføjet “caller id” til alle requests mod Geoservien
  • Version 1.2 (2011-07-04)
    • Logisk sortering af husnumre (tak til Michael Schøler)
    • Mere intelligent håndtering af opslag til OIO vedrørende maxantal ved matchAnywhere = false
    • Stylesheet opsætning udtrukket til separat fil
  • Version 1.1 (2011-06-28)
    • Valgfri anvendelse af de 4 adressefelter
    • Valgfri angivelse af metode for selektion af vejnavne (start|alle)
    • Valgfri angivelse af maks antal indgange i dropdown
  • Version 1.0 (2011-06-23)
    • Første version

Yderligere forslag og kommentarer er meget velkomne.

Bug i JavaScript eller er weekenden bare for nær?

Jeg er stødt på noget rimelig besynderligt i dag – JavaScript fortolkeren i IE6, IE7 og FF2 opfører sig nemlig tilsyneladende sært når man opretter selvrefererende JavaScript Object Notation (JSON) objekter.

JSON screenshot fra Firebug

Betragt den første variabeltilskrivning jeg udfører i Firebug konsollen i Firefox:

>>> var json = { "foo": 42 };

Den evaluerer til et objekt der indeholder:

>>> json
Object foo=42

Hvis vi gerne vil have oprettet et JSON objekt der refererer til sig selv, kan man angive f.eks.:

>>> var json = { "foo": 42, "selfRef": json.foo };

Hvilket evaluerer til et objekt der indeholder:

>>> json
Object selfRef=42 foo=42

Omskriver man det en smule, så property’en foo tilgås på array form bliver værditilskrivningen til:

>>> var json = { "foo": 42, "selfRef": json["foo"] };

Og det går det lige så fint med, da det også evaluerer til:

>>> json
Object selfRef=42 foo=42

Filmen lader dog til at knække helt hvis den nøgle man anvender er et tal, hvilket er fint gyldigt iøvrigt:

>>> var json = { "2": 42, "selfRef": json["2"] };

Nu har vi nemlig kun objektet:

>>> json
Object 2=42

Så jeg tænkte at jeg enten havde fundet en generel implementationsfejl i JavaScript fortolkerne i IE og FF (hvilket må siges at være overvejende usandsynligt), eller også er mine forsøg herover fejlbehæftede. Sidste mulighed viste sig at være årsagen.

Det går nemlig fint at erklære cykliske JSON strukturer hvis de basis data der skal indgå i selvreferencerne allerede er erklærede på forhånd. Og det er de netop hvis man afprøver dette forløb:

>>> var json = { "foo": 42 };
>>> var json = { "foo": 42, "selfRef": json.foo };
>>> json
Object selfRef=42 foo=42

Hvis json.foo ikke indledningsvist havde været erklæret fejler den selvreferende erklæring:

>>> var json = { "foo": 42 };
>>> var json = "";
>>> var json = { "foo": 42, "selfRef": json.foo };
>>> json
Object foo=42

Så det var udelukkende på grund af weekenden der var lige om hjørnet, og fordi forsøget på at indsætte en hidtil utilskrevet talnøgle i JSON strukturen gjorde at “fejlen” fremstod. Man kan dog fortsat være lidt tvivlende overfor hvordan en tilskreven property bare kan forsvinde ud i den blå luft. Man kunne forvente at selfRef som minimum var tilstede og blot indeholdt værdien "undefined" eller endnu bedre null. Alternativt havde en kastet exception også været ok.