The Angular module for AFD Postcode Evolution® (PCE) allows developers to easily harness the power of PCE in front-end Angular 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.
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.
This module is compatible with Angular 6.0.0 onwards, it is not compatible with AngularJS.
First install the module:
npm install --save @afd-software/pce-angular
Import it into your Angular project. We also need to import some key Angular components HttpClientModule
and FormsModule
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AfdPceAngularModule } from '@afd-software/pce-angular';
....
@NgModule({
declarations: [
AppComponent,
....
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
AfdPceAngularModule,
....
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Then in a component, preferably the top level component, you need to declare the AfdPceService and set your credentials.
The AFD API accepts two types of credential pairs Serial/Password and ID/Token, each with its own pceURL. Typically, ID/Token is recommended.
IMPORTANT: Serial/Password are not for use in public-facing websites. For more information, contact the AFD Support team.
//app.component.ts
import {Component, OnInit} from '@angular/core';
import {AfdPceService} from '@afd-software/pce-angular';
@Component({
.....
})
export class AppComponent implements OnInit {
constructor(
public afdPceService: AfdPceService
){}
ngOnInit(){
this.afdPceService.settings.afdSerial = 'YOUR SERIAL';
this.afdPceService.settings.afdPassword = 'YOUR PASSWORD';
}
}
ngOnInit(){
this.afdPceService.settings.afdID = 'YOUR_ID';
this.afdPceService.settings.afdToken = 'YOUR_TOKEN';
this.afdPceService.settings.afdPceUrl = 'https://apps.afd.co.uk/json';
}
That’s it, now you are ready to start adding controls to forms.
“TypeAhead” functionality allows users to search for addresses and see results in real-time as they type. Our Angular TypeAhead controls make adding type ahead to an Angular project simple.
Typically with AFD PCE each time that a search term is submitted to our FastFind service, the customer is charged. However, with FastFind version four it is possible to group multiple related requests together using a common uniqueid
and as long as the total number of results returned across the queries is 100 or less, the customer will only be charged once. As such, limiting the maximum number of results returned for a search to, for example, five, means that twenty key presses in a TypeAhead control will still only result in being charged once.
To set up TypeAhead we need to add the component to our HTML template.
// app.component.html
And add the AfdPceService
to the component:
// app.component.ts
import {Component} from '@angular/core';
import {AfdPceService} from '@afd-software/pce-angular';
....
export class AppComponent {
constructor(
public afdPceService: AfdPceService
) {
this.afdPceService.selectedCountry = null; // Ensure that the country is UK
}
}
That’s it, now when you start typing an address in the box you will be presented with results (5 by default).
There are two ways to specify a country for international searches, static country selection and dynamic country selection.
This method is for situations in which there will only ever be one country set for searches. To specify the country add the country=
attribute to the <afd-typeahead-component>
and specify the ISO3 code for that country.
// app.component.html
This method allows users to update the country. Essentially an object that contains at least the iso code should be set as the selectedCountry
on AfdPceService
.
// app.component.ts
import {Component} from '@angular/core';
import {AfdPceService} from '@afd-software/pce-angular';
....
export class AppComponent implements OnInit {
constructor(
public afdPceService: AfdPceService
) {
}
ngOnInit(){
this.afdPceService.selectedCountry = {
name: "United States of America",
iso: "USA"
}
}
}
Developers are free to supply this object to the service in anyway that they like, however, we also supply a directive that will populate a < select>
component with the countries supported by WorldAddress.
The following example shows how to add a country select control to a form:
They key points here are:
countries
array in AfdPceService
.Once the user selects a result from the TypeAhead control, the module will query PCE to retrieve the full result for the selected address and send it to the results fields.
For setting results, we have a directive, afdResult
, that should be placed on an input control. This control will then receive the specified PCE field.
All PCE fields are accessible and are assigned using the afdResult
directive.
There is a single event, afdRetrieveComplete
,that is fired on the document when a retrieve has been completed. This is a good way to look at the available fields or add some extra logic once the retrieve task has been completed.
To access this, the following code can be added the following code to the component:
// app.component.ts
import {Component, HostListener} from '@angular/core';
....
export class AppComponent {
@HostListener('document:afdRetrieveComplete', ['$event'])
onAfdRetrieveComplete(e: any) {
console.log(e.detail.body['Item'][0]);
}
constructor(
public afdPceService: AfdPceService,
) {}
}
By default the control has no style applied to it so that developers can easily apply their own styles. We do supply a css file with some sample code that can be used as a starter:
/node_modules/@afd-software/pce-angualr/typeahead.css
If you are using the Angular Material design framework we have a prebuilt Autocomplete control.
First install the @afd-software/pce-angular-material
module. This is in addition to the base @afd-software/angular-pce
modue.
npm install --save @afd-software/pce-angular-material
Import the module into your project:
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AfdPceAngularModule } from '@afd-software/pce-angular';
import { AfdPceAngularMaterialModule } from '@afd-software/pce-angular-material';
....
@NgModule({
declarations: [
AppComponent,
....
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
AfdPceAngularModule,
AfdPceAngularMaterialModule,
....
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Then in your template:
Card validation happens via three attribute directives. The first two of these check that the structure of the card number and the expiry date are correct. If both of these checks return valid then a validation directive that is placed on the parent form will fire and validate the pair of values against PCE. In addition to validation it is also possible to mask the inputs so that they are formatted correctly and extract information about the card.
As each call to PCE is charged for we do not want to send validation requests for numbers that are clearly not valid. As such, we first try to validate the card number and expiry date via a regular expression check and only when the patterns are valid do we request validation from PCE. For this first stage we have two attribute directives afdCardRegexValid
and afdExpiryRegexValid
, these should each be placed on the relevant input.
Once both of these controls are valid we then want to query PCE to validate the combination. To do this we place the afdCardPceValid
directive to the parent form.
Important: It is essential that you include both of these base directives in the controls. If you only use afdCardPceValid
you will request validation from PCE on each keystroke which will raise excessive charges.
The error state of the controls are accessible via both the Angular Form Control API and the Constraint Validation API.
We recommend using the form control API, to do so you must specify a template reference variable and set its value to ngModel
on the inputs and ngForm
on the form (e.g. #cardControl=”ngModel”). You also need to bind ngModel
to a variable in your class that will hold the value of the control.
When there is a regex validation error on either of the controls or on the form, one of the objects afdCardRegexValid
, afdExpiryPceValid
or afdCardPceValid
depending on the origin will be added to the errors
object of the control or form. The object contains an object with a single key value pair {message: 'Error Message'}
. This error can be customised in the settings object of the afdPceService.
The named control (e.g. cardControl
) is accessible both in the template, and also can be sent to the class via events such as (ngModelChange)
.
In the template it is useful to add helper messages that display when there is a validation error. *ngIf
can be used to display errors depending on the error that is displayed using the .hasError
function.
// app.component.ts
// ....
export class AppComponent{
// ....
changeModel(val, form, cardControl, expiryControl){
console.log(val);
console.log(form);
console.log(cardControl);
console.log(expiryControl);
}
// ....
}
It is possible to know some things about a card even before its number has been input in its entirety. We allow access to this via an Observable on the AfdPceService
.
To access this in your component use the following code:
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { AfdPceService } from '@afd-software/pce-angular';
import { Subscription } from 'rxjs';
....
export class AppComponent implements OnInit {
//....
cardInfoSubscription: Subscription | undefined;
cardInfo: any;
constructor(
public afdPceService: AfdPceService
) { }
ngOnInit() {
....
this.cardInfoSubscription = this.afdPceService.cardInfo.subscribe(data => {
this.cardInfo = data;
});
}
}
And then in your template:
-
Card Regex Valid:{{cardInfo.cardRegexValid}}
-
Expiry Regex Valid:{{cardInfo.expiryRegexValid}}
-
PCE Valid:{{cardInfo.pceValid}}
-
Card Type Nice:{{cardInfo.cardTypeNice}}
-
Card Type:{{cardInfo.cardType}}
-
Card Number: {{cardInfo.cardNumber}}
-
Expiry Date: {{cardInfo.expiryDate}}
The full cardInfo object looks like this:
cardInfo: {
pceValid: boolean,
cardRegexValid: boolean,
expiryRegexValid: boolean,
cardTypeNice: string,
cardType: string,
cardNumber: string,
expiryDate: string
};
It is possible to apply masks to the inputs to prevent invalid characters from being added and to format the inputs correctly. The card will add the spaces correctly to the field depending on the card type and the expiry date will be formatted in a mm / yyyy
format. To do this simply add the [textmask]
directive to the inputs as shown below.
Below is an example template for using Angular Material with the card validation directive:
// app.component.html
Card Number Validation
Card Regex Valid:{{cardInfo.cardRegexValid}}
Expiry Regex Valid:{{cardInfo.expiryRegexValid}}
PCE Valid:{{cardInfo.pceValid}}
Card Type Nice:{{cardInfo.cardTypeNice}}
Card Type:{{cardInfo.cardType}}
Card Number: {{cardInfo.cardNumber}}
Expiry Date: {{cardInfo.expiryDate}}
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { AfdPceService } from '@afd-software/pce-angular';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'app-component',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit {
cardInfoSubscription: Subscription;
cardInfo = null;
card;
expiry;
constructor(
public afdPceService: AfdPceService
) {}
ngOnInit() {
this.cardInfoSubscription = this.afdPceService.cardInfo.subscribe(data => {
this.cardInfo = data;
});
}
}
Bank Account validation happens via three attribute directives. The first two of these check that the structure of the account number and the sort code are correct. If both of these checks return valid then a validation directive that is placed on the parent form will fire and validate the pair of values against PCE. In addition to validation it is also possible to mask the inputs so that they are formatted correctly, and also extract information about the bank account.
As each call to PCE is charged for we do not want to send validation requests for numbers that are clearly not valid. As such, we first try to validate the account number and sort code via a regular expression check and only when the patterns are valid do we request validation from PCE. For this first stage we have two attribute directives afdAccountRegexValid
and afdSortRegexValid
, these should each be placed on the relevant input.
Once both of these controls are valid we then want to query PCE to validate the combination. To do this we place the afdAccountPceValid
directive to the parent form.
Important: It is essential that you include both of these base directives in the controls. If you only use afdAccountPceValid
you will request validation from PCE on each keystroke which will raise excessive charges.
The error state of the controls are accessible via both the Angular Form Control API and the Constraint Validation API.
We recommend using the form control API, to do so you must specify a template reference variable and set its value to ngModel
on the inputs and ngForm
on the form (e.g. #accountControl=”ngModel”). You also need to bind ngModel
to a variable in your class that will hold the value of the control.
When there is a regex validation error on either of the controls or on the form, one of the objects afdAccountRegexValid
, afdSortPceValid
or afdAccountPceValid
depending on the origin will be added to the errors
object of the control or form. The object contains an object with a single key value pair {message: 'Error Message'}
. This will be an error either set in the settings object of the afdPceService.
The named control (e.g. accountControl
) is accessible both in the template, and also can be sent to the class via events such as (ngModelChange)
.
In the template it is useful to add helper messages that display when there is a validation error. *ngIf
can be used to display errors depending on the error that is displayed using the .hasError
function.
// app.component.ts
// ....
export class AppComponent{
// ....
changeModel(val, form, accountControl, sortControl){
console.log(val);
console.log(form);
console.log(accountControl);
console.log(sortControl);
}
// ....
}
It is possible to know some things about an account even before its number has been input in its entirety. We allow access to this via an Observable on the AfdPceService
.
To access this in your component use the following code:
// app.component.ts
import {Component, OnInit} from '@angular/core';
import {AfdPceService} from '@afd-software/pce-angular';
import {Subscription} from 'rxjs';
....
export class AppComponent implements OnInit {
....
accountInfoSubscription: Subscription;
accountInfo = null;
constructor(
private afdPceService: AfdPceService
) {}
ngOnInit() {
....
this.accountInfoSubscription = this.afdPceService.accountInfo.subscribe(data => {
this.accountInfo = data;
});
}
And then in your template:
-
Account Number Regex Valid: {{ accountInfo.accountRegexValid }}
-
Sort Code Regex Valid: {{accountInfo.sortRegexValid}}
-
PCE Valid: {{accountInfo.pceValid}}
-
IBAN: {{accountInfo.iban}}
-
Clearing System: {{accountInfo.clearingSystem}}
-
Account Type: {{accountInfo.accountType}}
-
Account Number: {{accountInfo.accountNumber}}
-
Sort Code: {{accountInfo.sortCode}}
The full accountInfo object looks like this:
accountInfo: {
pceValid: boolean,
accountRegexValid: boolean,
sortRegexValid: boolean,
iban: string,
clearingSystem: string,
rollNumber: string,
accountType: string,
accountNumber: string,
sortCode: string
}
It is possible to apply masks to the inputs to prevent invalid characters from being added and to format the inputs correctly. The account field will only allow for eight numerical characters and the sortcode will be formatted in a 00-00-00
format. To do this simply add the [textmask]
directive to the inputs as shown below.
Below is an example template for using Angular Material with the bank account validation directive:
// app.component.html
Account Number Validation
Account Number Regex Valid: {{ accountInfo.accountRegexValid }}
Sort Code Regex Valid: {{accountInfo.sortRegexValid}}
PCE Valid: {{accountInfo.pceValid}}
IBAN: {{accountInfo.iban}}
Clearing System: {{accountInfo.clearingSystem}}
Account Type: {{accountInfo.accountType}}
Account Number: {{accountInfo.accountNumber}}
Sort Code: {{accountInfo.sortCode}}
// app.component.ts
import {Component, HostListener, Output, EventEmitter, OnInit} from '@angular/core';
import { AfdPceService, Countries } from '@afd-software/pce-angular';
import {Subscription} from 'rxjs/Subscription';
@Component({
selector: 'app-component[fxLayout="column"]',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit {
accountInfoSubscription: Subscription;
accountInfo = null;
account;
sort;
constructor(
public afdPceService: AfdPceService
) {}
ngOnInit() {
this.accountInfoSubscription = this.afdPceService.accountInfo.subscribe(data => {
this.accountInfo = data;
});
}
}
Phone validation happens via two attribute directives that are added to to an input control. In addition to validation it is also possible to mask the input so that it is formatted like a phone number, and extract information about the phone number.
As each call to PCE is charged for we do not want to send validation requests for numbers that are clearly not valid. As such, we first try to validate the phone number via Regex and only when the pattern is valid do we request validation from PCE. For this we have two attribute directives afdPhoneRegexValid
and afdPhonePceValid
.
Important: It is essential that you include both of these directives. If you only use afdPhonePceValid
you will request validation from PCE on each keystroke which will raise excessive charges.
You can optionally provide a [country]
(ISO2). This is the country that the control will assume if no country code is input. Specifying a country when typing, either using +
or ’00’ at the beginning of the number will override this option.
The error state of the control is accessible via both the Angular Form Control API and the Constraint Validation API.
We recommend using the form control API, to do so you must specify a template reference variable and set its value to ngModel
(e.g. #phoneControl=”ngModel”). You also need to bind ngModel
to a variable in your class that will hold the value of the control.
When there is a validation error one of the objects afdPhoneRegexValid
or afdPhonePceValid
depending on the origin will be added to the errors
object of the control. The object contains an object with a single key value pair {message: 'Error Message'}
. This will be an error either set in the settings or returned from PCE.
The phoneControl
is accessible both in the template, and also can be sent to the class via events (such as (ngModelChange).
In the template it is useful to add helper messages that display when there is a validation error. *ngIf
can be used to display errors depending on the error that is displayed using the .hasError
function.
>
This field is required
{{phoneControl.errors.afdPhoneRegexValid.message}}
{{phoneControl.errors.afdPhonePceValid.message}}
// app.component.ts
// ....
export class AppComponent{
// ....
changeModel(val, control){
console.log(val);
console.log(control);
}
// ....
}
The validator will also format the phone number according to the formatting rules of the country of the phone.
It is possible to know some things about a phone number even before it has been input in its entirety. We allow access to this via an Observable on the AfdPceService
.
To access this in your component use the following code:
// app.component.ts
import {Component, OnInit} from '@angular/core';
import {AfdPceService} from '@afd-software/pce-angular';
import {Subscription} from 'rxjs';
....
export class AppComponent implements OnInit {
....
phoneInfoSubscription: Subscription;
phoneInfo = null;
constructor(
private afdPceService: AfdPceService
) {}
ngOnInit() {
....
this.phoneInfoSubscription = this.afdPceService.phoneInfo.subscribe(data => {
this.phoneInfo = data;
});
}
And then in your template:
- {{ phoneInfo.regexValid }}
- {{ phoneInfo.country.name }}
The full phoneInfo object looks like this:
phoneInfo: {
pceValid: boolean,
regexValid: boolean,
country: {
name: string,
iso2: string,
iso3: string
},
isMobile: boolean,
isLandLine: boolean
};
It is possible to apply a mask to the input that prevents the input of anything except numbers and a “+” symbol in the first position of the input. To do this simply add the [textmask]
directive to the input as shown below.
Below is an example template for using Angular Material with the phone validation directive:
// app.component.html
Phone Number Validation
{{afdPceService.settings.messages.phone.required}}
{{phoneControl.errors['afdPhoneRegexValid'].message}}
{{phoneControl.errors['afdPhonePceValid'].message}}
Regex Valid: {{ phoneInfo.regexValid }}
PCE Valid: {{ phoneInfo.pceValid }}
Country: {{ phoneInfo.country.name }}
Country ISO2: {{ phoneInfo.country.iso2 }}
Country ISO3: {{ phoneInfo.country.iso3 }}
Is Mobile: {{ phoneInfo.isMobile }}
Is LandLine: {{ phoneInfo.isLandLine }}
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { AfdPceService, Countries } from '@afd-software/pce-angular';
import { MatDialog } from '@angular/material';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'app-component',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit {
phone;
countries = Countries;
phoneInfoSubscription: Subscription;
hasPhoneInfo = false;
phoneInfo = null;
constructor(
public afdPceService: AfdPceService
) {
this.afdPceService.phoneCountry = this.countries[234];
}
ngOnInit() {
this.phoneInfoSubscription = this.afdPceService.phoneInfo.subscribe(data => {
this.phoneInfo = data;
});
}
}
Email validation happens via two attribute directives that are added to to an input control.
As each call to PCE is charged for we do not want to send validation requests for email addresses that are clearly not valid. As such, we first try to validate the email address via Regex and only when the pattern is valid do we request validation from PCE. For this we have two attribute directives afdEmailRegexValid
and afdEmailPceValid
.
Important: It is essential that you include both of these directives. If you only use afdEmailPceValid
you will request validation from PCE on each keystroke which will raise excessive charges.
The error state of the control is accessible via both the Angular Form Control API and the Constraint Validation API.
We recommend using the form control API, to do so you must specify a template reference variable and set its value to ngModel
(e.g. #emailControl=”ngModel”). You also need to bind ngModel
to a variable in your class that will hold the value of the control.
When there is a validation error one of the objects afdEmailRegexValid
or afdEmailPceValid
depending on the origin will be added to the errors
object of the control. The object contains an object with a single key value pair {message: 'Error Message'}
. This will be an error either set in the settings or returned from PCE.
The emailControl
is accessible both in the template, and also can be sent to the class via events (such as (ngModelChange).
In the template it is useful to add helper messages that display when there is a validation error. *ngIf
can be used to display errors depending on the error that is displayed using the .hasError
function.
>
This field is required
{{emailControl.errors.afdEmailRegexValid.message}}
{{emailControl.errors.afdEmailPceValid.message}}
// app.component.ts
// ....
export class AppComponent{
// ....
changeModel(val, control){
console.log(val);
console.log(control);
}
// ....
}
It is possible to know some extra things about an email address. We allow access to this via an Observable on the AfdPceService
.
To access this in your component use the following code:
// app.component.ts
import {Component, OnInit} from '@angular/core';
import {AfdPceService} from '@afd-software/pce-angular';
import {Subscription} from 'rxjs';
....
export class AppComponent implements OnInit {
....
emailInfoSubscription: Subscription;
emailInfo = null;
constructor(
private afdPceService: AfdPceService
) {}
ngOnInit() {
....
this.emailInfoSubscription = this.afdPceService.emailInfo.subscribe(data => {
this.emailInfo = data;
});
}
And then in your template:
- {{ emailInfo.regexValid }}
- {{ emailInfo.pceValidationMessage }}
The full emailInfo object looks like this:
emailInfo: {
pceValid: boolean,
regexValid: boolean,
pceValidationMessage: string,
emailAddress: string
};
Below is an example template for using Angular Material with the email validation directive:
// app.component.html
Email Validation
{{afdPceService.settings.messages.email.required}}
{{emailControl.errors['afdEmailRegexValid'].message}}
{{emailControl.errors['afdEmailPceValid'].message}}
Regex Valid: {{ emailInfo.regexValid }}
PCE Valid: {{ emailInfo.pceValid }}
PCE Message: {{ emailInfo.pceValidationMessage }}
Email Address: {{ emailInfo.emailAddress }}
// app.component.ts
import {Component, HostListener, OnInit} from '@angular/core';
import {AfdPceService } from '@afd-software/pce-angular';
import {Subscription} from 'rxjs/Subscription';
@Component({
selector: 'app-component',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit{
email;
emailInfoSubscription: Subscription;
emailInfo = null;
constructor(
public afdPceService: AfdPceService
) {}
ngOnInit() {
this.emailInfoSubscription = this.afdPceService.emailInfo.subscribe(data => {
this.emailInfo = data;
});
}
}