One of the nice things about working with lookup fields on entity forms is the ability to filter the results programmatically via a form level JScript function. The steps for doing this, thankfully, are rather straightforward:

  1. Prepare a FetchXML filter snippet that applies the type of filtering you want to perform. This can either be written manually, or you can build your filter within Advanced Find, download the FetchXML and then copy + paste the <filter>…</filter> node.
  2. Access the control using the Xrm.Page.getControl object, and then use the addCustomFilter method to apply the filter
  3. Finally, setup your function to fire on the OnLoad event, using the addPreSearch method to actually apply the filter to the lookup control.

If you are still scratching your head at the above, then fortunately there is an MSDN article on the subject which provides further guidance, including a handy example snippet that you can modify and apply straight to your CRM instance. What I like most about this method is that its application is simple, but its potential is quite huge. Utilising conditional logic within your Jscript function means that you could potentially filter results based on values on the form, via a web service request to another CRM record or based on the value in an external CRM/ERP system. Used correctly and prudently, it can help to make form level data inputting much more easier and context sensitive.

CRM has a number of special field types that are reserved for certain system entities. One example is the Customer Data Type field. This is, in essence, a special kind of lookup control that spans two entities – Account & Contact. System customisers are able to create additional fields with this data type, but are unable to create a customer lookup control that spans across 2 entities of choice. This is a real shame, as I think this feature would be really welcome and be widely applicable to a number of different business scenarios.

I was recently working with this particular field on the Contact entity in order to meet a specific requirement as part of a solution – for only certain Account records to appear and for no Contact records to be made available to select. One potential work-around would be to just create a new 1:N relationship between Account:Contact, but this seems rather unnecessary when there is already a relationship in place that could be modified slightly in order to suit requirements. I was therefore interested in finding out whether the addCustomFilter/addPresearch methods could be utilised in this case. After a small, yet sustained, period of severe head-banging, I was able to get this working; although the solution could be argued as being less than ideal.

For the above requirement, lets assume we have a custom field on our Account entity – Company Type – which we are using to indicate what type of UK company an Account is:

4

Once created, we then populate our CRM sample Account records with the value of ‘Limited Company (Ltd.) and run a quick Advanced Find to confirm they return OK:

7

8

Now, for this example, we want to apply a very basic filter on the Customer field on our Contact entity to only show Account records that equal ‘Limited Company (Ltd.)’. Here is our “first attempt” JScript function(s) to achieve this:

function onLoad() {

    Xrm.Page.getControl("parentcustomerid").addPreSearch(modifyCustomerLookupField);

}


function modifyCustomerLookupField() {

	fetchXML = "<filter type='and'><condition attribute='jg_companytype' operator='eq' value='140250000' /></filter>";
	Xrm.Page.getControl("parentcustomerid").addCustomFilter(fetchXML);


}

After creating a JScript Library, adding it to a form, calling the onLoad() function as part of the OnLoad event and, finally (whew!), pressing the magnifying class on the control, we immediately get an error message:

1

Here’s the error message:

5

As a next step, to try and resolve this, I remembered within the FetchXml <filter>…</filter> node, you can specify the name of the entity that you want to filter on. This is typically required when you are using <link-entity> in order to join together multiple records. So I modified my JScript function to include the entity name within the fetchXML filter:

function onLoad() {

    Xrm.Page.getControl("parentcustomerid").addPreSearch(modifyCustomerLookupField);

}


function modifyCustomerLookupField() {

	fetchXML = "<filter type='and'><condition entityname='account' attribute='jg_companytype' operator='eq' value='140250000' /></filter>";
	Xrm.Page.getControl("parentcustomerid").addCustomFilter(fetchXML);


}

With fingers crossed, I then tried again…but still got an error message, but a slightly different one. Some progress at least!

2

3

Once my head had returned from the desk in front of me, I looked back at the original error message, in particular the fact that the Contact entity does not contain the new field we have on our Account. This is to be expected, but is there some way we can “fool” CRM by also having a field with the same name on Contact, but which is not used for anything? Going back into my solution, I created a field with the exact same logical name on the Contact entity, making it clear that this field should not be used. The data type, description etc. does not matter, so long as the logical name is the same as our field above:

