Introduction

The jQuery Plugin for AFD Postcode Evolution (PCE) allows developers to easily harness the power of PCE in front-end applications.

When filling out address forms, users simply need to start typing their address in a single typeahead box that will drill down on the results until the user can select their address from the list. Additionally, a reverse geocoding button can be added to the form that when clicked will search for addresses based on the user's current location.

The plugin also has powerful validation tools that allow validation of phone numbers, email addresses, credit/debit cards, and UK bank accounts. In addition to validation it is possible to extract further information from the fields (for example "card type"), restrict input to certain keys and format the fields automatically, independent of the actual keys pressed by the user.

Compatibility

jQuery Compatibility

The plugin is compatible with all versions of jQuery above version 1.6.

Bootstrap Compatibility

The plugin is ready, out of the box to work with both Bootstrap 3 and 4 form validation and the typeahead control is by default styled to look like a Bootstrap control. Developers simply need to create the form controls according to the Bootstrap documentation, and PCE will add its default behaviour and apply the correct validation styles.

Getting Started

Download the lastest version of the AFD jQuery plugin:

http://download.afd.co.uk/web/integrations/jquery/afd.jquery.1.9.0.zip

Include jQuery, the afd plugin, the AFD typeahead css, and your AFD config in the head of the html document.

<head>
  <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="afd.jquery.1.9.0.min.js"></script>
  <script>
    afdOptions = {
        serial: "YOUR_ID",
        password: "YOUR_TOKEN"
    };
  </script>
  <link type="text/css" rel="stylesheet" href="jquery.typeahead.afd.css">
<head>

Modular Versions

The main plugin afd.jquery.1.9.0.js contains all of the functionality available. However, as most developers will not need to deploy all of the features on all pages of a project, there are also modular versions of the plugin that are feature specific. This helps reduce the size of the plugins.

As of version 1.9.0 multiple modular files can be added to the same page.

Address Lookup

The Typeahead Control

In the body of the document add the following html for your Typeahead control. This tag structure is required but custom CSS can be applied if needed.

<div class="afd-typeahead-container">
  <div class="afd-typeahead-field">
    <div class="afd-typeahead-query">
      <input
        type="search"
        autocomplete="off"
        data-afd-control="typeahead">
    </div>
  </div>
    <div class="afd-search-again" style="display:none">Search Again</div>
    <div class="afd-manual-input-button" style="display:none">Manual Input</div>
    <div class="afd-manual-input-search-button" style="display:none">Address Search</div>
</div>

Lookup Controls

An alternative to typeahead address search is lookup controls. This is a family of three controls:

  • Lookup Field - An <input> field where an address search or postcode can be entered.
  • Lookup Button - A <button> that initiates the lookup.
  • Lookup Results - A <select> or <ul> control that displays the results of the lookup that when clicked retrieves the corresponding address.

A typical HTML setup is shown below, however, these controls can be moved around. They must be wrapped in a a container that contains the .afd-form-control class.

<div class="row">
  <div class="input-group col-md-4 afd-form-control">
    <input class="form-control" data-afd-control="lookupField" id="lookup-field" placeholder="Postcode Lookup">
    <div class="input-group-append">
      <button class="btn" data-afd-control="lookupButton">Lookup</button>
    </div>
    <div class="afd-manual-input-search-button" style="display:none">Address Search</div>
    <div class="afd-manual-input-button" style="display:none">Manual Input</div>
  </div>
</div>
<div class="row">
  <div class="col-8 afd-form-control">
    <ul class="custom-select" data-afd-control="lookupResultsList"></ul>
  </div>
</div>

For the lookup results control, we recommend using a <ul> control as that offers greater consistency in user experience across devices. However, if this is used an additional stylesheet (jquery.result.list.afd.css) should be added to the page. These style can then be customised further to match the theme of the page.

International Addresses

ZipAddress

For lookups using our ZipAddress product, the defaultCountry needs to be set to USA in afdOptions.country.

afdOptions.country.defaultCountry = "USA";

WorldAddress

For international lookups using our WorldAddress product, an additional country <select> control needs to be added to the form.

If there isn't already a country control form supplied then using the following HTML will add a <select> element to the form.

<select data-afd-control="country"></select>

This will populate with all of the available WorldAddress countries and automatically use the selected country in typeahead queries.

If there is already a control on the form, the details of that form and possibly a transformation function need to be supplied in afdOptions.country (see "Configuration Options" below).

Reverse Geocoding

It is also possible to get a users address from their devices' location api. We recommend that this control is used in conjunction with with the typeahead or lookup controls. This functionality requires two controls:

  • Reverse Geocode Button - A <button> that initiates the lookup.
  • Reverse Geocode Results - A <select> or <ul> control that displays the results of the lookup that when clicked retrieves the corresponding address.

Here is an example of a reverse geocode button alongside a typeahead control:

