API

Belgian addresses

Complete postal area
Get a list of postal areas matching the input (postcode or municipality name).
Complete street
Given a postal area, get a list of streets matching the specified street name.

Example address form implementation

This example demonstrates a form with autocompletion for a Belgian address. It calls the completePostalArea and completeStreet methods.

Try…

  • Antwerpen, Sleeckxstraat
  • 8840, 1e Jagersstraat
  • Woluwe-Saint-Lambert, Chemin des Deux Maisons

Please note that this is a demo based on an alternative data set, which is not suitable for use in a production setting or unit tests. In this data set the names of some streets and municipalities have been shortened. For example, 'Europalaan' may be returned as 'Europa [demo]'.

Code

The following example code can be used as a starting point for your implementation.

HTML

<form>
	<input type="hidden" class="input-postcode" />
	<input type="hidden" class="input-municipality-name" />

	<dl>
		<dt>
			<label for="postal-area">Postcode or municipality</label>
		</dt>
		<dd>
			<input class="input-postal-area" id="postal-area" type="text" placeholder="2610 or Antwerpen" />
		</dd>
		<dt>
			<label for="street-name">Street</label>
		</dt>
		<dd>
			<input class="input-street-name" id="street-name" type="text" placeholder="Europalaan" />
		</dd>
		<dt>
			<label for="house-number">House number</label>
		</dt>
		<dd>
			<input class="input-house-number" id="house-number" type="text" placeholder="3" />
		</dd>
	</dl>

	<address class="autocomplete-result"></address>
</form>

Javascript

This example script is based on jQuery and jQuery UI Autocomplete.

Please make sure to change the demo resource URL's (see code comments).

