OnChange part 3: Where is the clearOnChange method?

The Microsoft Dynamics CRM SDK comes with lots of functionality to affect how CRM behaves on the client side.
In a couple of articles I will discuss the opportunities ventilate my frustration over run-time event handling manipulation.

My first article in this series covered problems when trying to remove design-time defined onChange events in run-time using removeOnChange. The second one covered problems with context awareness after manipulating event handlers using addOnChange. To sum up the difficulties described in the two previous articles, it would be very useful to be able to say

Ok, I cannot remove the design-time event handlers, and there are some issues with manually added event handlers. So please, remove everything to give me a clean slate!

But there is no method to clear an attribute from all current event handlers.

To be able to remove an event handler, you must know its exact syntax. And you just can’t remove event handlers that were introduced design-time. It seems that introducing addOnChange and removeOnChange had a good intention and was a nice try, but they definitely didn’t go all the way.

OnChange part 2: addOnChange with context awareness

The Microsoft Dynamics CRM SDK comes with lots of functionality to affect how CRM behaves on the client side.
In a couple of articles I will discuss the opportunities ventilate my frustration over run-time event handling manipulation.

My first article in this series covered problems when trying to remove design-time defined onChange events in run-time. This article will cover some issues with “context awareness” that you may encounter when using addOnChange to alter the events firing from changes in the form. A javascript web resource for a form typically has some event handlers and some business logic methods, all contained in a javascript “namespace” according to recommendations in the SDK, see section Namespaced library names. It may look something like this:

Cinteros.JR.account = {

    // ---- Event handlers ---- //

    formLoad: function () {
        var attribute = Xrm.Page.getAttribute("numberofemployees");
        attribute.removeOnChange(Cinteros.JR.account.numberofemployees_onChange);
        attribute.addOnChange(Cinteros.JR.account.numberofemployees_onChange_with_vat);
    },

    numberofemployees_onChange: function () {
        var avgSalary = Xrm.Page.getAttribute("jr_avgsalary").getValue();
        var empCount = Xrm.Page.getAttribute("numberofemployees").getValue();
        var salaryCost = this.multiply(avgSalary, empCount);
        Xrm.Page.getAttribute("jr_salarycost").setValue(salaryCost);
    },

    numberofemployees_onChange_with_vat: function () {
        var avgSalary = Xrm.Page.getAttribute("jr_avgsalary").getValue();
        var empCount = Xrm.Page.getAttribute("numberofemployees").getValue();
        var vat = Xrm.Page.getAttribute("jr_vat_level").getValue();
        var salaryCost = this.multiply(avgSalary, empCount);
        var netsalaryCost = salaryCost - this.multiply(salaryCost, vat);
        Xrm.Page.getAttribute("jr_salarycost").setValue(netsalaryCost);
    },

    // ---- Business logic methods ---- //

    multiply: function (a, b) {
        return a * b;
    }
}

Notice how the internal method multiply is called by using syntax

  this.multiply(a, b);

This indicates that it is a method in the same (current) “namespace”. This works fine and as expected when the event handler (numberofemployees_onChange in this case) has been added in the form customizations.
But when the event handler is added using attibute.addOnChange, it is not the call to the method that is passed to the function, but rather the “contents” of it. This in turn does not have a clue about my namespace, when executed.
An alternative could be to try to wrap my my function in a caller when adding it:

attribute.addOnChange(function () { Cinteros.JR.account.numberofemployees_onChange_with_vat(); });

This works, but makes the code harder to read and easier to get wrong. Note that the same – exactly the same – wrapper method must be used if you want to un-hook the event handler using attribute.removeOnChange. And even when trying that, I failed to get the remove function to work as expected.

Alternative javascript strategy

The alternative strategy described in the SDK discuss making methods unique by simply defining a specific prefix for all functions, and declaring them somthing like this:

// ---- Event handlers ----
function Cinteros_JR_account_formLoad() {
    var nameAttribute = Xrm.Page.getAttribute("name");
    nameAttribute.removeOnChange(Cinteros_JR_account_name_onChange);
    nameAttribute.addOnChange(Cinteros_JR_account_name_onChange_special);
    nameAttribute.addOnChange(function () { Cinteros_JR_account_name_onChange_special(); });
};

function Cinteros_JR_account_name_onChange() {
    var avgSalary = Xrm.Page.getAttribute("jr_avgsalary").getValue();
    var empCount = Xrm.Page.getAttribute("numberofemployees").getValue();
    var salaryCost = Cinteros_JR_account_multiply(avgSalary, empCount);
    Xrm.Page.getAttribute("jr_salarycost").setValue(salaryCost);
};

