{"id":1470,"date":"2011-06-23T13:04:52","date_gmt":"2011-06-23T12:04:52","guid":{"rendered":"http:\/\/www.hinnerup.net\/?p=1470"},"modified":"2014-02-03T16:17:15","modified_gmt":"2014-02-03T15:17:15","slug":"autocomplete-med-ajax-paa-adresse-med-jquery-og-oio","status":"publish","type":"post","link":"https:\/\/www.hinnerup.net\/en\/permanent\/2011\/06\/23\/autocomplete-med-ajax-paa-adresse-med-jquery-og-oio\/","title":{"rendered":"Autocomplete med Ajax p\u00e5 adresse med jQuery og OIO"},"content":{"rendered":"<p><\/p>\n<p>Indtastning af adresseoplysninger er notorisk noget b\u00f8vlet: Der er flere indbyrdes forbundne felter og erfaringsvis opst\u00e5r der meget hurtigt mangel p\u00e5 sammenh\u00e6ng &#8211; hvilket f\u00f8rer til manuelle processer for opf\u00f8lgning og fejlretning, for ikke at glemme muligheden for tabte forsendelser.<\/p>\n<p>Heldigvis har den offentlige digitalisering i danmark resulteret i gratis &#038; ubetinget adgang til services, der kan sammens\u00e6ttes til en gevaldig hj\u00e6lp 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\u00e5 postnummer og bynavn givet, med samt en liste over gyldige vejnumre.<\/p>\n<p>Herunder et eksempel p\u00e5 et s\u00e6t adressefelter der hj\u00e6lper hvor hj\u00e6lpes kan. Pr\u00f8v eventuelt f\u00f8rst at taste vejnavn og lade autocomplete klare &#8220;resten&#8221; &#8211; og derefter i postnummerfeltet at skrive et nyt\/andet postnummer og derefter konstat\u00e9r, at autocomplete i vejnavne-feltet nu kun giver navne i det p\u00e5g\u00e6ldende postnummer.<\/p>\n<style>  .wp-fuckup p, .wp-fuckup br  { display: none; } .ui-autocomplete-loading { background: white url('\/2011\/06\/oiorest\/ui-anim_basic_16x16.gif') right center no-repeat; }\t#streetname { width: 25em; } <\/style>\n<div class=\"wp-fuckup\">\n<link rel=\"stylesheet\" href=\"http:\/\/code.jquery.com\/ui\/1.8.13\/themes\/base\/jquery-ui.css\">\n<script src=\"http:\/\/code.jquery.com\/jquery-latest.js\"><\/script><br \/>\n<script src=\"http:\/\/code.jquery.com\/ui\/1.8.13\/jquery-ui.min.js\"><\/script><br \/>\n<script src=\"\/2011\/06\/oiorest\/jquery.ui.plugin_autocompleteAddress.js\"><\/script><br \/>\n<script>\n\t$().ready(function() {\n\t\tjQuery(\"#streetname\").autocompleteAddress();\n\t});\n<\/script><\/p>\n<div class=\"ui-widget\">\n  <label for=\"streetname\" >Vejnavn:<\/label><br \/>\n  <input type=\"text\" name=\"streetname\" id=\"streetname\" \/><br \/>\n  <label for=\"streetnumber\">Nr.:<\/label><br \/>\n  <input type=\"text\" name=\"streetnumber\" id=\"streetnumber\" size=\"4\" \/>\n<\/div>\n<div class=\"ui-widget\">\n  <label for=\"zipcode\">Postnummer: <\/label><br \/>\n  <input type=\"text\" name=\"zipcode\" id=\"zipcode\" size=\"4\"  \/><br \/>\n  <input type=\"text\" name=\"city\" id=\"city\" size=\"45\" disabled=\"disabled\" \/><\/div>\n<\/div>\n<p>Givet, at de rette inkludes er gjort, kan den fulde funktionalitet af ovenst\u00e5ende implementeres med et kald ala<\/p>\n<pre class=\"prettyprint\">\r\n$().ready(function() {\r\n  $(&#34;#streetname&#34;).autocompleteAddress();\r\n});\r\n<\/pre>\n<p>Ovenst\u00e5ende under foruds\u00e6tning af at der er defineret input felter i HTML&#8217;en som herunder.<\/p>\n<pre class=\"prettyprint\">\r\n&lt;div class=&#34;ui-widget&#34;&gt; \r\n\t&lt;label for=&#34;streetname&#34;&gt;Vejnavn: &lt;&#47;label&gt; \r\n\t&lt;input type=&#34;text&#34; name=&#34;streetname&#34; id=&#34;streetname&#34;&#47;&gt;\r\n\t&lt;label for=&#34;streetnumber&#34;&gt;Nr.: &lt;&#47;label&gt; \r\n\t&lt;input type=&#34;text&#34; name=&#34;streetnumber&#34; id=&#34;streetnumber&#34; size=&#34;4&#34; &#47;&gt;\r\n&lt;&#47;div&gt;\r\n&lt;div class=&#34;ui-widget&#34;&gt; \r\n\t&lt;label for=&#34;zipcode&#34;&gt;Postnummer: &lt;&#47;label&gt; \r\n\t&lt;input type=&#34;text&#34; name=&#34;zipcode&#34; id=&#34;zipcode&#34; size=&#34;4&#34;  &#47;&gt;\r\n\t&lt;input type=&#34;text&#34; name=&#34;city&#34; id=&#34;city&#34; size=&#34;45&#34; disabled=&#34;disabled&#34; &#47;&gt;\r\n&lt;&#47;div&gt;<\/pre>\n<p>S\u00e5fremt det \u00f8nskes at benytte andre feltnavne\/id&#8217;er en de her angivne, kan de angives eksplicit:<\/p>\n<pre class=\"prettyprint\">\r\n  $(&#34;#streetname&#34;).autocompleteAddress({\r\n    streetNumber: &#34;#streetnumber&#34;,\r\n    zipCode : &#34;#zipcode&#34;,\r\n    city: &#34;#city&#34;\r\n});\r\n<\/pre>\n<p>S\u00e5fremt en eller flere af adresse-felterne ikke kan findes (eller angives med null i argumentet) udelades autocomplete-funktionaliteten for d\u00e9t. S\u00e6rligt er tilf\u00e6ldet, hvor det eksempelvis kun \u00f8nskes at benytte plugin&#8217;et til at lave autocomplete p\u00e5 postnummer\/bynavn: Her skal blot s\u00f8rges for, at instantiere fra et vilk\u00e5rligt element der IKKE er et input felt (eksempelvis &#8220;body&#8221;).<\/p>\n<p>V\u00e6rd at bem\u00e6rke er ogs\u00e5 f\u00f8lgende options:<\/p>\n<p><b>matchAnywhere<\/b> Default: false<br \/>\nAfg\u00f8r hvorvidt det indtastede kan matche et vilk\u00e5rligt sted i vejnavnet (true), eller kun i begyndelsen (false).<\/p>\n<p><b>maxSuggestions<\/b> Default: 12<br \/>\nAngiver hvor mange valgmuligheder der maksimalt vises. <\/p>\n<p>De n\u00f8dvendige inkludes er &#8220;de g\u00e6ngse&#8221; for brug af jQuery og tilh\u00f8rende UI, med tilf\u00f8jelse af en lille smule bogholderi (style) og den til form\u00e5let udviklede widget: <a href=\"\/2011\/06\/oiorest\/jquery.ui.plugin_autocompleteAddress.js\">autocompleteAddress.js<\/a>.<\/p>\n<pre class=\"prettyprint\">\r\n&lt;link rel=&#34;stylesheet&#34; href=&#34;http:&#47;&#47;code.jquery.com&#47;ui&#47;1.8.13&#47;themes&#47;base&#47;jquery-ui.css&#34;&gt; \r\n&lt;script src=&#34;http:&#47;&#47;code.jquery.com&#47;jquery-latest.js&#34;&gt;&lt;&#47;script&gt;\r\n&lt;script src=&#34;http:&#47;&#47;code.jquery.com&#47;ui&#47;1.8.13&#47;jquery-ui.min.js&#34;&gt;&lt;&#47;script&gt;\r\n&lt;script src=&#34;http:&#47;&#47;www.hinnerup.net&#47;2011&#47;06&#47;oiorest&#47;jquery.ui.plugin_autocompleteAddress.js&#34;&gt;&lt;&#47;script&gt;\r\n&lt;link rel=&#34;stylesheet&#34; href=&#34;jquery.ui.plugin_autocompleteAddress.css&#34;&gt; \r\n<\/pre>\n<p>Bag kulisserne er der tale om, at <a href=\"http:\/\/jqueryui.com\/demos\/autocomplete\/#remote-jsonp\">jQuery UI&#8217;s autocomplete er k\u00e6det til JSONP opslag<\/a> mod &#8220;.json&#8221;-udgaverne af OIO&#8217;s REST-baserede webservices, j\u00e6vnf\u00f8r deres dokumentation for henholdsvis <a href=\"http:\/\/geo.oiorest.dk\/documentation\/api\/vej.aspx\">Vejnavne<\/a>, <a href=\"http:\/\/geo.oiorest.dk\/documentation\/api\/adresse.aspx\">Adresser <\/a>og <a href=\"http:\/\/geo.oiorest.dk\/documentation\/api\/postnummer.aspx\">Postnummer<\/a>.<\/p>\n<p>V\u00e6rd at bem\u00e6rke er, at OIO&#8217;s implementation af vejnavne-servicen returnerer resultater p\u00e5 matches hvorsomhelst i navnet &#8211; og i autocomplete sammenh\u00e6ng er det mest intuitive for de fleste formentlig at det er starten af vejnavnet man s\u00f8ger p\u00e5. S\u00e5fremt matchAnywhere er false, ganges maxSuggestions med to ved opslag til Geoservicen, for at tilstr\u00e6be at &#8220;have nok&#8221;, n\u00e5r overfl\u00f8dige resultater frasorteres (idet Geoservicen kun underst\u00f8tter s\u00f8gninger af typen &#8220;matchAnywhere&#8221;). Det har den uheldige effekt, at idet 2 og 3 bogstavskombinationer forekommer i rigtig mange vejnavne, vil de f\u00f8rste (mange) resultater fra OIO ofte IKKE v\u00e6re med matches i begyndelsen &#8211; hvorfor autocomplete ikke altid udnyttes af plugin&#8217;et. Bem\u00e6rk, at denne uhensigtsm\u00e6ssighed vil kunne omg\u00e5s ved blot at fjerne maxantal begr\u00e6nsningen p\u00e5 kaldet mod OIO &#8211; med performance fald som den eneste pris. <\/p>\n<p>Situationen kan eksemplificeres ved i ovenst\u00e5ende at lave s\u00f8gning efter eksempelvis &#8220;Bygm&#8221; og &#8220;By&#8221; henholdsvis med og uden at have angivet postnummeret &#8220;2400&#8221;.<\/p>\n<p>Rent praktisk h\u00e5ndteres sagen i koden med kald af .filter og derefter .slice som illustreret herunder.<\/p>\n<pre class=\"prettyprint\">\r\nvar serviceUri = &#34;http:&#47;&#47;geo.oiorest.dk&#47;vejnavne.json&#34;;\r\nvar serviceArguments = {\r\n\t&#47;* Note; Custom filtering on success may reduce this *&#47;\r\n\tmaxantal: matchAnywhere ? maxSuggestions : eStreetName.val().length &lt; 4 ? 20*maxSuggestions : 2*maxSuggestions ,\r\n\tvejnavn: request.term\r\n};\r\n\r\nif(eZipCode.length) {\r\n\tvar zipCode = eZipCode.val();\r\n\tif(zipCode.length == 4) {\r\n\t\tserviceArguments.postnr = zipCode;\r\n\t}\r\n}\r\n\r\n$.ajax({\r\n\turl: serviceUri,\r\n\tdataType: &#34;jsonp&#34;,\r\n\tdata: serviceArguments,\r\n\tsuccess: function( data ) {\r\n\t\tif(!matchAnywhere) {\r\n\t\t\t&#47;&#47;Remove matches that are not in the beginning of navn\r\n\t\t\tdata = data.filter(function (vej) {\r\n\t\t\t\tvar pattern = new RegExp(&#34;^&#34; + eStreetName.val(), &#34;i&#34;);\r\n\t\t\t\treturn pattern.test(vej.navn);\r\n\t\t\t});\r\n\t\t}\r\n\t\t\r\n\t\t&#47;&#47;Reduce to max number of suggestions for display\r\n\t\tdata = data.slice(0, maxSuggestions); \r\n\r\n\t\t&#47;&#47;Map OIO object to label&#47;value for jQuery autocomplete\r\n\t\tdata = $.map(data, function( vej ) {\r\n\t\t\treturn {\r\n\t\t\t\tlabel: vej.navn + &#34; (&#34; + vej.postnummer.nr + &#34;)&#34;,\r\n\t\t\t\tvalue: vej.navn\r\n\t\t\t}\r\n\t\t})\r\n\t\t\r\n\t\tresponse(data);\r\n\t}\r\n});\r\n<\/pre>\n<p>For optimering af brugeroplevelsen benyttes kun et enkelt opslag i forhold til autocomplete af vejnummeret &#8211; resultatet caches lokalt. Dette muligg\u00f8r b\u00e5de en mere logisk sortering end den alfanumeriske (1, 10, 11, 2a, 20 &#8230;) som OIO leverer data i. Desuden omg\u00e5s derved det &#8220;problem&#8221; der ligger i at adressse-servicen hos OIO matcher eksakt p\u00e5 husnummer-angivelse, og dermed ikke i udgangspunktet er synderligt velegnet til den n\u00e6rv\u00e6rende autocomplete-anvendelse.<\/p>\n<p>Dette <a href=\"http:\/\/plugins.jquery.com\/project\/autocompleteAddress\">plugin er tilf\u00f8jet jQuery repository med navnet autocompleteAddress<\/a>. <\/p>\n<p>\u00d8verst p\u00e5 listen over kommende features st\u00e5r:<\/p>\n<ul>\n<li><strong>Version 1.5 (?)<\/strong>\n<ul>\n<li>Forslag modtages gerne!<\/li>\n<\/ul>\n<\/li>\n<li><strong>Version 1.4 (2011-08-22)<\/strong>\n<ul>\n<li>Sortering p\u00e5 vejnavn\/postnummer tilf\u00f8jet<\/li>\n<\/ul>\n<\/li>\n<li><strong>Version 1.3 (2011-07-27)<\/strong>\n<ul>\n<li>Optimeret mapning og filtrering af vejnavne &#038; numre<\/li>\n<li>Optimeret parsning og sortering af vejnumre<\/li>\n<li>Optimeret logik omkring maxantal (tilf\u00f8jet missFactor)\n<li>Tilf\u00f8jet &#8220;caller id&#8221; til alle requests mod Geoservien<\/li>\n<\/ul>\n<\/li>\n<li><strong>Version 1.2 (2011-07-04)<\/strong>\n<ul>\n<li>Logisk sortering af husnumre (tak til Michael Sch\u00f8ler)<\/li>\n<li>Mere intelligent h\u00e5ndtering af opslag til OIO vedr\u00f8rende maxantal ved matchAnywhere = false<\/li>\n<li>Stylesheet ops\u00e6tning udtrukket til separat fil<\/li>\n<\/ul>\n<\/li>\n<li><strong>Version 1.1 (2011-06-28)<\/strong>\n<ul>\n<li>Valgfri anvendelse af de 4 adressefelter <\/li>\n<li>Valgfri angivelse af metode for selektion af vejnavne (start|alle)<\/li>\n<li>Valgfri angivelse af maks antal indgange i dropdown<\/li>\n<\/ul>\n<\/li>\n<li><strong>Version 1.0 (2011-06-23)<\/strong>\n<ul>\n<li>F\u00f8rste version<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Yderligere forslag og kommentarer er meget velkomne.<\/p>\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Indtastning af adresseoplysninger er notorisk noget b\u00f8vlet: Der er flere indbyrdes forbundne felter og erfaringsvis opst\u00e5r der meget hurtigt mangel p\u00e5 sammenh\u00e6ng &#8211; hvilket f\u00f8rer til manuelle processer for opf\u00f8lgning og fejlretning, for ikke at glemme muligheden for tabte forsendelser. Heldigvis har den offentlige digitalisering i danmark resulteret i gratis &#038; ubetinget adgang til services, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2128,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,72,5,4],"tags":[82,108,119,124,121,81,80,77],"class_list":["post-1470","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-jquery","category-json","category-programming","tag-ajax","tag-featured","tag-javascript","tag-jquery","tag-json","tag-jsonp","tag-plugin","tag-widget"],"_links":{"self":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts\/1470","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/comments?post=1470"}],"version-history":[{"count":71,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts\/1470\/revisions"}],"predecessor-version":[{"id":2159,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts\/1470\/revisions\/2159"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/media\/2128"}],"wp:attachment":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/media?parent=1470"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/categories?post=1470"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/tags?post=1470"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}