(function () {
	'use strict';

	var $ = jQuery,
		address = { 'postcode': null, 'municipalityNisCode': null, 'municipalityName': null, 'streetName': null },

		// Change the following selectors to match your form elements.
		postcodeInput = $('.input-postcode'),
		municipalityInput = $('.input-municipality-name'),
		postalAreaInput = $('.input-postal-area'),
		streetNameInput = $('.input-street-name'),
		houseNumberInput = $('.input-house-number'),
		addressElement = $('.autocomplete-result'),

		// Change the following URL's to your production URL's.
		// Do not use the demo URL's in your production environment or unit tests.
		postalAreaUrl = 'demo/be/autocomplete/postal-area/',
		streetNameUrl = 'demo/be/autocomplete/street/';

	$(function () // DOMReady handler.
		{
			autoCompleteAddressParts();
		}
	);

	var autoCompleteAddressParts = function ()
	{
		postalAreaInput.autocomplete({
			autoFocus: true,
			select: function (event, ui)
			{
				// Clear streetName if municipalityNisCode or postcode has changed.
				if ((address.municipalityNisCode !== null && address.municipalityNisCode !== ui.item.municipalityNisCode)
					|| (address.postcode !== null && address.postcode !== ui.item.postcode)
				)
				{
					streetNameInput.removeClass('input-valid', 'input-error');
					streetNameInput.val('');
					address.streetName = null;
				}

				postcodeInput.val(ui.item.postcode);

				if (typeof(ui.item.postcode) !== 'undefined')
				{
					address.postcode = ui.item.postcode;
				}
				else
				{
					address.postcode = null;
				}

				postalAreaInput.removeClass('input-error');
				postalAreaInput.addClass('input-valid');

				municipalityInput.val(ui.item.municipalityName);
				address.municipalityName = ui.item.municipalityName;

				address.municipalityNisCode = ui.item.municipalityNisCode;

				renderAddress();
			},
			change: function (event, ui)
			{
				if (ui.item === null) // Postal area has changed, but isn't one of the autocomplete items.
				{

					postalAreaInput.removeClass('input-valid');
					postalAreaInput.addClass('input-error');

					streetNameInput.removeClass('input-valid', 'input-error');
					streetNameInput.val('');

					address.postcode = address.municipalityNisCode = address.municipalityName = address.streetName = null;
					renderAddress();
				}
			},
			source: function (request, responseCallback)
			{
				var sourceScope = this;

				$.getJSON(
					postalAreaUrl + encodeURIComponent(request.term),
					'',
					function (items, status, xhr)
					{
						if (typeof items.exception !== 'undefined')
						{
							return console.error(items.exception);
						}

						// Format matches.
						for (var i = 0, item; item = items[i]; i++)
						{
							items[i].value = items[i].label = item.municipalityName;

							if (typeof item.postcode === 'number')
							{
								items[i].value = items[i].label = item.postcode + ' ' + item.municipalityName;
							}

							if (typeof item.matchedName === 'string')
							{
								items[i].label += ' (' + item.matchedName + ')';
							}
						}

						responseCallback(items);
					}
				).fail(function (jqXHR)
					{
						if (jqXHR.status !== 200)
						{
							// Server might have (capacity) issues, stop sending requests to be safe.
							sourceScope.close();
							sourceScope.disable();
						}
					}
				);
			}
		});

		streetNameInput.autocomplete({
			autoFocus: true,
			select: function (event, ui)
			{
				streetNameInput.removeClass('input-error');
				streetNameInput.addClass('input-valid');

				postcodeInput.val(ui.item.postcode);
				address.postcode = ui.item.postcode;

				municipalityInput.val(ui.item.municipalityName);
				address.municipalityName = ui.item.municipalityName;

				address.streetName = ui.item.streetName;

				renderAddress();
			},
			change: function (event, ui)
			{
				if (ui.item === null) // Street name has changed, but isn't one of the autocomplete items.
				{
					streetNameInput.removeClass('input-valid');
					streetNameInput.addClass('input-error');

					address.streetName = null;
					renderAddress();
				}
			},
			source: function (request, responseCallback)
			{
				var sourceScope = this;

				if (address.municipalityNisCode === null)
				{
					return; // Can't continue without municipalityNisCode value.
				}

				$.getJSON(
					streetNameUrl + address.municipalityNisCode + '/' + (address.postcode || '') +'/' + encodeURIComponent(request.term),
					'',
					function (items, status, xhr)
					{
						if (typeof items.exception !== 'undefined')
						{
							return console.error(items.exception);
						}

						// Format matches.
						for (var i = 0, item; item = items[i]; i++)
						{
							items[i].value = items[i].label = item.streetName;

							if (address.postcode !== item.postcode)
							{
								items[i].label += ' (' + item.postcode + ')';
							}
						}

						responseCallback(items);
					}
				).fail(function (jqXHR)
					{
						if (jqXHR.status !== 200)
						{
							// Server might have (capacity) issues, stop sending requests to be safe.
							sourceScope.close();
							sourceScope.disable();
						}
					}
				);
			}
		});

		houseNumberInput.on('keyup', function ()
		{
			var valid = /^\d+/.test(houseNumberInput.val().trim());
			houseNumberInput.toggleClass('input-valid', valid);
			houseNumberInput.toggleClass('input-error', !valid);

			renderAddress();
		});
	};

	var renderAddress = function ()
	{
		addressElement.empty();

		if (address.postcode === null || address.municipalityName === null || address.streetName === null)
		{
			return;
		}

		addressElement.append(address.streetName);

		var houseNumber = houseNumberInput.val().trim();

		if (houseNumber !== '')
		{
			addressElement.append(' ', houseNumber);
		}

		addressElement.append($('<br>'), address.postcode, ' ', address.municipalityName);
	}

})();

CSS

The jQuery UI Autocomplete widget requires some functional CSS to work. Use one of jQuery UI's themes or create your own.

.ui-helper-hidden-accessible {
	border: 0;
	clip: rect(0 0 0 0);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
}

.ui-widget {
	box-shadow: 0 10px 15px rgba(0, 0, 0, .15);
}

.ui-widget-content {
	background-color: #fff;
}

.ui-state-active {
	background-color: #f0f6fa;
}

.ui-menu {
	padding: 0;
	z-index: 99;
}

.ui-menu-item {
	cursor: pointer;
}

.ui-menu-item-wrapper {
	padding: 8px 12px;
	line-height: 1;
}

.ui-autocomplete {
	position: absolute;
	max-height: 300px;
	overflow-y: auto;
 	overflow-x: hidden;
}