<div class="row">
	<div class="afd-typeahead-container afd-form-control form-group col-md-9">
		<div class="afd-typeahead-field">
			<div class="afd-typeahead-query input-group">
				<div class="input-group-prepend">
					<button type="button" class="btn" data-afd-control="reverseGeocodeButton">
						<svg width="18" height="18" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
							<path d="M1325 1024h-109q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h109q-32-108-112.5-188.5t-188.5-112.5v109q0 26-19 45t-45 19h-128q-26 0-45-19t-19-45v-109q-108 32-188.5 112.5t-112.5 188.5h109q26 0 45 19t19 45v128q0 26-19 45t-45 19h-109q32 108 112.5 188.5t188.5 112.5v-109q0-26 19-45t45-19h128q26 0 45 19t19 45v109q108-32 188.5-112.5t112.5-188.5zm339-192v128q0 26-19 45t-45 19h-143q-37 161-154.5 278.5t-278.5 154.5v143q0 26-19 45t-45 19h-128q-26 0-45-19t-19-45v-143q-161-37-278.5-154.5t-154.5-278.5h-143q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h143q37-161 154.5-278.5t278.5-154.5v-143q0-26 19-45t45-19h128q26 0 45 19t19 45v143q161 37 278.5 154.5t154.5 278.5h143q26 0 45 19t19 45z"/>
						</svg>
					</button>
				</div>
				<input class="form-control"
					   type="search"
					   autocomplete="off"
					   data-afd-control="typeahead"
					   name="lion"
				>
			</div>
		</div>
		<div class="afd-search-again" style="display:none">Search Again</div>
		<div class="afd-manual-input-button" style="display:none">Manual Input</div>
		<div class="afd-manual-input-search-button" style="display:none">Address Search</div>
	</div>
</div>
<div class="row">
	<div class="col-sm-12 afd-form-control">
		<ul data-afd-control="reverseGeocodeResultsList"></ul>
	</div>
</div>

For the lookup results control, we recommend using a <ul> control as that offers greater consistency in user experience across devices. However, if this is used an additional stylesheet (jquery.result.list.afd.css) should be added to the page. These style can then be customised further to match the theme of the page.

Results Fields

For each result field that you want to add to the page you need to add the data-afd-result attribute to the <input> and set the attribute as the PCE field that you would like it to display. The PCE fields are case sensitive.

<div class="form-control">
  <label for="Postcode">Postcode:</label>
  <input data-afd-result="Postcode" id="postcode">
</div>

A full list of PCE fields can be found in Appendix A.

Typeahead Configuration Options

In addition to setting the serial and username there are a number of options that it is possible to set to govern the behaviour of the typeahead, lookup and result fields.

afdOptions.typeahead.maxItems

type: number

default: 5

The number of search results returned by the typeahead control. For performance purposes we do not recommend setting this higher than 5.

afdOptions.typeahead.pushUp

type: boolean | array

default: false

This setting is useful in forms that do not label the individual property and street fields but rather bundle them together as a single field.

If set to true and the retrieved result's property or street fields are empty, this will push the street and/or locality up into the closest empty space.

An array can also be supplied that specifies exactly which fields should be pushed up and in what order. For example:

[
   'Organisation',
   'Property',
   'Street',
   'Locality',
   'Town'
 ]

afdOptions.typeahead.afterHideTypeahead

type: boolean

default: false

If set to true this will hide the typeahead control once an address has been retrieved.

afdOptions.typeahead.searchAgain

type: boolean

default: true

When afdOptions.typeahead.afterHideTypeahead is set to true the typeahead control will be hidden after an address has been retrieved. This option will show in its place a "Search Again" button that when clicked will again show the typeahead control.

afdOptions.typeahead.afterClearTypeahead

type: boolean

default: true

If set to true, once a retrieve has been completed the contents of the typeahed box will be removed.

afdOptions.typeahead.beforeHideResults

type: boolean

default: false

When set to true, this will hide the results fields until an address retrieve has been completed.

afdOptions.typeahead.parentClass

type: string

default: null

Input controls in most modern HTML forms are usually nested inside a container along labels and validation messages e.g.

<!--bootstrap 4 example-->
<div class="field-group">
    <label for="street">Street</label>
    <input name="street" data-afd-result="Street">    
</div>

In the above example, if afdOptions.typeahead.beforeHideResults is set to true only the input will be hidden and the label will still be visible before a search. Setting parentClass, to field-group will hide the entire container until the retrieve has been completed.

afdOptions.typeahead.fieldSets

type: [string]

default: []

In some forms, certain fields may be bundled together in a single fieldset, which has a single label but also shares the class name of the input fields. The Magento address fields are an example of this:

<fieldset class="fieldset">
    <label>Street</label>
    <div class="field">
        <input data-afd-result="Property">
    </div>
    <div class="field">
        <input data-afd-result="Street">
    </div>
    <div class="field">
        <input data-afd-result="Locality">
    </div>
</fieldset>

In the above example, the parentClass option will only hide the inputs and the label will still be visible. Setting this option to ['fieldset'] will also hide the parent fieldset.

afdOptions.typeahead.manualInputButton

type: boolean

default: false

When afdOptions.typeahead.beforeHideResults is set to true, it is not possible for the user to manually enter address. Enabling this this option will display a button below the typeahed control that when clicked will show the address fields.

afdOptions.typeahead.fewResultsManualInput

type: boolean

default: true

When afdOptions.typeahead.beforeHideResults is set to true, and for whatever reason, the user is unable to find their address they would be unable to enter it manually as the results fields are hidden. Setting this option to true causes the control to check to see if the number of returned results is leass than the maxItems, if it is, an additional entry will be added to the bottom of the typeahead results that will allow the user to enter their address manually.

afdOptions.typeahead.fewResultsManualInputText

type: string

default: "Can't see your address? Enter it manually"

This is the text that will be shown if afdOptions.typeahead.fewResultsManualInput is set to true.

afdOptions.typeahead.notEmptyShowResults

type: boolean

default: false

When afdOptions.typeahead.beforeHideResults is set to true, the address fields will be hidden until an address has been retrieved. In some cases this behaviour may not be completely desirable. For example, it may be jarring on an edit address page if no address fields are visible. Setting this option to true will mean that any field that is already populated will not be hidden by beforeHideResults.

afdOptions.typeahead.hideEmpties

type: boolean

default: false

If this option is set to true, when an address is retrieved, any fields that do not have values will be hidden.

afdOptions.typeahead.containers

type: [string]

default: []