6

 

Going back to our form and trying again, we see that this looks to have done the trick – our three records are now returning successfully when we use the control! 🙂

9

Another good thing about this is that the custom filter will also apply when the user clicks on ‘Look Up More Records’; although the Contact entity can still be selected, no records will be returned for obvious reasons.

I was glad this was ultimately possible to get working; however, to play devil’s advocate for a few moments, it is worth noting the following if you choose to set this up within your own environment:

  • Simply creating a new 1:N relationship between Account:Contact would be a more straightforward and less technical approach of achieving the above; you should review your requirements carefully and consider whether this approach would satisfy your objectives.
  • By adding form level JScript to this entity, you may start to impact on your form load times, particularly if you have lots of other functions running on the form or if you implement additional logic into your function.
  • It is arguably not best practice to have a field within CRM that is being used in a “hacky” manner, as outlined above. If you are happy to have such a field within your CRM environment, then you will need to ensure that you take a number of steps to clearly label this field and its purpose within the CRM. The last thing you want is for someone to delete it by accident.

If anyone else has found a better or alternative way of achieving the above, please let me know in the comments below!

I was working within CRM recently, attempting to configure some form level logic in order to display/hide fields, based on certain conditions on the form itself. I went into it rather gung-ho and immediately started writing the following JScript function:

function hideFormFields() 

{

    var myField = Xrm.Page.getAttribute("jg_myfield").getValue();

    if (myField = "Value1") {

        Xrm.Page.getControl("jg_myfieldtohide1").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide2").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide3").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide4").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide5").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide6").setVisible(true);

    }

    else if (myField = "Value2") {

        Xrm.Page.getControl("jg_myfieldtohide1").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide2").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide3").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide4").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide5").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide6").setVisible(false);

    }
}

I then suddenly thought “Hang on – can’t this be done via a Business Rule instead?”. For CRM Administrators who do not have any previous development skills, Business Rules were a godsend when Dynamics CRM 2013 was first released, having been continually improved since. They essentially enable you to implement conditional logic and actions on your entity forms, without the need of writing a single line of code. Business Rules are, in fact, a form of JScript, utilising many of the capabilities available as part of the XRM framework. As an excellent case in point, we can very easily replicate the above code into a Business Rule, like so:

BusinessRule

There is an important lesson here, that anyone who works extensively within CRM needs to always remember; if it can be done out of the box within CRM, then why would you go to the trouble and effort to write a JScript function? Here are some reasons why CRM Developers should always think twice before typing away on that new form-level JScript function:

Business Rules actually do a lot more than you’d expect

This is something I am guilty of forgetting, and I’m having to train myself to consider this more carefully in future. In the above example, I made the immediate assumption that showing/hiding form fields on a conditional basis was not possible via a Business Rule – how very wrong I was! This seems to underline a general theme with how CRM customisers/developers approach Business Rules, assuming a glass half-empty approach. As of 2016 Update 1, as well as being able to modify a fields visibility, Business Rules can also support the following scenarios:

  • Show Error Message
  • Set Field Value – Fields can be set to match the value of another field, a specific value (including lookups), the result of a formula (Date/Number fields only) or be cleared of data.
  • Set Business Requirement.
  • Set Default Value – Fields can be set to match the value of another fields, a specific value (including lookups) or as the result of a formula (Date/Number fields only).
  • Lock or unlock field

What emerges, when combined with the conditional logic builder, is a means of utilising some of the most frequently used methods available to you via the SDK. And we can also hope and anticipate that as part of future releases of CRM, this list will be expanded on further.

Business Rules are supported, whereas your JScript may not be

To summarise another way, although you can do lots of things via Jscript within CRM, that doesn’t mean that you should. One thing I have observed with those who work with CRM, but have had more of a developer background, is that there is tendency to utilise methods/code which is not officially supported by Microsoft within CRM. Looking around the CRM community, and you often see that an unsupported solution is provided to a specific requirement, but often with no warning label attached to stress what it is doing. A good example of something which is unsupported is manipulating the Document Model Object (DOM) of the current page. Just because it works now doesn’t mean it will in the future, potentially causing major problems for your CRM deployment. If you are ever in doubt, be sure to review the supported extensions article on MSDN for CRM, and always think twice before you start using that nice bit of code you find on a Google search.

