CRM 2013: JavaScript – Update Entity Image using Rest endpoint without jQuery

CRM 2013 introduced a new type of entity attribute called an “Entity Image”. Once an entity is configured to show an image, each entity record can have at most one image associated with the record, to be displayed on the top left corner next to the title of the record.

If we wish to change the image dynamically using JavaScript, here’s how…

Entity Image in CRM 2013

CRM 2013 introduced a new type of entity attribute called an “Entity Image”. Certain system entities such as Account and Contact have this attribute already b y default. You can also create this Entity Image attribute for a custom entity as well. The schema name of this Entity Image attribute is always “EntityImage”, and each entity that is configured to display this image can only have 1 attribute of this type.

You can find more information about entity images in the CRM 2013 SDK (version 6.0.2 at the time of writing).

There are several key things to remember:

  • if you want to update the image by code, you must set the value of the “EntityImage” attribute to a “byte[]” that contains the contain of the image file.
  • All images are displayed in a 144×144 pixel square.
  • The entity image can be displayed via an absolute URL: {0}/image/download.aspx?entity={1}&attribute={2}&id={3}&timestamp={4}
    • {0}: the organization URL (e.g. “https://myorg.crm.dynamics.com“)
    • {1}: the entity logical name (e.g. “contact”)
    • {2}: the attribute logical name (“entityimage”)
    • {3}: the EntityImageId value (the GUID of the Entity Image)
    • {4}: the EntityImage_Timestamp value. This value represents when the image was last updated (e.g. “635120312218444444”)

Once an entity form is marked to display an Entity Image, all you have to do is click on the image box on the record and it will  show the upload dialog:

ODataEntityImage-01

All you have to do is upload the desired image from your local machine and click “OK”. This will upload the image in byte[] to the “EntityImage” column of the entity table in the CRM 2013 organization database.

Retrieve and  Set an Entity Images in CRM 2013 in Code

Just like all the other attributes of an entity in the CRM database, you can retrieve and set an entity image by code via the CRM 2013 API. In the CRM 2013 SDK (version 6.0.2 at the time of writing), there is a section on how to do this in C# (look for the SDK section: “Sample: Set and retrieve entity images”). The sample code is in

SampleCode\CS\GeneralProgramming\LateBound\EntityImages.cs

There are also 2 nice blog posts on with plenty of step-by-step screenshots, on how to set the entity image in C# if you have the image on your local disk:

However, what if the requirement is a bit more … dynamic? What if the image set in the “EntityImage” attribute of an entity record should depend on some dynamic values set by a user? Furthermore, what if I wish to use an image stored as a web resource in CRM rather than uploading from a user’s local disk? In this case, you can still write the logic to be trigger by a .Net plugin, but you can also do the same on the client side via JavaScript and the OData endpoint.

For more information on how to use Ajax with the CRM OData endpoint, see a previous post here.

Example Requirement

Suppose we have the following requirements:

On the contact record where the EntityImage attribute is displayed in CRM by default, there is a  numeric  field called “Credit Limit” (schema name “creditlimit”). If a user opens a contact record and sets the contact credit limit in one of the following ranges, updates the contact record to display the corresponding image:

  • If contact credit limit is in the range: £0 to £5000, set this image to 1 pile of coins:
    ODataEntityImage-02
  • If contact credit limit is in the range: £5001 to £10000, set this image to 2 piles of coins:
    ODataEntityImage-03
  • If contact credit limit is in the range: £10001+, set this image to 3 piles of coins:
    ODataEntityImage-04

Note that as we can only store one image in the “EntityImage” attribute of an entity record at any given time, the above requirements means we have to overwrite an existing image with possibly a new image depending on the value set in the contact credit limit for the record. Also, we need to ensure that the 3 images are uploaded to CRM as picture web resources.

To meet the above requirements I shall use Ajax to work with the XmlHttpRequest object in JavaScript.

First we upload the 3 images as image web resources in CRM to ensure we can retrieve any one of the web resources via the OData endpoint. For example, once we uploaded image “OnePileCoins.jpg” as web resource “ts_onecoinpile.jpg” in CRM, we can retrieve this image as byte[] via the following kind of OData url (again see an earlier post if you do not understand Odata endpoint):

http://<crm address>/XRMServices/2011/OrganizationData.svc/WebResourceSet?$filter=Name eq ‘ts_onecoinpile.jpg’&$select=Name,Content

The “OnChange” event of the contact’s “Credit Limit” field triggers a JavaScript method, which does the following:

  1. Check if the “Contact Credit Limit” field is in one of the ranges set out in the requirements.
  2. If “Contact Credit Limit” is between £0 to £5000, retrieve image web resource “ts_onecoinpile.jpg” in byte[] and set the contact record’s “EntityImage” attribute to this image by updating this attribute.
  3. If “Contact Credit Limit” is between £5001 to £10000, retrieve image web resource “ts_twocoinpiles.jpg” in byte[] and set the contact record’s “EntityImage” attribute to this image by updating this attribute.
  4. If “Contact Credit Limit” is £10001 and above, retrieve image web resource “ts_threecoinpiles.jpg” in byte[] and set the contact record’s “EntityImage” attribute to this image by updating this attribute.

WARNING: While this requirement can be met by the above 4 steps using Ajax and the REST endpoint, beware that if the image size is large, you might encounter performance issues (especially for CRM 2013 Online).

JavaScript and OData Endpoint In Action …

Firstly, the function “<namespace>.OnAttributeChange_CreditLimit” is hooked to the “OnChange” event in CRM for the attribute “creditlimit” on the contact main form:

//Hook this method to the "OnChange" event of "creditlimit" field
OnAttributeChange_CreditLimit: function () {

    var contactId = Xrm.Page.data.entity.getId();
    var contactCreditLimit = Xrm.Page.getAttribute("creditlimit").getValue();

    if (contactCreditLimit == null || contactCreditLimit < 5001) {

        //retrieve image onecoinpile.jpg and update contact record "EntityImage" attribute
        this.UpdateContactRecordWithNewImage(contactId, "ts_onecoinpile.jpg");

    }
    else if (contactCreditLimit >= 5001 && contactCreditLimit < 10001) {

        //retrieve image twocoinpiles.jpg and update contact record "EntityImage" attribute
        this.UpdateContactRecordWithNewImage(contactId, "ts_twocoinpiles.jpg");

    }
    else if (contactCreditLimit >= 10001) {

        //retrieve image threecoinpiles.jpg and update contact record "EntityImage" attribute
        this.UpdateContactRecordWithNewImage(contactId, "ts_threecoinpiles.jpg");

    }
},

This function grabs the current value of the credit limit attribute on the contact form and checks its value. If it falls into one of the 3 credit ranges, the corresponding web resource image name, along with the contact Guid, are passed to another method called “UpdateContactRecordWithNewImage” function.

UpdateContactRecordWithNewImage: function(contactId, webResourceName){

    this.GetImageWebResource(
        contactId,
        webResourceName,
        this.UpdateContactRecord
    );

},

Note that this is really a wrapper function for another method called “GetImageWebResource”, which takes in both the contact GUID and web resource image name as the first 2 parameters, with the third parameter as the successCallback function if the synchronous “GET” in “GetImageWebResource” is successful.

GetImageWebResource: function (contactId, imageName, successCallback) {

    //OData URI to get address information from parent account record
    var oDataURI = Xrm.Page.context.getClientUrl()
        + "/XRMServices/2011/OrganizationData.svc/"
        + "WebResourceSet"
        + "?$filter="
        + "Name eq '" + imageName + "'"
        + "&$select=Name,Content";

    //Synchronous XMLHttpRequest to retrieve account record
    var req = new XMLHttpRequest();
    req.open("GET", encodeURI(oDataURI), false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.onreadystatechange = function () {
        //debugger;
        if (this.readyState == 4 /* complete */) {
            req.onreadystatechange = null; //avoids memory leaks
            if (this.status == 200) {
                //parse the response string as a JSON object into the successCallback method.
                successCallback(contactId, JSON.parse(this.responseText).d);
            }
            else {
                var errorMsg1 = "GetImageWebResource Error: cannot retrieve image with name = " + imageName + ".";
                //display a non-blocking alert dialog
                Xrm.Utility.alertDialog(errorMsg1, function () { });
            }
        }
    };
    req.send();
},

If the retrieval is unsuccessful, a non-blocking alert dialog is displayed to the user. If the image is retrieved successfully, the successCallback given by “UpdateContactRecord” function is called. The first parameter is the contact GUID, while the second is the JSON object containing the web resource image data.

We can see this image data in its original XMLHttpResponse text form:

ODataEntityImage-05

Where, assigning the “image” variable to “JSON.parse(this.responseText).d” you can see the 2 attributes we have asked for: “Content” in byte[] and “Name” of the web resource.

ODataEntityImage-06

The “UpdateContactRecord” successCallback method takes the image data and “POST” this to as the “EntityImage” attribute of the current contact record:

UpdateContactRecord: function (recordId, webResource) {

    var contact = {};
    contact.EntityImage = webResource.results[0].Content; //byte[] content of the web resource

    var jsonContact = JSON.stringify(contact);

    //OData URI
    var oDataURI = Xrm.Page.context.getClientUrl()
        + "/XRMServices/2011/OrganizationData.svc/"
        + "ContactSet(guid'" + recordId + "')";

    //Synchronous post
    var req = new XMLHttpRequest();
    req.open("POST", encodeURI(oDataURI), false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("X-HTTP-Method", "MERGE");
    req.onreadystatechange = function () {
        //debugger;
        if (this.readyState == 4 /* complete */) {
            req.onreadystatechange = null;
            if (this.status == 204 || this.status == 1223) {
                //reloads the contact record
                window.location.reload(false);
            }
            else {
                var errorMsg2 = "UpdateContactRecord Error: Cannot update contact record with contactId = " + recordId + ".";
                //display a non-blocking alert dialog
                Xrm.Utility.alertDialog(errorMsg2, function () { });
            }
        }
    };
    req.send(jsonContact);
}

The result?

For a new contact record that has no “Credit Limit” set, now if you put in a value in that field, e.g. £4000, the record will be updated to show “onecoinpile.jpg” in the web resource.

ODataEntityImage-07

Similarly, setting the contact’s “Credit Limit” to e.g. £6000 updates the record’s Entity Image to “twocoinpiles.jpg”:

ODataEntityImage-08

Same story with the “threecoinpile.jpg” image.

Ta-da!

Advertisements

5 thoughts on “CRM 2013: JavaScript – Update Entity Image using Rest endpoint without jQuery

  1. I suppose there’s no way to do this with a workflow or a Business Rule? This would be a nice thing to have but I’m not willing to spend money for a consultant on something like that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s