In the case that two forms are on the same page, use this option to differentiate. Put a jQuery selector for each form container into the array and the functionality for each typeahead control will be limited to each container.

afdOptions.typeahead.retrieveFields

type: string

default: "standard"

When using ZipAddress or WorldAddress it is possible to set the names of the fields returned from our PCE service to be more appropriate. The data-afd-results controls will need to be reflect the fields that are returned. Possible options are usa and international

afdOptions.typeahead.matchPositions

type" boolean

default: false

When set to yes this allows for the highlighting of the matching strings in the results list. The matching strings are contained within a <span> element with the class set as .afd-matched-highlight, and so a style must be applied to this class for the highlighting to be visible.

.afd-matched-highlight {
  font-weight: bold;
}

afdOptions.typeahead.postcodeFirst

type" boolean

default: true

By default the postcode is shown first in the results list. When this is set to false, the postcode is shown at the end of the results list.

afdOptions.typeahead.hideForCountries

type" array

default: []

Allows restriction of the countries that the typeahead controls are displayed on. Array of ISO3 country codes. Hides the control for all countries in the array, shows the rest.

afdOptions.typeahead.showForCountries

type" array

default: []

An alternative to hideForCountries. Allows restriction of the countries that the typeahead controls are displayed on. Array of ISO3 country codes. Shows the control for all countries in the array, hides the rest.

Lookup Configuration Options

afdOptions.lookup.prefetch

type: boolean

default: true

Pre-fetches results as the user is typing so that when the lookup button is pressed the lookup has already been done instantly shows the results without the need of a network request.

afdOptions.lookup.pushUp

type: boolean

default: false

This setting is useful in forms that do not label the individual property and street fields but rather bundle them together as a single field.

If set to true and the retrieved result's property or street fields are empty, this will push the street and/or locality up into the closest empty space.

An array can also be supplied that specifies exactly which fields should be pushed up and in what order. For example:

[
   'Organisation',
   'Property',
   'Street',
   'Locality',
   'Town'
 ]

afdOptions.lookup.beforeHideResults

type: boolean

default: false

When set to true, this will hide the results fields until an address retrieve has been completed.

afdOptions.lookup.parentClass

type: string

default: null

Input controls in most modern HTML forms are usually nested inside a container along labels and validation messages e.g.

<!--bootstrap 4 example-->
<div class="field-group">
    <label for="street">Street</label>
    <input name="street" data-afd-result="Street">    
</div>

In the above example, if afdOptions.lookup.beforeHideResults is set to true only the input will be hidden and the label will still be visible before a search. Setting parentClass, to field-group will hide the entire container until the retrieve has been completed.

afdOptions.lookup.fieldSets

type: [string]

default: []

In some forms, certain fields may be bundled together in a single fieldset, which has a single label but also shares the class name of the input fields. The Magento address fields are an example of this:

<fieldset class="fieldset">
    <label>Street</label>
    <div class="field">
        <input data-afd-result="Property">
    </div>
    <div class="field">
        <input data-afd-result="Street">
    </div>
    <div class="field">
        <input data-afd-result="Locality">
    </div>
</fieldset>

In the above example, the parentClass option will only hide the inputs and the label will still be visible. Setting this option to ['fieldset'] will also hide the parent fieldset.

afdOptions.lookup.manualInputButton

type: boolean

default: false

When afdOptions.lookup.beforeHideResults is set to true, it is not possible for the user to manually enter address. Enabling this this option will display a button below the lookup control that when clicked will show the address fields.

afdOptions.lookup.hideEmpties

type: boolean

default: false

If this option is set to true, when an address is retrieved, any fields that do not have values will be hidden.

afdOptions.lookup.afterRetrieveHideResultsList

type: boolean

default: false

After a retrieve has completed hide the results box.

afdOptions.lookup.postcodeIsLookup

type: boolean

default: false

Set to true if the postcode result field should also function as the lookup box.

afdOptions.lookup.containers

type: [string]

default: []

In the case that two forms are on the same page, use this option to differentiate. Put a jQuery selector for each form container into the array and the functionality for each lookup control will be limited to each container.

afdOptions.lookup.retrieveFields

type: string

default: "standard"

When using ZipAddress or WorldAddress it is possible to set the names of the fields returned from our PCE service to be more appropriate. The data-afd-results controls will need to be reflect the fields that are returned. Possible options are usa and international

afdOptions.lookup.postcodeFirst

type" boolean

default: true

By default the postcode is shown first in the results list. When this is set to false, the postcode is shown at the end of the results list.

afdOptions.lookup.hideForCountries

type" [string]

default: []

Allows restriction of the countries that the lookup controls are displayed on. Array of ISO3 country codes. Hides the controls for all countries in the array, shows the rest.

afdOptions.lookup.showForCountries

type: [string]

default: []

An alternative to hideForCountries. Allows restriction of the countries that the lookup controls are displayed on. Array of ISO3 country codes. Shows the controls for all countries in the array, hides the rest.

Country Field Configuration

afdOptions.country.defaultCountry

type: string

default: null

If you only plan on doing ZipAddress lookups this should be set as USA.

If you are using WorldAddress for international lookups this set the default country of the country select control.

afdOptions.country.availableCountries

type: [string]

default: []

Limit the countries in the country field to the ones given in the array. Must be ISO3 country codes.

afdOptions.country.customCountryControl

type: string

default: null

jQuery selector of the country control that is to be used for WorldAddress. This is for when the AFD country control is not being used.

afdOptions.country.customCountryConverter

type: function

default: null

Function that accepts the value attribute of the country control <select>, and transforms it into an ISO3 country code aand then returns it. This is necessary if the value attribute of the country control is not an ISO3 country code.

Reverse Geocode Configuration Options