Your JScript may cause problems for end users

So your JScript is supported – great! But that doesn’t necessarily mean it’s going to work well from an end users perspective. If your JScript code, for example, does not provide a sufficient level of error handling, your end users could end up receiving error messages frequently. Or perhaps consider a scenario where your code is handling your errors well and outputting them correctly for potential debugging; this can lead to more lines of code that are unnecessary, and cause an impact when running the application on certain machines/browsers. With Business Rules, you don’t have to worry about addressing that careful balancing act between form loading times versus JScript library sizes. And, you can be assured that the CRM application as a whole will be able to handle your custom logic without affecting the performance of your deployment.

Jscript should have a time, place and bespoke requirement

What I mean by this is that JScript should only really begin to factor in when you are dealing with very specific, business requirements that the application “as-is” has no means of satisfying. An example of this is if you need to provide specific data validation to a field (such as a telephone number or bank sort code number). The only way this is ever going to be possible is via some kind of Regular Expression (RegEx) validation, which can only be performed via JScript. As one the key takeaways from this blog post, I would stress that you should always first attempt to build a Business Rule that is designed to meet the requirement that you are looking for, utilising other out of the box elements where appropriate (fields, workflows etc.). When it starts to become pretty obvious that a Business Rule is not going to cut it, then you can “give yourself permission” to start writing a JScript function 🙂

A “No Code First” approach should always prevail

I was recently introduced to this simple concept, but it is one that got me thinking and re-evaluating many of my previous solutions that I have built within CRM and elsewhere. When attempting to provide a potential solution to a requirement within CRM, you should try and put forward two solutions (where possible): a solution that can be achieved using out of the box functionality and one that requires bespoke coding to resolve. It may be that the first solution requires considerable time to build within CRM, but doing it this way could mean your solution is a lot more readable and understandable for those going into the system in future. By comparison, your 3-6 lines of code could prove to be virtually indecipherable.

So, in conclusion, can you guess what your new “Rule” should be moving forward?

Going back to my earlier example of your CRM Developer, AKA Former Application Developer, person, you can anticipate that they will have a very good knowledge of what CRM is capable from an SDK point of view. What may be lacking is a good understanding and knowledge of application as a whole, and specific features (such as SLA’s, Business Process Flows etc.). I would invite these people, and in fact anyone who works extensively with CRM, to focus their learning efforts towards the functional side of the application, so that they can ensure they have a good grasp of what CRM is capable of doing with, potentially, just a few mouse clicks. And, finally, to always think twice and consider alternative solutions before deciding on the best option – for everyone involved.

I was having a chat with a colleague recently about the new Interactive Service Hub (ISH) in CRM, in particular the new entity forms that are used as part of this. One of the questions that came up was “From a form scripting point of view, do ISH forms let you utilise all of the same references, properties and methods available as part of a Main form?”. As is generally the case in these situations, we can turn to our good friends TechNet and MSDN for answers. Specifically, we are able to find out the following on MSDN:

All the form scripting events and methods supported by the CRM mobile clients (phone and tablet) are supported in the interactive service hub.

If your organisation is fortunate enough to be using CRM 2016 Update 1 or CRM 2016 Service Pack 1, then you can also utilise the following methods/events as well:

Source: https://msdn.microsoft.com/en-us/library/mt671135.aspx#Anchor_1

So what does this mean in practical terms and how should this factor into your decision to utilise Interactive Forms over standard CRM forms? Here are a few things to consider, as well as my own thoughts on the best way to proceed:

If you are on CRM 2016, then get yourself Update 1/Service Pack 1 ASAP

There are a number of important new methods that can be used for interactive forms as part of this update. For example, you get much better options when it comes to working with IFRAME controls, interacting with the currently loaded record you are working with (via getID), loading a new record form (via openEntityForm or openQuickCreate) and setting focus to a particular field on a form (via setFocus). This goes above and beyond what is currently supported via the CRM tablet apps, and it is good to see that this CRM update has added these in. Having access to these methods may help to decide whether you can safely migrate or start using ISH forms within your organisation. And, as we have seen previously, the update process to SP1 for CRM 2016 is relatively straightforward, so why wouldn’t you look at upgrading?

