Skip to the content

Salesforce Plugin

Our plugin for Salesforce supports lightning and contains the following features:

  • PredictiveAddress
  • Company Information Lookup
  • TPS and CTPS checking
  • Bank Account Validation
  • International Telephone Validation
  • Telephone Formatting
  • Email Validation
  • Unusable Name Validation

Salesforce Plugin Compatibility

Our Salesforce plugin makes use of the lightning update to integrate PredictiveAddress, real-time validation, and TPS checking (amongst a variety of other services) into record forms for standard and custom objects and can even be applied to custom fields.

Installation

To install the Data8 Salesforce plugin, click the link to be taken to the installation wizard. Login to your Salesforce instance and click the 'Install' button. Agree to allowing requests to the 'webservices.data-8.co.uk' domain as this is necessary for our validation API's to work.

Should you ever wish to uninstall the Data8 Salesforce plugin, first revert any changes made to object page layouts and button overrides. Finally go to Setup > Packages > Installed Packages and uninstall the Data8 plugin.

Configuration

From the Data8 settings page (accessed from the app launcher) you can enable and choose the services and validation options that suit your needs.

Settings

On the configuration screen, enter your Server API key found on your Data8 Dashboard. Each validation service requires the necessary credits to function.

Once again, the API Key you enter needs to be a Server-side key, which can be configured from the Data8 Dashboard.

Configuring objects to work with the Data8 plugin

To configure standard or custom objects to work with Data8 validation, override the 'Edit' and 'New' button functionality under the 'Button, Links and Actions' tab. This can be done from the 'Object Manager' from the 'Setup' menu. The 'Edit' and 'New' buttons for each object should be overridden with the appropriate Visualforce page. For example, Account should be overriden to use the Data8Validation_Account Visualforce page. Three Visualforce pages have already been created for you (Account, Contact and Lead). For custom objects, a Visualforce page will need to be created. The necessary code for this Visualforce page can be found at the bottom of this page.

Buttons, Links and Actions Override

There is a reported bug in Salesforce Lightning that can display old/out-of-date data on a record. Whilst Salesforce are working on a fix for this issue, we have created our own workaround fix for the issue. View a record of the object type for which you wish to apply the fix, click the cog at the top right and select 'Edit Page'. Drag and drop the Data8_Validation_CacheFix Visualforce page onto the page and then Save and Activate your page as Org Default.

Setting up bank validation

To use bank validation on your objects, simply set up the necessary fields (minimum account number and sort code) for each object you wish to use it with. A full list of fields that can be created can be found below:

  • Account Number
  • Sort Code
  • Bank Name
  • Branch Name
  • Bank Address
  • IBAN
  • BIC Code

You can then configure the mapping of these fields from the Data8 Settings page.

Setting up the company information lookup service

To use the Business Information lookup service, edit the 'Page Layout' of an object and drag the 'Get Company Information' button onto the layout. It is also recommended to add a 'Company' field and the appropriate 'Company Information' Visualforce page to the layout. To set up the Company Information Visualforce page for custom objects please contact our helpdesk.

Setting up TPS and CTPS

To use the TPS or CTPS checking service, set up a field on the desired object to store the TPS result. You will also need to create a field to store the last checked date if you are planning on using Batch processing to keep your TPS data up to date.

The 'Page Layout' of the object will also need editing, to add the TPS_Status Visualforce page (which displays the results of the TPS checks in a clean, easy to see format). This Visualforce page has been created for the Account, Contact and Lead objects. Other/custom objects will need this page creating. Please contact the helpdesk to obtain the code for this page.

The final step is to map the fields on the Data8 Settings page to finish the configuration.

Setting up geocoding within PredictiveAddress

The geocoding feature within predictive address will get the longitude and latitude of the entered and validated address. The geocoding feature requires custom fields to be created for each address type i.e. one for Shipping Address, one for Billing Address, one for Mailing Address etc.