afdOptions.reverseGeocode.maxItems

type: number

default: 100

Maximum number of addresses that should be returned from the AFD service.

afdOptions.reverseGeocode.linkedControl

type: string

default: 'typeahead'

The control that the reverse geocode button is attached to. Behaviour related to field visibility and populating results will be taken from this control's options. Should be either typeahead or lookup

afdOptions.reverseGeocode.hideOnDesktop

type: boolean

default: false

The accuracy of the location API is significantly lower than that of a mobile device. Setting this to true hides the button on desktops.

afdOptions.reverseGeocode.buttonContainer

type: string | null

default: null

If the button is in a container that should also be hidden on desktops, the selector for the container should be specified here.

Card Validation

This plugin validates credit / debit card numbers first on the page and then against AFD's card validation service. In addition it provides useful information about the card and can optionally display logos for which ever card type is being entered.

Card Number and Expiry Date Controls

In the body add <input> elements for card and expiry date with the corresponding attributes data-afd-control="card" and data-afd-control="expiry" set.

<div class="form-control">
  <label for="card">Card Number:</label>
  <input data-afd-control="card" id="card">
</div>
<div class="form-control">
  <label for="expiry">Expiry Date:</label>
  <input data-afd-control="expiry" id="expiry">
</div>

Checking Validation

When a number or date is input validation will begin.

There is no point in validating against the AFD card validation service until the structure of the card number and the date are known to be valid. This being the case, as the user types both fields will be checked for validity and only once both are valid and the control loses focus will the service be queried.

Once PCE returns a valid outcome both fields will have the afd-valid class added. If the input loses focus and the fields are not valid the input will have the afd-invalid class added. If the user begins to type either with the valid or the invalid class set, both will be removed until either the number and date are both valid or the control loses focus again.

In addition to classes the validation fields also make use of the constraint validation API which is supported by all major browsers. This allows the use of the :valid and invalid pseudo classes and the validation JavaScript objects attached to input elements. An example of how you might display validation messages is shown in the section afd:cardValidationUpdated.

Card Logos

It is possible to add card logos to the card validation area. To do this simply add a <span> with class afd-card-logo. An example with logos displayed in a Bootstrap 4 input group:

<div class="form-group">
	<label for="card">Card: </label>
	<div class="input-group">
		<div class="input-group-prepend">
			<span class="afd-card-logo input-group-text"></span>
		</div>
		<input class="form-control" data-afd-control="card" id="card">
		<div class="invalid-feedback"></div>
	</div>
</div>
<div class="form-group">
	<label for="expiry">Expiry: </label>
	<input class="form-control" data-afd-control="expiry" id="expiry">
	<span class="invalid-feedback"></span>
</div>

The images are SVGs and are by default scaled to 24px by 16px. This can be changed in afdOptions.card.logoWidth and afdOptions.card.logoHeight.

Loading Spinner

The plugin comes with a loading spinner out of the box that can be added to the controls. To use the spinner simply include the css file jquery.spinner.afd.css in the page and then supply the selector of the parent of the input to afdOptions.card.loadingSpinner.

While the styling has already been taken care of, it is possible that the position of the spinner may not match the design of the controls. If this is the case override the following css rules:

.afd-loading > :before, .afd-loading > :after {
  top: 3.5em;
  right: 1em;
}

If a custom spinner is required it can be styled using the .afd-loading class which is applied to the element given in afdOptions.card.loadingSpinner.

Advanced Usage

The card module emits events on document on validation update and validation complete.

afd:cardValidationUpdated

This event is emitted after a syntax check on the card number or the expiry date after each key-up event, and is also emitted after a full AFD check which is triggered when either of the controls lose focus while both are structurally valid. The callback contains the event object and the elements themselves.

Example:

$(document).on('afd:cardValidationUpdated', function (e, cardElement, expiryElement) {
        $('#card-type-nice').html($(cardElement).data('card-type-nice'));
        $('#afd-valid').html($(cardElement).data('card-is-afd-valid').toString());
        $('#card-syntax-valid').html($(cardElement).data('card-is-syntax-valid').toString());
        $('#card-type').html($(cardElement).data('card-type'));
        $('#expiry-syntax-valid').html($(expiryElement).data('expiry-is-syntax-valid').toString());
    });
Additional Information

We only check against the AFD service once the patterns in the fields are known to be valid. However, it is possible to get some information from the card number before it is complete and so these are available via the jQuery data API. For example:

$(document).on("afd:cardValidationUpdated", function(e, element){
  var cardInfo = {
    cardType: $(element).data("card-type"),
    cardTypeNice: $(element).data("card-type-nice"),
    isCardSyntaxValid: $(element).data("card-is-syntax-valid"),
    isExpirySyntaxValid: $(element).data("expiry-is-syntax-valid"),
    isAfdValid: $(element).data("card-is-afd-valid"),
  };
  console.log(cardInfo);
});

This can be used to display information in accompanying fields.

Displaying Validation Messages

As mentioned previously, the constraint validation API used in combination with event can be used to get the validation message set on the element. An example is as follows:


<div class="form-control">
  <label for="card">Card Number:</label>
  <input data-afd-control="card" id="card">
  <p id="card-error-message"></p>
</div>
<div class="form-control">
  <label for="expiry">Expiry Date:</label>
  <input data-afd-control="expiry" id="expiry">
  <p id="expiry-error-message"></p>
</div>
<script>
  $(document).on("afd:cardValidationUpdated", function(e, cardElement, expiryElement){
    if(!cardElement.validity.valid){
      $("#card-error-message").html(element.validationMessage);
    }else{
      $("#card-error-message").html("");
    };
  if(!expiryElement.validity.valid){
      $("#expiry-error-message").html(expiryElement.validationMessage);
    }else{
      $("#expiry-error-message").html("");
    };
  });