Be sure you familiarise yourself with Interactive Form debugging

Anyone who works with CRM form scripting will be familiar with the trials and tribulations of browser debugging your scripts via Developer Tools on your browser of choice: open up your script library, set your breakpoints and then perform the actions needed to trigger your script. Try this with the new Interactive Forms, and you will notice that your custom library is not loaded onto the form. What the fudge?!?

Before panicking too much, the good news is that scripts can still be debugged, but you just have to go down a slightly different route. The CRM Team have written an excellent blog post that covers not just debugging for interactive forms, but for all forms as well. The first two options suggested seem to be the most straight-forward way of debugging interactive forms, but you can’t help but laugh at the fact that one of the suggested options is to use functionality within Google Chrome! 🙂 Joking aside, using Dynamic JScript in the manner outlined looks to be an effective way of setting breakpoints in a familiar manner. I may have to look at trying this at some point in the future.

You cannot programmatically switch to a different entity form in the Interactive Service Hub

It is sometimes useful to change the currently loaded form that a user is presented with depending on certain conditions. For example, if a user enters certain data within a Lead form to indicate the record should be treated as high priority, you may want a new form to be opened that contains additional fields, subgrids etc. that need to be completed in order to progress the record accordingly. Within the Xrm.Page.Ui reference, we have two methods that help us achieve this objective: formSelector.getCurrentItem, which returns the GUID for the currently loaded form, and formSelector.items, which returns a list of GUID’s for all forms that the current user has access to. The bad news is that, because these two methods are not supported in the mobile app, you will also be unable to use them within the ISH. This is likely due to the fact that, similar to Mobile Forms, only one form is presented to user when using the ISH, which is dictated by the form order and the users security permissions.

ISH forms do not contain a Ribbon

This may be one of the major reasons that prevent against an en masse adoption of ISH forms in the near future. One of the benefits of using the default CRM forms is the ability to modify the the CRM ribbon in order to add, remove or modify button behaviours across the application. This is great if you decide that you don’t want your users to have access to the Delete button, need to modify the order of the buttons to match the ones that are used the most or you need to setup a custom button that performs a web server call to an external system. Again, similar to the mobile application, there is no ribbon anywhere on the ISH, which means you may be missing out on key functionality going down this route.

ISH can only currently be used with a limited list of entities

If you are hoping to get your CRM setup to use ISH for your Sales related entities, then don’t get too carried away at this stage. You are currently limited to using ISH with a specific list of CRM entities. The full list, courtesy of our good friends again, is as follows:

  • Account
  • Contact
  • Case
  • All Activity Entities (System/Custom)
  • Social Profile
  • Queue Item
  • Knowledge Article
  • Custom Entities

Expect this to change in future, as one of the things that I have previously highlighted as part of Update 1/Service Pack 1 was the ability to add Feedback onto any entity within CRM, including custom ones. It would make sense that the Sales side of CRM gets some love and attention to include Leads, Opportunities etc. as part of ISH (so we may not even call it this if that happens!).

Conclusions or Wot I Think

It is clear that, whilst some of the headline benefits of using ISH are clear – visual experience, ability to drill down to individual records and efficient record filtering – , there are some very crucial and important technical limitations with the feature that need to be factored in before you decide to just completely migrate across to ISH. I would say that if your organisation has not been extensively customised to utilise form level scripting and other types of bespoke development work, then you can perhaps get away with making the jump. By contrary, you should be holding off and evaluating your existing customisations first to see if a) they are supported/unsupported by ISH or b) if there is some way to drop certain form scripting, ribbon customisations etc. in favour of using something default within CRM (for example, a Business Rule instead of a Jscript function). It could be that you can ditch a whole load of code that is not required as part of this exercise and instead utilise base functionality within CRM, something which is always preferable.

One thing I have been wondering about is the eventual aim with the ISH: is it intended that this will eventually replace the existing CRM user experience or will it continue to just be an alternative way of using CRM? It will be interesting to see how the feature is developed over the next couple of releases of CRM; one of the key indicators of this replacing the “old style” CRM forms is if we start to see all form scripting options made available in ISH and the introduction of the Ribbon.