The custom field should be of type Geolocation, which contains fields for latitude and longitude. These will be automatically populated when entering an address with predictive address. This will also populate the default hidden geolocation fields that are on the object such as ‘BillingLongitude’ on the Account object. You may want to edit the page layout of the object and place the custom geolocation field after the address fields.

One thing to note is that the custom fields should be named after the relative address i.e. Shipping Geolocation / Billing Geolocation etc.

Usage

After entering your configuration details and clicking save, the relevant services will be applied to various data entry points around your site, assuming they have been configured.

PredictiveAddress

When PredictiveAddress is enabled, any suitable address entry section on your forms will have use of our address autocomplete and verification tool. Simply begin typing an address/postcode/company name into the Address line 1 box to start searching and narrowing down results.

PredictiveAddress

Validation

If entered data is identified as invalid, the error will be highlighted suitably on the form.

When Telephone Validation is enabled, all suitable telephone number fields are validated automatically. There are also three other options available to you for further control of validation: Landline Validation, Mobile Validation and Default Country Code.

Option Description
Landline Validation If you have purchased our UK Landline Validation service, enable this option to use the enhanced level of validation for any UK landline numbers in addition to the standard level of validation provided by the International Telephone Validation service.
Mobile Validation If you have purchased our Mobile Validation service, , enable this option to use the enhanced level of validation for any mobile numbers in addition to the standard level of validation provided by the International Telephone Validation service.
Default Country Code The ISO 2-character country code or international dialling code of the country to validate the telephone number in, unless that number contains an explicit country code prefix.

When Email Validation is enabled, all suitable email address fields are validated automatically. The level of validation to apply to entered email addresses can be selected from a drop down on the settings page. See the table below for information on each level.

Email Validation Levels:

Level Description
Syntax The supplied email is checked to ensure that it meets the standard email address format. This is the quickest option and would reject such incorrect email addresses as "noone@nowhere" and "N/A", but would accept incorrect email addresses that are correctly formed but that do not include a valid domain name such as "noone@data-9.com".
Domain The supplied email is checked to ensure that the domain name (the part to the right of the @ sign) exists and is set up to receive email. This is still normally very quick, but can take a few seconds in some cases. This check would reject incorrectly formatted email addresses in the same way as the Syntax check, and would also reject a misspelled domain name such as "noone@data-9.com". It can also detect when a domain name exists but does not handle email, such as "noone@example.com". It does not verify that the part of the email address to the left of the @ sign exists.
Server In addition to the Domain level checks, validates that at least one of the mail servers advertised for the domain is actually live.
Address In addition to the Server level checks, validates that the mail server accepts mail for the full email address.

When Name Validation is enabled, all suitable name fields are validated automatically.

Bank Account Validation, when enabled will be performed on the mapped fields when saving a new/existing record.

Validation

TPS and CTPS

When enabled and with mapping configured, TPS and CTPS will be performed on the suitable fields when saving a new/existing record. The result will be output to the mapped output field. The results will also be displayed nicely with icons on the record details page.

TPS Checking

Custom Object Visualforce Page for Overriding Button Actions