</script>

afd:cardValidationStarted

This event is emitted once a validation request against the AFD card validation service is initialised. This will happen when a user focusses out of one of the controls and they both have valid syntaxes. This may be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:cardValidationStarted', function (e, cardElement, expiryElement) {
    // do something
});

afd:cardValidationSuccess

This event is emitted once a validation request against against AFD's card validation service has been completed successfully. This does not mean that the card number itself is valid, just that the request was successful. The data object contains the response from the AFD service. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:cardValidationSuccess', function (e, data, cardElement, expiryElement) {
   console.log(data);
   // do something
});

afd:cardValidationError

This event is emitted once a validation request against against AFD's card validation service has encountered an error. This does not mean that the card number itself is invalid, just that the request was not successful. The err object contains details of the error. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:cardValidationError', function (e, err) {
    console.log(err);
    // do something
});

Account Validation

Account and Sort Code Controls

In the body add <input> elements for account number and sort code with the corresponding attributes data-afd-control="account" and data-afd-control="sort" set.

<div class="form-control">
  <label for="account">Account Number:</label>
  <input data-afd-control="account" id="account">
</div>
<div class="form-control">
  <label for="sort">Sort Code:</label>
  <input data-afd-control="sort" id="sort">
</div>

Loading Spinner

The plugin comes with a loading spinner out of the box that can be added to the controls. To use the spinner simply include the css file jquery.spinner.afd.css in the page and then supply the selector of the parent of the input to afdOptions.account.loadingSpinner.

While the styling has already been taken care of, it is possible that the position of the spinner may not match the design of the controls. If this is the case override the following css rules:

.afd-loading > :before, .afd-loading > :after {
  top: 3.5em;
  right: 1em;
}

If a custom spinner is required it can be styled using the .afd-loading class which is applied to the element given in afdOptions.account.loadingSpinner.

Checking Validation

When an account number or sort code is input validation will begin.

There is no point in validating against PCE until the structure of the card number and the date are known to be valid. This being the case, as the user types both fields will be checked for validity and only once both are valid and the control loses focus will PCE be queried.

Once PCE returns a valid outcome both fields will have the afd-valid class added. If the input loses focus and the fields are not valid the input will have the afd-invalid class added. If the user begins to type either with the valid or the invalid class set, both will be removed until either the number is valid or the control loses focus again.

In addition to classes the validation fields also make use of the constraint validation API which is supported by all major browsers. This allows the use of the :valid and invalid pseudo classes and the validation JavaScript objects attached to input elements. An example of how you might display validation messages is shown in the section afd:accountValidationUpdated.

Advanced Usage

The account module emits events on the document on validation update and validation complete.

afd:accountValidationUpdated

This event is emitted after a syntax check on the account number or the sort code after each keyup event and also after a full AFD check which is triggered when either of the inputs lose focus. The callback contains the event object and the element itself.

Additional Information

We only check against AFD once we are sure that the pattern is valid, after that we will be able to get some information about the account number in addition to its validation status via the data API. For example:

$(document).on("afd:accountValidationUpdated", function(e, accountElement, sortElement){
    $("#account-syntax-valid").html($(accountElement).data("account-is-syntax-valid").toString());
    $("#afd-valid").html($(accountElement).data("account-is-afd-valid").toString());
    $("#sort-code-syntax-valid").html($(sortElement).data("sort-code-is-syntax-valid").toString());
	$("#clearing-system").html($(accountElement).data("account-clearing-system"));
	$("#iban").html($(accountElement).data("account-iban"));
	$("#roll-number").html($(accountElement).data("account-roll-number"));
	$("#account-type").html($(accountElement).data("account-type"));
});

This can be used to display information in accompanying fields.

Displaying Validation Messages

As mentioned previously the constraint validation API used in combination with event can be used to get the validation message set on the element. An example is as follows:


<div class="form-control">
  <label for="account">Account Number:</label>
  <input data-afd-control="account" id="account">
  <p id="account-error-message"></p>
</div>
<div class="form-control">
  <label for="sort">Sort Code:</label>
  <input data-afd-control="sort" id="sort">
  <p id="sort-error-message"></p>
</div>
<script>
  $(document).on("afd:accountValidationUpdated", function(e, accountElement, sortElement){
    if(!accountElement.validity.valid){
      $("#account-error-message").html(accountElement.validationMessage);
    }else{
      $("#account-error-message").html("");
    };
  if(!expiryElement.validity.valid){
      $("#sort-error-message").html(sortElement.validationMessage);
    }else{
      $("#sort-error-message").html("");
    };
  });
</script>

afd:accountValidationStarted

This event is emitted once a validation request against the AFD account validation service is initialised. This will happen when a user focusses out of one of the controls and they both have valid syntaxes. This may be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:accountValidationStarted', function (e, accountElement, sortCodeElement) {
    // do something
});

afd:accountValidationSuccess

This event is emitted once a validation request against against AFD's account validation service has been completed successfully. This does not mean that the account number itself is valid, just that the request was successful. The data object contains the response from the AFD service. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:cardValidationSuccess', function (e, data, accountElement, sortCodeElement) {
   console.log(data);
   // do something
});

afd:accountValidationError

This event is emitted once a validation request against against AFD's account validation service has encountered an error. This does not mean that the card number itself is invalid, just that the request was not successful. The err object contains details of the error. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:cardValidationError', function (e, err) {
    console.log(err);
    // do something
});

Phone Number Validation

The Phone Number Control

In the body add an <input> element with the attribute data-afd-control="phone" set.