In the meantime, make sure you do check out ISH at some stage, as the potential of setting up a visually attractive reporting and day-to-day application tool is huge. Just don’t let your Sales team see it yet, as you will end up disappointing them!

The Scenario: You are running CRM Online in conjunction with some legacy database/application systems. These systems are setup with a SQL Server Reporting Services instance that is looking to either an SQL Server, OLE DB etc. database.

The Problem: You need to make data from your legacy systems visible within your CRM. The information needs to be displayed on the Entity Form and show specific information from the legacy database that relates to the CRM record.

Admittedly, the above is perhaps somewhat unlikely situation to find yourself in, but one which I recently had to try and address. I suppose the most straightforward resolution to the above is to just say “Get rid of the legacy system!”. Unfortunately, the suggestion didn’t go down to well when I voiced it myself…

So at this point the next best answer looked to be try and utilise what we have within the existing infrastructure: an all singing, all-dancing SSRS and SQL Server database instance.

What if we were to try uploading an .rdl file that includes a FetchXML and our SQL/OLE DB database data source into CRM? Whenever you try to perform this, you will get this error message:

ReportUploadError_NoFetchXML

 

Rats! So there is no way in which we can include a non-fetch XML Data Source to our separate SSRS report instance. So is there anything else within CRM that can be utilised to help in this situation? Let’s first take a quick look at the following nifty little feature within CRM, courtesy of our good friend MSDN:

You can use an IFRAME to display the contents from another website in a form, for example, in an ASP.NET page. Displaying an entity form within an IFrame embedded in another entity form is not supported.

Use the getValue method on the attributes that contain the data that you want to pass to the other website, and compose a string of the query string arguments the other page will be able to use. Then use a Field OnChange event, IFRAME OnReadyStateComplete event, or Tab TabStateChange event and the setSrc method to append your parameters to the src property of the IFRAME or web resource.

You may want to change the target of the IFRAME based on such considerations as the data in the form or whether the user is working offline. You can set the target of the IFRAME dynamically.

Source: https://msdn.microsoft.com/en-gb/library/gg328034.aspx

Having worked extensively with SSRS in the past, I am also aware that you can use an SSRS URL string in order to specify properties about how the report is rendered, its size and – most crucially – what the value of required parameters should be. The friend that keeps on giving has a great article that goes through everything that you can do with an SSRS report URL and also how to use Parameters as part of your URL. So in theory therefore, we can place an IFRAME on our form and then use JScript to access form-level field values and modify the IFRAME URL accordingly.

Here are the steps involved:

  1. Go into Form Editor and add a new IFRAME to the form, specifying the following settings:

Name: The Logical name of the control, this will be required as part of the JScript code used later, so make a note of it.

URL: As this is a mandatory field, you can specify any value here as it will change when the form is loaded by the user. This is not practical as we don’t want this to be displayed if, for example, the field that we are passing to the URL has no value in it. Our JScript code will sort this out in a few moments

Label: This can be anything, and defaults to whatever is entered into the Name field

Restrict cross-frame scripting, where supported: Untick this option

Ensure that ‘Visible by default’ is ticked

Your settings should look something like this:

IFRAMESettings

  1. Create or modify an existing JScript Library for the form, adding in the following function (after modifying the values accordingly):
function onLoad_LoadSSRSReport() {

    //First get the page type (Create, Update etc.)

    var pageType = Xrm.Page.ui.getFormType();
    
    //Then, only proceed if the Form Type DOES NOT equal create, can be changed depending on requirements. Full list of form types can be found here:
    
    //https://msdn.microsoft.com/en-us/library/gg327828.aspx#BKMK_getFormType

    if (pageType != "1") {

        //Get the value that you want to parameterise, in this case we are on the Account entity and need the Account Name

        var accountName = Xrm.Page.getAttribute("name").getValue();

        //In order to "accept" the parameter into the URL, spaces need to be replaced with "+" icons

        accountName = accountName.replace(/ /g, "+");

        //Now, get the the name of the IFRAME we want to update

        var iFrame = Xrm.Page.ui.controls.get("IFRAME_myssrsreport");

        //Then, specify the Report Server URL and Report Name.

        var reportURL = "https://myssrsserver/ReportServer?/My+Reports/My+Parameterised+Report&MyParameter=";

        //Now combine the report url and parameter together into a full URL string

        var paramaterizedReportURL = reportURL + accountName;

        //Finally, if there is no value in the Account Name field, hide the IFRAME; otherwise, update the URL of the IFRAME accordingly.

        if (accountName == null) {
            iFrame.setVisible(false);
        }
        else {

            iFrame.setSrc(paramaterizedReportURL);
        }
    }
}
  1. Add the function to the OnLoad event handler on the form. Now, when the form loads, it will update the IFRAME with the new URL with our required parameter.