This code can be pasted into the new visualforce page for the custom object. The Standard controller referenced in the script need to be edited to suit the new custom object in three locations (line 1, line 9 and line 19).
<apex:page standardController="Account">
    <apex:includeLightning />
    
    <div id="Data8_FormPlaceholder" />
    
    <link rel="stylesheet" href="https://webservices.data-8.co.uk/content/predictiveaddress.css" />
    <script type="text/javascript" src="https://webservices.data-8.co.uk/javascript/predictiveaddress.js"></script>
    <script>
        var recordId = '{!Account.id}';
    	var component;
    $Lightning.use("d8:Data8Validation_App", function() {
        $Lightning.createComponent(
            "d8:Data8Validation",
            {},
            "Data8_FormPlaceholder",
            function(cmp) {                   
                cmp.set("v.attachPAFunction", myAttachPredictiveAddress);
                cmp.set("v.recordId", recordId);
                cmp.set("v.objectType","Account");
                cmp.set("v.showObjectTypeSelect", false);
                cmp.set("v.handleErrorsFunction", handleErrors);
                cmp.set("v.clearErrorsFunction", clearFormErrors);
                cmp.set("v.enableInlineEditFunction", enableInlineEdit);
                cmp.set("v.attachOnChange", attachOnChange);
                cmp.set("v.emailSuggestedChangeFunction", emailSuggestedChange);
                component = cmp;
            });
    });
    var setComponentDirtyField = function(fieldNames){
        component.setDirtyField(fieldNames);
    }
    
    </script>
    <script type="text/javascript">
    function myAttachPredictiveAddress(apiKey, maxLineLength, unwantedPunctuation, allowedCountries, barredCountries, includeNYB, includeMR, includeLocation){
        var addresses = window.document.getElementsByTagName("LIGHTNING-INPUT-ADDRESS");
        for(var i=0; i<addresses.length; i++){
            var street = addresses[i].getElementsByTagName("TEXTAREA")[0];
            
            if(street && street.name == "street" && !street.classList.contains("data8-predictiveaddress")){
                
                var longitude = "";
                var latitude = "";
                
                if(includeLocation){
                    var placeholder = street.placeholder;
                    var subtractWord = ' Street';
                    var addressParent = placeholder.slice(0, -subtractWord.length); // i.e Shipping / Billing
                    addressParent = addressParent.toLowerCase();
                    
                    // If using custom fields of type Geolocation for lat long
                    var locationFields = document.getElementsByTagName("LIGHTNING-INPUT-LOCATION");
                    for(var j=0; j<locationFields.length; j++){
                        if(!longitude || !latitude){
                            var locationField = locationFields[j];
                            var geolocationNameField = locationField.getElementsByTagName("LEGEND")[0];
                            if(geolocationNameField)
                                var geolocationName = geolocationNameField.innerText.toLowerCase();
                            
                            if(geolocationName && geolocationName.includes(addressParent)){
                                    
                                var locationInputs = locationField.getElementsByTagName("INPUT");
                                
                                for(var k = 0; k < locationInputs.length; k++){
                                    if(!longitude || !latitude){
                                        if(locationInputs[k].name.toLowerCase().includes("longitude")){
                                            longitude = locationInputs[k].id;
                                            continue;
                                        }
                                        
                                        if(locationInputs[k].name.toLowerCase().includes("latitude")){
                                            latitude = locationInputs[k].id;
                                            continue;
                                        }
                                        
                                    }
                                    else
                                        break;
                                }
                            }
                        }
                        else
                            break;
                    }
                    
                    // If using custom fields of type Text for lat long
                    if(!longitude || !latitude){
                        var allInputs = document.getElementsByTagName("INPUT");
                        for(j=0; j<allInputs.length; j++){
                            if(!longitude || !latitude){
                                var inputName = allInputs[j].name.toLowerCase();
                                if(inputName.includes(addressParent)){
                                    if(inputName.includes("longitude"))
                                        longitude = allInputs[j].id;
                                    else if(inputName.includes("latitude"))
                                        latitude = allInputs[j].id;
                                }
                            }
                            else
                                break;
                        }
                    }
                }
                
                var inputFields = addresses[i].getElementsByTagName("INPUT");
                
                for (var x=0; x<inputFields.length; x++){
                    if(inputFields[x].name === "city")
                        city = inputFields[x].id;
                    if(inputFields[x].name === "province")
                        province = inputFields[x].id;
                    if(inputFields[x].name === "postalCode")
                        postalCode = inputFields[x].id;
                    if(inputFields[x].name === "country")
                        country = inputFields[x].id;
                }
                
                var streetId = street.id;
                
                AddPA(apiKey, street, streetId, city, province, postalCode, country, maxLineLength, unwantedPunctuation, allowedCountries, barredCountries, includeNYB, includeMR, includeLocation, longitude, latitude);
            }
        }
        
        var inputs = window.document.getElementsByTagName("INPUT");
        for(var i=0; i<inputs.length; i++){
            var index = inputs[i].name.toLowerCase().indexOf("_street");
            if(index != -1){
                // assume there is a custom address field as standard street fields are of type text-area not input
                var inputName = inputs[i].name;
                var addressPrefix = inputName.substring(0, index);
                if(addressPrefix){
                    var street = inputs[i];
                    var streetId = street.id;
                    var city = "";
                    var province = "";
                    var postalCode = "";
                    var country = "";
                    var longitude = "";
                    var latitude = "";
                    
                    var cityElem = document.getElementsByName(addressPrefix + "_City__c")[0];
                    if(!cityElem)
                        cityElem = document.getElementsByName(addressPrefix + "_city__c")[0];
                    if(cityElem)
                        city = cityElem.id;
                    
                    var provinceElem = document.getElementsByName(addressPrefix + "_Province__c")[0];
                    if(!provinceElem)
                        provinceElem = document.getElementsByName(addressPrefix + "_province__c")[0];
                    if(provinceElem)
                        province = provinceElem.id;
                    
                    var postalCodeElem = document.getElementsByName(addressPrefix + "_PostalCode__c")[0];
                    if(!postalCodeElem)
                        postalCodeElem = document.getElementsByName(addressPrefix + "_postalCode__c")[0];
                    if(postalCodeElem)
                        postalCode = postalCodeElem.id;
                    
                    var countryElem = document.getElementsByName(addressPrefix + "_Country__c")[0];
                    if(!countryElem)
                        countryElem = document.getElementsByName(addressPrefix + "_country__c")[0];
                    if(countryElem)
                        country = countryElem.id;
                    
                    var longitudeElem = document.getElementsByName(addressPrefix + "_Longitude__c")[0];
                    if(!longitudeElem)
                        longitudeElem = document.getElementsByName(addressPrefix + "_longitude__c")[0];
                    if(longitudeElem)
                        longitude = longitudeElem.id;

                    var latitudeElem = document.getElementsByName(addressPrefix + "_Latitude__c")[0];
                    if(!latitudeElem)
                        latitudeElem = document.getElementsByName(addressPrefix + "_latitude__c")[0];
                    if(latitudeElem)
                        latitude = latitudeElem.id;                    
                    
                    if(street && streetId && postalCode)
                        AddPA(apiKey, street, streetId, city, province, postalCode, country, maxLineLength, unwantedPunctuation, allowedCountries, barredCountries, includeNYB, includeMR, includeLocation, longitude, latitude);
                }
            }
        }
    }
    
    function AddPA(apiKey, street, _street, _city, _province, _postalCode, _country, maxLineLength, unwantedPunctuation, allowedCountries, barredCountries, includeNYB, includeMR, includeLocation, longitude, latitude){
        new data8.predictiveaddressui(street, {
            ajaxKey: apiKey,
            applicationName: 'Salesforce',
            initialCountry: 'auto',
            allowedCountries: allowedCountries,
            barredCountries: barredCountries,
            maxLineLength: maxLineLength,
            unwantedPunctuation: unwantedPunctuation,
            includeNYB: includeNYB,
            includeMR: includeMR,
            includeLocation: includeLocation,
            fields: [
                { element: _street, field: 'line1' },
                { element: _city, field: 'town' },
                { element: _province, field: 'county' },
                { element: _postalCode, field: 'postcode' },
                { element: _country, field: 'country' }
            ],
            selectAddress: function(address){
                var streetElem = document.getElementById(_street);
                var cityElem = document.getElementById(_city);
                var provinceElem = document.getElementById(_province);
                var postalCodeElem = document.getElementById(_postalCode);
                var countryElem = document.getElementById(_country);
                
                if(longitude){
                    var longitudeElem = document.getElementById(longitude);
                    if(longitudeElem){
                        longitudeElem.value = address.RawAddress.Location.Longitude;
                        triggerEvent(longitudeElem, 'input');
                    }
                }
                
                if(latitude){
                    var latitudeElem = document.getElementById(latitude);
                    if(latitudeElem){
                        latitudeElem.value = address.RawAddress.Location.Latitude;
                        triggerEvent(latitudeElem, 'input');
                    }
                }
                    
                if(streetElem)
                    triggerEvent(streetElem, 'input');
                
                if(cityElem)
                    triggerEvent(cityElem, 'input');
                
                if(provinceElem)
                    triggerEvent(provinceElem, 'input');
                
                if(postalCodeElem)
                    triggerEvent(postalCodeElem, 'input');
                
                if(countryElem)
                    triggerEvent(countryElem, 'input');
            }
        });
    }
    
    function triggerEvent(el, type){
        if ('createEvent' in document) {
            // modern browsers, IE9+
            var e = document.createEvent('HTMLEvents');
            e.initEvent(type, false, true);
            el.dispatchEvent(e);
        } else {
            // IE 8
            var e = document.createEventObject();
            e.eventType = type;
            el.fireEvent('on'+e.eventType, e);
        }
    }
    
    function enableInlineEdit(){
        var editButtons = document.getElementsByTagName("svg");
        var editButton;
        for(var i=0; i<editButtons.length; i++){
            if(editButtons[i].getAttribute("data-key") == "edit"){
                editButton = editButtons[i];
                break;
            }
        }
        
        if(editButton){
            var button = editButton.closest("button");
            button.click();
        }
    }
    
    function handleErrors(fieldName, errored){
        var element = document.getElementsByName(fieldName)[0];
        if(element){
            element.classList.toggle("slds-has-error", errored);
        }
    }
    
    function clearFormErrors(){
        var element = document.getElementsByClassName("data8Form")[0];
        if(element){
            var inputs = document.getElementsByTagName("input");
            for(var i=0; i<inputs.length; i++){
                inputs[i].classList.remove("slds-has-error");
            }
        }
    }
    
    function emailSuggestedChange(fieldName, suggestedEmail, bAdd){
        var element = document.getElementsByName(fieldName)[0];
        if(element){
            if(fieldName == "Email" || element.getAttribute("type") === "email"){
                if(bAdd){
                    var parent = element.parentNode;
                    if(parent){
                        var alertDiv = document.createElement("div");
                        alertDiv.style = "margin-top:2px; padding:5px; background-color:#ffffdc; border:1px solid #f8e38e;"
                        alertDiv.classList.add("data8-warning");
                        alertDiv.innerHTML = "Did you mean: '" + suggestedEmail + "'?";
                        
                        parent.insertBefore(alertDiv, element.nextSibling);
                    }
                }
                else{
                    var parent = element.parentNode;
                    if(parent){
                        var alertDiv = parent.getElementsByClassName("data8-warning")[0];
                        if(alertDiv)
                            element.parentNode.removeChild(alertDiv);
                    }
                }
            }
        }
    }
    
    function attachOnChange(){
        var form = document.querySelector('form');
        if(form){
        	form.addEventListener('change', function() {
            if(event.target.nodeName == "LIGHTNING-INPUT-FIELD"){
            	var fields = event.target.getElementsByTagName("INPUT");
                if(!fields)
                    fields = event.target.getElementsByTagName("TEXTAREA");
                if(!fields)
                    fields = event.target.getElementsByTagName("SELECT");
                
                if(fields){
                    var nameList = [];
                    for(var i=0; i < fields.length; i++){
                    	nameList.push(fields[i].name);
                    }
                    setComponentDirtyField(nameList);
                    }
            }
            else if(event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA" ||event.target.nodeName == "SELECT")
                setComponentDirtyField(event.target.id);
        });
        }
    }
    </script>
</apex:page>

Email Validation Blogs

The number of returned mail reduced by 28% as a result of the integrated reference to the goneaway file

Business Strategy Manager, Brookson Ltd

Start a Free 30 Day Trial Today

Start a free trial today