<div class="form-control">
  <label for="phone">Phone Number:</label>
  <input data-afd-result="phone" id="phone">
</div>

This module loads some additional of the libraries and a flag file from AFD's servers.

Loading Spinner

The plugin comes with a loading spinner out of the box that can be added to the control. To use the spinner simply include the css file jquery.spinner.afd.css in the page and then supply the selector of the parent of the input to afdOptions.phone.loadingSpinner.

While the styling has already been taken care of, it is possible that the position of the spinner may not match the design of the controls. If this is the case override the following css rules:

.afd-loading > :before, .afd-loading > :after {
  top: 3.5em;
  right: 1em;
}

If a custom spinner is required it can be styled using the .afd-loading class which is applied to the element given in afdOptions.phone.loadingSpinner.

Checking Validation

When a number is entered validation will begin. If the number is valid the input will have the afd-valid class added. If the control loses focus and the number is not valid the input will have the afd-invalid class added. If the user begins to type either with the valid or the invalid class set, both will be removed until either the number is valid or the control loses focus again.

In addition to classes the validation fields also make use of the constraint validation API which is supported by all major browsers. This allows the use of the :valid and invalid pseudo classes and the validation JavaScript objects attached to input elements. An example of how you might display validation messages is shown in the section afd:phoneValidationUpdated.

Dealing with Country Codes

The control assumes that the country code is UK (+44) unless set otherwise in afdOptions.phone.defaultDialingCode. There is a country dropdown box that lets the user choose their country, also the user can specify their country dialing code by prefixing the number with '+' or '00'.

It is possible to link the country dropdown in the phone control to an external country field. To do this specify the selector of the external country field in afdOptions.phone.countryControl. When a country is selected in the external country control the, country of the phone control will track that.

The external country control functionality works on the basis that the value attribute of the external country control supplies either an ISO2 or ISO3 country code. However, not all forms are setup this way. An example might look like this:

<select>
    <option data-country="FRA" value="France">France</option>
</select>

In this case the value matches the name of the country not the ISO code. For situations like this, a function can be supplied to afdOptions.phone.countryControlConverter that gets the data attribute and returns it.

For example:


afdOptions.phone.countryControlConverter = function(e) {
    // e is the event object from the country change
    var $el = $(e.target);
    var value = $el.val();
    return $el.find('[value="' + value + '"]').attr('data-country'); 
}

Advanced Usage

The phone module emits events on the document on validation update and validation complete.

  • afd:phoneValidationUpdated // event, validationObject

afd:phoneValidationUpdated

This event is emitted after a regex check on the phone number after each keyup event and also after a full AFD check which is triggered when the input loses focus. The callback contains the event object and the element itself.

Additional Information

We only check against AFD once the pattern is known to be valid. However, it is possible to get some information from the number before it is complete and so these are available via the data API. For example:

$(document).on("afd:phoneValidationUpdated", function(e, element){
  var phoneInfo = {
    phoneNumber: $(element).data('phone-number'),
    phoneNumberE164: $(element).data('phone-number-e164'),
    phoneNumberInternational: $(element).data('phone-number-international'),
    phoneNumberNational: $(element).data('phone-number-national'),
    phoneNumberRFC3966: $(element).data('phone-number-rfc3966'),
    phoneRegion: $(element).data("phone-region"),
    phoneRegionName: $(element).data('phone-region-name'),
    phoneRegionISO2:$(element).data('phone-region-iso2'),
    phoneRegionISO3: $(element).data('phone-region-iso3'),
    isMobile: $(element).data("phone-is-mobile"),
    isLandLine: $(element).data("phone-is-landline"),
    isSyntaxValid: $(element).data("phone-is-syntax-valid"),
    isAfdValid: $(element).data("phone-is-afd-valid"),
    phoneNumberType: $(element).data('phone-number-type')
  }
  console.log(phoneInfo);
});

This can be used to display information in accompanying fields.

Displaying Validation Messages

As mentioned previously the constraint validation API used in combination with event can be used to get the validation message set on the element. An example is as follows:


<div class="form-control">
  <label for="phone">Phone Number:</label>
  <input data-afd-result="phone" id="phone">
  <p id="error-message"></p>
</div>
<script>
  $(document).on("afd:phoneValidationUpdated", function(e, element){
    if(!element.validity.valid){
      $("#error-message").html(element.validationMessage);
    }else{
      $("#error-message").html("");
    };
  });
</script>

afd:phoneValidationStarted

This event is emitted once a validation request against the AFD phone validation service is initialised. This will happen when a user focusses out of the control and the syntax is valid. This may be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:phoneValidationStarted', function (e, element) {
    // do something
});

afd:phoneValidationSuccess

This event is emitted once a validation request against against AFD's phone validation service has been completed successfully. This does not mean that the phone number itself is valid, just that the request was successful. The data object contains the response from the AFD service. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:phoneValidationSuccess', function (e, data, element) {
   console.log(data);
   // do something
});

afd:phoneValidationError

This event is emitted once a validation request against against AFD's phone validation service has encountered an error. This does not mean that the phone number itself is invalid, just that the request was not successful. The err object contains details of the error. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:phoneValidationError', function (e, err) {
    console.log(err);
    // do something
});

Email Address Validation

Email Control

In the body add an <input> element with the attribute data-afd-control="email" set.

<div class="form-control">
  <label for="email">Email Address:</label>
  <input data-afd-result="email" id="email">
</div>

Loading Spinner

The plugin comes with a loading spinner out of the box that can be added to the control. To use the spinner simply include the css file jquery.spinner.afd.css in the page and then supply the selector of the parent of the input to afdOptions.email.loadingSpinner.

While the styling has already been taken care of, it is possible that the position of the spinner may not match the design of the controls. If this is the case override the following css rules:

.afd-loading > :before, .afd-loading > :after {
  top: 3.5em;
  right: 1em;
}

If a custom spinner is required it can be styled using the .afd-loading class which is applied to the element given in afdOptions.email.loadingSpinner.

Checking Validation

When an email address is input validation will begin. If the address is valid the input will have the afd-valid class added. If the input loses focus and the address is not valid the input will have the afd-invalid class added. If the user begins to type either with the valid or the invalid class set, both will be removed until either the address is valid or the control loses focus again.

In addition to classes the validation fields also make use of the constraint validation API which is supported by all major browsers. This allows the use of the :valid and invalid pseudo classes and the validation JavaScript objects attached to input elements. An example of how you might display validation messages is shown in the section afd:emailValidationUpdated.

Advanced Usage

The email module emits events on the document on validation update and validation complete.

  • afd:emailValidationUpdated // event, validationObject
  • afd:validateComplete // event, emailElement

afd:emailValidationUpdated

This event is emitted after a regex check on the email address after each keyup event and also after a full AFD check which is triggered when the input loses focus. The callback contains the event object and the element itself.

Additional Information

We only check against AFD once the pattern is known to be valid, however we do supply an object that contains validation information on each key-press.

$(document).on("afd:emailValidationUpdated", function(e, element){
  var emailInfo = {
    pceMessage: $(element).data("email-pce-message");
    isRegexValid: $(element).data("email-is-regex-valid");
    isAfdValid: $(element).data("email-is-afd-valid");
  }
  console.log(emailInfo);
});

This can be used to display information in accompanying fields.

Displaying Validation Messages

As mentioned previously the constraint validation API used in combination with event can be used to get the validation message set on the element. An example is as follows:


<div class="form-control">
  <label for="email">Email Address:</label>
  <input data-afd-result="email" id="email">
  <p id="error-message"></p>
</div>
<script>
  $(document).on("afd:emailValidationUpdated", function(e, element){
    if(!element.validity.valid){
      $("#error-message").html(element.validationMessage);
    }else{
      $("#error-message").html("");
    };
  });
</script>

afd:emailValidationStarted

This event is emitted once a validation request against the AFD email validation service is initialised. This will happen when a user focusses out of the control and the syntax is valid. This may be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:emailValidationStarted', function (e, element) {
    // do something
});

afd:emailValidationSuccess

This event is emitted once a validation request against against AFD's email validation service has been completed successfully. This does not mean that the email address itself is valid, just that the request was successful. The data object contains the response from the AFD service. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:emailValidationSuccess', function (e, data, element) {
   console.log(data);
   // do something
});

afd:emailValidationError

This event is emitted once a validation request against against AFD's email validation service has encountered an error. This does not mean that the email address itself is invalid, just that the request was not successful. The err object contains details of the error. This may also be useful for custom loading spinner logic if the default spinner is not used.

Example:

$(document).on('afd:emailValidationError', function (e, err) {
    console.log(err);
    // do something
});

Appendices

Appendix A PCE Fields