And there we go, we now have our separate SSRS instance report working within CRM! A few things to point out though:

  • If the report parameter supplied does not load any matching records, then SSRS will display a standard message to this effect. You would need to modify the report settings in order to display a custom message here, if desired.
  • It is recommended that you have https:// binding setup on your report instance and supply this to as part of the setSrc method. http:// binding works, but you may need to change settings on your Web Browser in order to support mixed mode content. Full instructions on how to set this up can be found here.
  • This may be stating the obvious here, but if your SSRS instance is not internet-facing, then you will get an error message in your IFRAME if you are not working from the same network as your SSRS instance. Fortunately, SSRS can be configued for an Internet deployment.
  • The steps outlined in 1) can also be used to specify a non-parameterised SSRS report within an IFRAME dashboard too. I would recommend using the following SSRS system parameters as part of the URL though:
    • rs:ClearSession=true
    • rc:Toolbar=false

e.g.

https://myssrsserver/ReportServer/Pages/ReportViewer.aspx?%2fMy+Reports%2fMy+Non+Parameterised+Report&rs:ClearSession=true&rc:Toolbar=false

One of the most challenging things about any system migration is ensuring that information from other business systems can be made available, and it is good to know that CRM has supported approaches that can help to bridge the gap.

One of our company directors has a big thing for Americanisms and American spellings over the “proper” English spellings/pronunciations. So it came as no surprise that when we first showed him CRM, he immediately pointed out the default names on the Address field composite box:

CompositeAddressControl

Specifically, he didn’t like “State/Province” or “Zip/Postal Code” (for those of you who are not aware, “State/Province is the equivalent to a County over here and we refer to “Zip/Postal Code” generally as Postcode).

Being good and sympathetic fellow Englanders, our team went away to investigate. Changing the display name of each individual address field didn’t work, as you may have expected. It turns out that that the composite address fields can instead be accessed and changed using the Xrm.Page.getControl JScript method to return each individual field and then set the label accordingly. But how do we find out the name of each control to access? Microsoft have a very informative article on MSDN that goes through Composite Controls and how they operate:

From the article:

You can access the individual constituent controls displayed in the flyout by name. These controls use the following naming convention: <composite control name>_compositionLinkControl_<constituent attribute name>. To access just the address_line1 control in the address1_composite control you would use: Xrm.Page.getControl(“address1_composite_compositionLinkControl_address1_line1”).

Source: https://msdn.microsoft.com/en-gb/library/dn481581.aspx

All we need therefore is the attribute logical name for each of the constituent fields on the control and to then add this to the getControl method!

So after a quick 5-10 minutes of coding, we now how the following nice little Jscript function that fires OnLoad for all entity forms that use the Composite Address control for Address 1 and Address 2 fields:

function changeAddressLabels() {

    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_line1").setLabel("Address 1");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_line2").setLabel("Address 2");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_line3").setLabel("Address 3");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_city").setLabel("Town");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_stateorprovince").setLabel("County");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_postalcode").setLabel("Postal Code");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_country").setLabel("Country");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line1").setLabel("Address 1");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line2").setLabel("Address 2");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line3").setLabel("Address 3");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_city").setLabel("Town");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_stateorprovince").setLabel("County");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_postalcode").setLabel("Postal Code");
    Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_country").setLabel("Country");
}

A victory for our team and for England – cup of tea, anyone?

Does anyone else have any experience doing interesting things with Composite Controls? Please leave a comment below if you have.