function Cinteros_JR_account_name_onChange_special() {
    var avgSalary = Xrm.Page.getAttribute("jr_avgsalary").getValue();
    var empCount = Xrm.Page.getAttribute("numberofemployees").getValue();
    var salaryCost = Cinteros_JR_account_multiply(avgSalary, empCount);
    var vat = Xrm.Page.getAttribute("jr_vat_level").getValue();
    var netsalaryCost = Cinteros_JR_account_multiply(salaryCost, vat);
    Xrm.Page.getAttribute("jr_salarycost").setValue(netsalaryCost);
};

    // ---- Business logic methods ----

function Cinteros_JR_account_multiply(a, b) {
    return a * b;
};

This is a strategy I don’t like very much. The “JScript object to create a kind of namespace” (as Microsoft puts it) provides better source code management and maintainability, and is simply far more appealing.
But unfortunately, it does not work when you use the SDK functions to manipulate event handlers.
(Again, I wish someone will prove me wrong in this. Can’t wait to write that apology to the Dynamics team…!)

To Be Continued… OnChange part 3: Where is the clearOnChange method?

OnChange part 1: Remove design-time event handlers

The Microsoft Dynamics CRM SDK comes with lots of functionality to affect how CRM behaves on the client side.
In a couple of articles I will discuss the opportunities ventilate my frustration over run-time event handling manipulation.

Events reacting to changes in fields can be defined design-time by making customizations to forms, and run-time by adding onChange event handlers by calling attribute.addOnChange(eventHandler).
To change the behavior run-time, there is also a method to remove designated event handlers by calling attribute.removeOnChange(eventHandler).
Read more about this in the SDK.

It is however not possible to remove event handlers that were added design-time.

The definition of methods addOnChange and removeOnChange are quite straight forward. You pass a function pointer to the method you want to add or remove. Much like you do when you define event handlers design-time. account.name.onchange In a scenario where a field is designed to have a specific event handler and you want to remove it to be replaced by another one, you would think that you call removeOnChange with the method name as entered in the customizations. Sample form library:

Cinteros.JR.account = {
    formLoad: function () {
        var nameAttribute = Xrm.Page.getAttribute("name");
        nameAttribute.removeOnChange(Cinteros.JR.account.name_onChange);
        nameAttribute.addOnChange(Cinteros.JR.account.name_onChange_special);
    },

    name_onChange: function () {
        // Do standard things with name attribute
        Xrm.Utility.alertDialog("Normal function"); 
    },

    name_onChange_special: function () {
        // Do special things with name attribute
        Xrm.Utility.alertDialog("Special function"); 
    }
}

I discovered that the call to removeOnChange had no effect in this scenario. But the addOnChange added the new method as event handler. So I started digging using the F12 debugger in my browser. What does the function really do? And why does it fail silently?
All events firing on field changes in a form are stored in one of two arrays. The first one contains “Sys.EventHandlerList” items that are events defined by CRM itself or by customization. The second one contains the “dynamic events” added by the addOnChange method.
When removing events, both of these arrays are investigated for the function to remove. So why then does it not find and remove the function as I want it to?
The answer lies in what is actually contained in these arrays. When I step my way down the internal functions of CRM, I am able to investigate what an event handler from customization according to the image above will result in within that array, and how it is matched from the removeOnChange function.
The list of event handlers from customization above contains this:

[
    function name_onchange_handler(eventObj, eventArgs) {
        try {
            var eContext = Mscrm.FormUtility.constructExecutionObject(eventObj, 0, null, null);
            eContext = Mscrm.FormUtility.constructExecutionObject(eventObj, 0, null, eContext);
            var t_s = new Date().getTime();
            Cinteros.JR.account.name_onChange();
            var t_e = new Date().getTime();
            Mscrm.MetricsReporting.instance().addMetric('form_event_onchange_function_Cinteros.JR.account.name_onChange', t_e - t_s);
        } catch (e) {
            displayError('name', 'onchange', e.description);
        }
    }
]

As you can see the function name that was entered in the customizations is now wrapped to extract the context (which is not even used after extraction in this case) and some timing and metrics, and of course the try-catch-wrapper.
And the function reference passed to removeOnChange contains – not the name of the function in my javascript, but the contents, which equates to this:

function () { 
    // Do standard things with name attribute 
    Xrm.Utility.alertDialog("Normal function"); 
}

There is no hint at all to what the actual method to remove was, simply the code that would be executed.
So when the remove function calls Array.remove(list, item), there will of course be no match as the code block above is not found in the array and the customized event handler will still fire for every onChange event on the field.
The only way to actually remove a design-time event handler, I guess, would be to perform the same wrapping when you call the removeOnChange, something like this:

nameAttribute.removeOnChange(function name_onchange_handler(eventObj,eventArgs) { try { var eContext=Mscrm.FormUtility.constructExecutionObject(eventObj,0,null,null); eContext=Mscrm.FormUtility.constructExecutionObject(eventObj,0,null,eContext); var t_s = new Date().getTime(); Cinteros.JR.account.name_onChange(); var t_e = new Date().getTime(); Mscrm.MetricsReporting.instance().addMetric('form_event_onchange_function_Cinteros.JR.account.name_onChange', t_e - t_s); } catch(e) { displayError('name', 'onchange', e.description); } });

Unfortunately, I haven’t been able to come up with the correct formatting of this string to make it work. And it would probably not be very supported.
(I sincerely hope someone will give me a sarcastic comment on my grave misunderstanding, and a pointer to how this should be done, and I would have to post an official apology to the Dynamics team… please, please, correct and enlighten me! 🙂

To Be Continued… OnChange part 2: addOnChange with context awareness

MS CRM SDK 5.0.13: Xrm.Page.context.getClientUrl – at last!

The long long wait is over… Have you ever had a CRM installation that can be accessed using different URLs, e.g. one to be used inside a corporate network, and one to be used for external access?
Have you also written some javascript to make calls to the OData endpoint or to open a new entity form? Then you have realized that the context.getServerUrl method returns the URL that was assigned the server during the installation of CRM, and not the URL currently used to access CRM. Why is that a problem? Well, authenticating the user to one URL, and then having javascript making calls to the OData endpoint on another URL, will just give the user a “too bad, you are not authorized to do anything on this URL”. Now, at last, in Microsoft Dynamics CRM Software Development Kit version 5.0.13 the context.getClientUrl method is introduced, which returns the base URL currently used by the user to access the CRM application.
The getServerUrl method is still there, but deprecated and should not be used in the future. Documentation can be found here. Happy javascripting!

Automatically Set Regarding on New Activities

Summary

Missing functionality in the MS CRM 2011 OOB functionality:

  • Activities created from menu File – New Activity on entity forms do not get the Regarding field populated.
  • When creating new activities from the associated view on the entity form, the Regarding field is mapped properly.

FileNewActivityIn this post, I will demonstrate a javascript example of a generic way to populate the Regarding field on activities, where the OOB CRM functionality fails to do this.TaskWORegarding

Objective

Whenever possible, the activity form shall to try to find which record that should be set as regarding. While doing this, also provide an opportunity to specify which entities that shall be allowed as regarding for each type of activity entity.

Method

  1. As the activity form is not opened with any parameters indicating “where it came from”, I investigate window.parent.opener to find information of its origin.
  2. Metadata requests are used to find additional information of the source, to be able to map between ObjectTypeCode and LogicalName, as well as to dynamically find which attribute on the source that is the primary attribute (i.e. the “name” attribute”).
  3. I perform a REST request to find the name of the source record, instead of e.g. trying to walk through the source form’s DOM to find information about it.

Code samples

Function to verify and populate the Regarding field:

Cinteros.Xrm.Activity = {
      _verifyRegarding: function (regardingEntities) {
        try {
            // First check if we have a valid mapped regardingobject
            var regardingObjectId = Xrm.Page.getAttribute("regardingobjectid").getValue();
            if (regardingObjectId && regardingObjectId[0].entityType) {
                // We have a regarding object through mapping, verify it is from an allowed entity
                if (!regardingEntities || !regardingEntities.length) {
                    return true;
                }
                for (var i = 0; i < regardingEntities.length; i++) {
                    if (regardingObjectId[0].entityType === regardingEntities[i]) {
                        return true;
                    }
                }
                return false;
            }
            // No regarding object was set - now examine opener to see where we came from
            if (window && window.parent && window.parent.opener && window.parent.opener.location && window.parent.opener.location.href) {
                var href = window.parent.opener.location.href;
                // Extract parent etc from its href
                var parentEtc = Cinteros.Xrm.SDK.getParameter(href, "etc") || Cinteros.Xrm.SDK.getParameter(href, "oType");
                // Get metadata for parent entitytype
                var regardingEntityMeta;
                var entityMetadataCollection;
                if (!regardingEntities || !regardingEntities.length) {
                    // No allowed entities specified, load metadata for all entities
                    entityMetadataCollection = Cinteros.Xrm.SDK.RetrieveAllEntities();
                }
                else {
                    // Load metadata only for allowed entities
                    entityMetadataCollection = [];
                    for (var i = 0; i < regardingEntities.length; i++) {
                        entityMetadataCollection.push(Cinteros.Xrm.SDK.RetrieveEntity(regardingEntities[i]));
                    }
                }
                // Get the metadata for correct parent entity, based on etc/otc
                for (var i = 0; i < entityMetadataCollection.length; i++) {
                    if (entityMetadataCollection[i].ObjectTypeCode == parentEtc) {
                        regardingEntityMeta = entityMetadataCollection[i];
                        break;
                    }
                }
                if (regardingEntityMeta && regardingEntityMeta.ObjectTypeCode == parentEtc) {
                    // Extract parent id from its href
                    var parentId = Cinteros.Xrm.SDK.getParameter(href, "id") || Cinteros.Xrm.SDK.getParameter(href, "oId");
                    if (parentId) {
                        parentId = unescape(parentId);
                        var attributeMeta = Cinteros.Xrm.SDK.RetrieveAttribute(regardingEntityMeta.LogicalName, regardingEntityMeta.PrimaryNameAttribute);
                        // Retrieve the regarding entity, to be able to find its primary name
                        var regardingObject = Cinteros.Xrm.REST.Retrieve(regardingEntityMeta.SchemaName, parentId, "?$select=" + attributeMeta.SchemaName);
                        if (regardingObject) {
                            // Found regarding record, create lookup object
                            var regardingLkp = [{ "id": parentId, "entityType": regardingEntityMeta.LogicalName, "name": regardingObject[attributeMeta.SchemaName]}];
                            Xrm.Page.getAttribute("regardingobjectid").setValue(regardingLkp);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        catch (e) {
            window.alert("Error in verifyRegarding:nn" + e.description);
        }
    }
}

Note: The javascript-functions in namespace Cinteros.Xrm are part of our internally developed tools, but the names should be quite self-explanatory.
REST functionality can be replaced by similar functionality in the CrmRestKit, see http://crmrestkit.codeplex.com/, or by other custom made code.
MetaData functionality can be replaced by functionality in the MS CRM SDK, see Sample: Retrieve Entity Metadata Using JScript.
Feel free to contact me if you have any questions.

Function to register for the formLoad event on each activity entity that shall have this functionality:

Cinteros.Xrm.Activity = {
    formLoad: function () {
        try {
            // Only do this when creating new activities
            if (Xrm.Page.ui.getFormType() === 1) {
                // For this example - four entities are allowed to be set as regarding
                var allowedEntities = ["contact", "lead", "opportunity", "jr_my_custom_entity"];
                if (this._verifyRegarding(allowedEntities) === false) {
                    window.alert("Activity must be created from a valid regarding record.n(" + allowedEntities.toString() + ")");
                    Xrm.Page.ui.close();
                }
            }
        }
        catch (e) {
            window.alert("Error during formLoad:nn" + e.description);
        }
    }
}

It is possible to call the _verifyRegarding function without any parameter, thus allowing any entity as regarding object. This will however read all entity metadata from the database, which typically takes a few seconds. So specifying the allowed set of regarding entity types is recommended.
Exclude the if-clause when calling the _verifyRegarding function to ignore it’s return value. Then the function will simply populate the regarding field when possible, without any verification that the field must be populated, or that it must be populated by a specific entity type.
Note that this solution uses window references and url parameters to interpret the caller. This is probably not supported according to MS CRM SDK, but it is not unsupported either, as it does not alter the DOM or use undocumented javascript methods, and it includes quite good error handling.

Xrm.Utility methods in MS Dynamics CRM UR8

  • Have you ever used the unsupported javascript-function openObj to open a form in Microsoft Dynamics CRM 2011?
  • Have you ever cursed out loud over getting correct paths and parameters for URL Addressable Forms?
  • Have you ever implemented your own functionality to open a Microsoft Dynamics CRM 2011 webresource in a new window?

Stop that. Now. At last, in UR8 Microsoft has included supported javascript-functions for those actions, providing a better user experience as well as nicer code than using the functionality of URL Addressable Forms and Views. No new SDK version has been released yet, so you cannot read about it or find any examples there, it was just recently announced in The Microsoft Dynamics CRM Blog.

Basic description

There is a javascript library called Xrm.Utility which is available “everywhere” as long as you have a CRM context.

Xrm.Utility.openEntityForm(name, id, parameters)
Xrm.Utility.openWebResource(webResourceName, webResourceData, width, height)

Both functions return the window object that is created which allows you to e.g. move and resize the window.
The parameters parameter can be used to set default values when creating a new record and to specify which form to display.
One of the best things though – is that the openEntityForm function takes the LogicalName of the entity instead of forcing us to make a metadata request to get the ObjectTypeCode…!

Usage examples

openEntityForm
  • Open a record from a custom html or Silverlight displaying CRM data
  • Open a new record form from a custom ribbon button populating with default data
  • Create a new record in javascript and then opening that new record
openWebResource
  • Open a webresource from a custom ribbon button (e.g. html page with Bing map integration)
  • Prompt user for confirmation using your own nicely styled Confirm dialog (instead of ugly styled window.confirm(…))

Thank’s Markus for enlightening me about this news!

Execute Server-Side Code from Javascript

Background:

General business rules shall be implemented in server-side code to ensure its execution regardless of the origin of data changes; CRM UI, workflow, integration or any other application consuming the CRM web services. But on some occasions it would be handy to be able to execute this code from JavaScript to improve the user’s experience of the application.

Scenario:

When creating or updating an Account, there is a plugin registered Pre Validation Create/Update to verify that the given VAT number is in a correct format. If not, the plugin throws an exception instructing the user to enter a correct VAT number.

VATincorrect

Another plugin is registered Pre Operation Create/Update to look up city/state/county from given zip-code to ensure correct data for the account. This function consumes an external service from a third party accessible as a web service.

Account Cinteros zip

Challenge

To improve user experience, the customer requires immediate verification of the VAT no and lookup of geographic information for the zip-code.

Solution 1 (bad):

Required functionality can of course be implemented entirely in JavaScript. Rules for VAT numbers and calls to external web services can be coded in client side code. Calling external services may be a problem, depending on firewall configuration, local browser settings etc. but usually it is possible to find a way around these problems. Composing and parsing SOAP-messages in javascript is neither intuitive nor fun, but of course it can be done. This solution however would duplicate the same code in two entirely different environments and languages. Duplicated code is, and I think everyone agrees to this, NOT something we want. Right?! Especially not from a maintenance perspective.

Solution 2 (good:)

Create a custom entity jr_serverfunction with one text field jr_parameter and one text field jr_result.

ServerFunction blank

Server-side

  • Extract logic from the two plugins mentioned to methods in an isolated C# class
  • Rewrite the plugins to consume this class (to preserve existing functionality invoked on create/update)
  • Create a plugin triggering Post Operation RetrieveMultiple on jr_serverfunction. This plugin shall investigate the incoming query to extract it’s condition for field jr_parameter and use this condition to execute desired server-side code
  • When the result of the function is determined, an instance of entity jr_serverfunction is created (in code, not saved to the database), resulting data/information placed in field jr_result, and the entity placed in the EntityCollection that is to be returned in the query response

ServerFunction registration Note that the custom entity will actually never hold any records in the CRM database. This is why I also trigger the Create message and immediately throw an error. ServerFunction assembly Plugin code:

public class ServerSideExecution : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        if (context.MessageName == "Create")
            throw new InvalidPluginExecutionException("Server Function entity cannot be instantiated");

        if (context.MessageName == "RetrieveMultiple" &&
            context.Stage == 40 &&      // Post Operation
            context.PrimaryEntityName == "jr_serverfunction" &&
            context.InputParameters.Contains("Query") &&
            context.InputParameters["Query"] is QueryExpression)
        {
            ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            tracer.Trace("Initialize service etc");
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
            QueryExpression query = (QueryExpression)context.InputParameters["Query"];
            tracer.Trace("Extract condition from query");
            ConditionExpression parameterCondition = MyFunctions.GetFilterConditionByAttribute(query.Criteria, "jr_parameter");
            if (parameterCondition != null && parameterCondition.Values.Count == 1)
            {
                string parameter = parameterCondition.Values[0].ToString().Trim('%');
                tracer.Trace("Parameter is: {0}", parameter);
                string command = parameter.Split(';')[0];
                string result = null;
                switch (command)
                {
                    case "VerifyVAT":
                        tracer.Trace("Check if VAT number is correct");
                        string vat = parameter.Split(';')[1];
                        if (MyFunctions.VerifyVAT(vat))
                            result = "ok";
                        else
                            result = "not ok";
                        break;
                    case "LookupZIP":
                        tracer.Trace("Lookup city etc from ZIP code");
                        string zip = parameter.Split(';')[1];
                        // Returns a semi-colon separated string with city;state;country
                        result = MyFunctions.GetZipInfo(zip);
                        break;
                    // **************************************
                    // ** Add more functions here as needed
                    // **************************************
                }
                if (result != null)
                {
                    tracer.Trace("Create resulting serverfunction entity with result: {0}", result);
                    Entity serverfunction = new Entity("jr_serverfunction");
                    Guid id = new Guid();
                    serverfunction.Id = id;
                    serverfunction.Attributes.Add("jr_serverfunctionid", id);
                    serverfunction.Attributes.Add("jr_parameter", parameter);
                    serverfunction.Attributes.Add("jr_result", result);
                    tracer.Trace("Replace contents of resulting entitycollection");
                    EntityCollection resultCollection = (EntityCollection)context.OutputParameters["BusinessEntityCollection"];
                    resultCollection.Entities.Clear();
                    resultCollection.Entities.Add(serverfunction);
                    context.OutputParameters["BusinessEntityCollection"] = resultCollection;
                }
            }
        }
    }
}

Note: The function MyFunctions.GetFilterConditionByAttribute is part of internally developed tools. Please contact me if you are interested in how we find specific conditions in a query.
The plugin can easily be tested by making an Advanced Find query on the Server Function entity in the CRM.
TestVAT TestZIP

Client-side

In the client-side JavaScript a method is registered for the onChange event of the VAT no field. The function will use the REST endpoint to query CRM for records of jr_serverfunction where jr_parameter equals “VerifyVAT;1234567890” (where the numbers should be the number entered on the form).
The result will contain one record, and the jr_result field will contain “ok” or “not ok”, which the JavaScript can use to immediately instruct the user to correct the number.

Cinteros.Xrm.AccountServerFunction = {
    jr_vat_onChange: function () {
        try {
            var vatNo = Xrm.Page.getAttribute("jr_vat").getValue();
            if (vatNo != null) {
                var parameter = "VerifyVAT;" + vatNo;
                var result = this.ExecuteServerFunction(parameter);
                if (result === "not ok") {
                    window.alert("VAT number is not in a correct format");
                }
            }
        }
        catch (e) {
            alert("Error in jr_vat_onChange:nn" + e.description);
        }
    },

    ExecuteServerFunction: function (parameter) {
        var result = null;
        var serverFunctionResult = Cinteros.Xrm.REST.RetrieveMultiple("jr_serverfunction",
                "?$select=jr_result" +
                "&$filter=jr_parameter eq '" + parameter + "'");

        if (serverFunctionResult && serverFunctionResult.length === 1) {
            result = serverFunctionResult[0].jr_result;
        }
        return result;
    }
}

Note: The javascript-function Cinteros.Xrm.REST.RetrieveMultiple is part of our internally developed tools, it may well be replaced by similar functionality in the CrmRestKit (http://crmrestkit.codeplex.com/) or by other custom made code.
Registering this function as the onchange event of the VAT number field immediately executes the server-side functionality for validating a VAT number when the user changes the field in the CRM client.

VATeventhandler VATincorrectJS

Corresponding onChange event for the zip-code field can be implemented to get geographic information and automatically populate city/state etc. on the form.

address1_postalcode_onChange: function () {
    try {
        var zipCode = Xrm.Page.getAttribute("address1_postalcode").getValue();
        if (zipCode != null) {
            var parameter = "LookupZIP;" + zipCode;
            var result = this.ExecuteServerFunction(parameter);
            if (result) {
                var city = result.split(';')[0];
                var state = result.split(';')[1];
                var country = result.split(';')[2];
                Xrm.Page.getAttribute("address1_city").setValue(city);
                Xrm.Page.getAttribute("address1_stateorprovince").setValue(state);
                Xrm.Page.getAttribute("address1_country").setValue(country);
            } 
        }
    }
    catch (e) {
        alert("Error in address1_postalcode_onChange:nn" + e.description);
    }
}