Field Name Default Size Description Postcode Plotter Postcode Plus Names and Numbers
Lookup 255 Specify postcode (or zipcode) and fast-find lookup string’s here for lookup operations
Key 255 Provides a key which can be used to easily retrieve the record again, e.g. when a user clicks on an item in the list box.
List 512 Provides a list item formatted to be added to a list box for this record.
Product 40 Indicates the product name used [10]
Name 120 Full name (includes title, first name, middle initial and surname).
Gender 6 The gender (M or F) of the resident if known.
Forename 30 The first name of the resident
MiddleInitial 6 The middle initiate of the resident.
Surname 30 The surname/last name of the resident.
OnEditedRoll 6 Indicates if the resident is on the edited electoral roll (i.e. they have not opted out). Set to Y if they are on he Edited Roll, N if not, blank for Organisation and other records). To search set to #Y to return only records on the electoral roll, #N only for those not on the electoral roll or !N for all records including Organisations but excluding those not on the Edited Roll.
DateOfBirth 10 The residents date of birth if known (electoral roll attainers in the last 10 years only).
Residency 6 Gives time in years that the occupant has lived at this address.
HouseholdComposition 106 Describes the household composition of the selected address
Organisation 120 Full business name (includes any department)
Property 120 Property (building-includes any sub-building).
Street 120 Delivery Street (includes any sub-street)
Locality 70 Locality (sometimes a village name – in ZipAddress used for Urbanization)
Town 30 Postal Delivery Town (or City)
Postcode 10 The Royal Mail Postcode for this address (or ZipCode)
OrganisationName 60 Business Name
Department 60 Department Name
Sub Building 60 Sub Building Name
Building 60 Building Name
Number 10 House Number
DependentThoroughfare 60 Sub-Street Name
Thoroughfare 60 Street Name
DoubleDependentLocality 35 Sub-Locality Name
DependentLocality 35 Locality Name (Urbanization in ZipAddress)
Town 30 Postal Delivery Town (City)
Postcode 10 The Royal Mail Postcode for this address (or Zipcode)
UDPRN 8 Provides a unique identifier for the address
BuildDate 10 Provides the build date, which can be used as the start date, entry date, and update date fields for BS7666.
Administrator 20 Provides the administrator of the gazetteer (AFD).
Language 5 Provides the language (ENG)
Department 60 The name of a department within an organization where required.
Organization 60 The Organization Name
SubUnit 60 Sub-Unit of a building where needed
BuildingName 60 Building Name where present
BuildingNumber 10 Building Number, including 17A, 17-19, etc
SubStreet 60 Sub-Street where needed
DeliveryStreet 60 Designated Street Name
SubLocality 60 Sub-Locality where required
DeliveryLocality 60 Locality name (or Urbanization)
DeliveryTown 30 Postal Town name (or City)
Code 10 The Postcode (or ZipCode)
PostalCounty 30 Royal Mail supplied postal county
AbbreviatedPostalCounty 30 Royal Mail approved abbreviation is used where available for the postal county
OptionalCounty 30 Postal counties including optional ones for most addresses which would otherwise not have a county name.
AbbreviatedOptionalCounty 30 Royal Mail approved abbreviation is used where available for the optional county
TraditionalCounty 30 The traditional county name for this postcode
AdministrativeCounty 30 The administrative county name for this postcode
Outcode 4 The Outcode porton of the Postcode (the portion before the space)
Incode 3 The Incode portion of the Postcode (the portion after the space).
DPS 2 The Delivery Point Suffix which along with the postcode uniquely identifies the letterbox.
PostcodeFrom 8 Used with Postcode field to provide a range for searching. Also returns any changed postcode from a lookup.
PostcodeType 6 L for Large User Postcode, S for Small User.
MailsortCode 5 Used for obtaining bulk mail discounts.
UDPRN 8 Royal Mail Unique Delivery Point Reference Number assigned to this letter box
JustBuilt 10 AFDJustBuilt - Contains the date of inclusion on PAF for properties thought to be recently built. The date is tored numerically in descending format in the form YYYYMMDD. YYYY is the year, MM is the month and DD is the day. For example 20080304 is 04/03/2008.
Phone 20 STD Code or Phone Number
GridE 10 Grid Easting as a 6 digit reference
GridN 10 Grid Northing as a 6/7 digit reference
Latitude 10 Latitude representation of Grid Reference in Decimal Format (WGS84)
GBGridE 10 UK Based Grid Easting as a 6 digit reference. Always returns the UK based grid even for Northern Ireland addresses.
GBGridN 10 UK Based Grid Northing as a 6/7 digit reference
NIGridE 10 Irish Grid Based Grid Easting as a 6 digit reference. Always returns the Irish base grid even for mainland UK addresses
NIGridN 10 Irish Grid Based Grid Northing as a 6/7 digit reference
Longitude 10 Longitude representation of Grid Reference in Decimal Format (WGS84)
Miles 6 Distance from supplied grid reference
Km 6 Distance from supplied grid reference
UrbanRuralCode 2 Provides a code which indicates if an area is mainly urban or rural and how sparsely populated those areas are
UrbanRuralName 60 Provides a description which goes along with the UrbanRuralCode.
SOALower 9 Lower level Super Output Area (Data Zone in Scotland, Super Output Area in Northern Ireland)
SOAMiddle 9 Middle level Super Output Area (Intermediate Geography in Scotland, not applicable for Northern Ireland).
SubCountryName 20 Provides the devolved or non-UK country name (e.g. England, Scotland, Wales etc.)
WardCode 9 Code identifying the electoral ward for this postcode
WardName 50 Name identifying the electoral ward for this postcode
AuthorityCode 9 Local/Unitary Authority for this Postcode (same as the start of the ward code).
Authority 50 Local / Unitary Authority for this postcode
ConstituencyCode 9 Parliamentary Constituency Code for this postcode
Constituency 50 Parliamentary Constituency for this postcode
DevolvedConstituencyCode 9 Devolved Constituency Code for this postcode (currently covers Scotland)
DevolvedConstituencyName 50 Devolved Constituency Name for this postcode (currently covers Scotland)
EERCode 9 Code identifying the European Electoral Region for this postcode
EERName 40 Name identifying the European Electoral Region for this postcode
LEACode 3 Code identifying the Local Education Authority for this postcode
LEAName 50 Name identifying the Local Education Authority for this postcode
TVRegion 30 ISBA TV Region (not TV Company)
Occupancy 6 Indication of the type of occupants of properties found on the selected postcode
OccupancyDescription 30 Description matching the Occupancy
AddressType 6 Indication of the type of property level data to capture to have the full address for a property on the selected postcode
AddressTypeDescription 55 Description matching the Address Type
NHSCode 6 National Health Service Area Code
NHSName 50 National Health Service Area Name
PCTCode 9 National Health Service Clinical Commissioning Group Code for England (Local Health Board Code in Wales, Community Health Partnership in Scotland, Local Commissioning Group in Northern Ireland, Primary Healthcare Directorate in the Isle of Man)
PCTName 50 Name matching the PCT Code field
CensationCode 10 Censation Code assigned to this Postcode
CensationLabel 50 Provides a handle for the Censation Code
Affluence 30 Affluence description
Lifestage 100 LifeStage description
AdditionalCensusInfo 200 Additional information from the Census.
Business 100 Provides a description of the type of business
SICCode 10 Standard Industry Classification Code for an organisation record
Size 6 Gives an indication of the number of employees of an organisation at this particular office.
LocationType 6 The type of Business Location, e.g. Head Office or Branch Office
BranchCount 6 The number of branches for this business
GroupID 6 An ID of the Group were a business is part of a wider group
ModelledTurnover 15 The modelled annual turnover for the business
NationalSize 6 Gives an indication of the number of employees of an organisation covering all sites.
AliasLocalities 4 Returns the number of alias records present for the postcode sector in which this result resides
AliasLocality 35 Returns an alias (non-postal) locality that resides in the postcode sector that this address is contained in. Note that many postcode sectors have multiple alias localities and as such you can include this field multiple times to return multiple localities.
DataSet 10 With Postcode Plus and Welsh data can be set to ‘Welsh” to obtain the Welsh language version of an address in Wales where available. If not set then the English language version will be returned.
CouncilTaxBand 6 Provides the Council Tax Band for the selected property.