An oft-requested requirement as part of any Dynamics CRM/Dynamics 365 for Enterprise (D365E) deployment is a level of integration with another application system. In some of these cases, this will involve pulling through external web pages and passing them form-level attribute values, to load an external systems report, record page etc. From a CRM/D365E point of view, this can be very straightforwardly achieved thanks to some of the functionality provided as part of the Xrm.Page object model. For example. let’s assume that you have an IFrame control on your form and you wanted to load an ASP.NET web page, passing the ID of the record as a query parameter in the URL. Setup your IFrame on your form, with a random URL and set to hidden. Then, a JScript function like this on the OnLoad event would get the job done for you:
function loadIFrame() {
//Get the current record ID
var entityID = Xrm.Page.data.entity.getId();
//Replace { & } with their appropriate URL counterparts in entityID
entityID = entityID.replace("{", "%7b");
entityID = entityID.replace("}", "%7d");
//Create the URL
var url = "http://myexternalwebpage.com/MyAspPage.aspx?id=" + entityID;
//Then, update the IFrame with the new URL and make it visible on the form
Xrm.Page.getControl("IFRAME_myiframe").setSrc(url);
Xrm.Page.getControl("IFRAME_myiframe").setVisible(true);
}
What helps with the above is that there are well-documented code samples that assists when putting together this example, so you can be confident that the solution will work and is fully supported.
Things get a little more complicated once we are operating outside the standard CRM/D365E environment. Assume that instead of displaying this IFrame control on a form, it needs to be displayed as part of an Entity Form in Adxstudio/CRM Portals. Here is where the head scratching can commence in earnest, and you need to look at getting your hand’s dirty writing custom code to achieve your requirements. There a few hurdles to overcome in the first instance:
- How do you access attribute values from an Entity Form, such as a record ID?
- Once you are able to access the attribute value, how to you set this up on your Entity Form?
- How do you embed an IFrame within an Entity Form?
Let’s take a look at one approach to the above, working on the same basis as above - an external URL that we pass the record ID to, from within an Entity Form Web Page. Things may get a bit more difficult if you need to access other entity attribute values, which may require some kind of trickery with Liquid Templates to achieve successfully.
Accessing Entity Form Record ID
When your Entity Form page is loaded on your Portal, there are a number of properties regarding the record that are exposed on the underlying web page - the name of the entity, the record ID, Status and Status Reason values. These can be accessed via a div element on the page, which can be viewed within the DOM Explorer as part of a Web Browsers developer tools (in the below example, Internet Explorer is used):
The id of the div class will always be the same, except for the value in the middle, which is the GUID for the Entity Form record within CRM/D365E, but without the dashes. So you don’t need to necessarily go into the DOM to get this value; as a time-saving mechanism, simply export your Entity Form record into Excel and view the first hidden column to obtain this value.
Suffice to say, because we know that this value is accessible when our Portal page loads, we can look at programmatically accessing this via a JScript function. The following snippet will do the trick:
var recordID = document.getElementById('EntityFormControl_31c41a020771e61180e83863bb350f28_EntityFormView_EntityID').value;
Now that we have a means of accessing the attribute value, our options in terms of what we can do with it greatly increase 🙂
Executing Entity Form Custom JScript Functions
There are two ways you can place custom JScript on your portal page - you can either place your functions within the Custom JavaScript field, located on the Entity Form form within CRM:
Functions will be added to the bottom of your Web Page when loaded, meaning they can be freely accessed after the page has loaded. The second way, which leads us nicely onto the next section, is to wrap your JScript function as a custom HTML snippet on the Web Pages Copy (HTML) field.
Embedding an IFrame on your Web Page
All Web Pages in Adxstudio/Portals - irrespective of what other content the page is loading - contain a Copy (HTML) field. This enables you to write your own bespoke text or other HTML content that is displayed on the Web Page. In the case of an Entity Form Web Page, then the content will be displayed just below the Entity Form. Thanks to the ability to access and write our own custom HTML code for this, options for bespoke development are greatly increased - simply click the Source button to switch to the underlying HTML editor:
Then, using a combination of the snippet we used earlier and utilising the HTML tag, we can place the following in our Copy (HTML) to do the lot for us - get our record ID, pass it to an external web page and then load this within an IFrame:
<p>
<script>
function getEntityID() {
var url = "http://myexternalwebpage.com/MyAspPage.aspx?id=";
var entityID = document.getElementById('EntityFormControl_31c41a020771e61180e83863bb350f28_EntityFormView_EntityID').value;
var iframeSrc = document.getElementById('myiframe').src;
if (iframeSrc != url + "%7b" + entityID + "%7d") {
setTimeout(function () {
document.getElementById('myiframe').src = url + "%7b" + entityID + "%7d";
}, 2000);
}
}
</script>
</p>
<h1>My IFrame</h1>
<p>
<iframe width="725" height="250" id="myiframe" src="" onload="getEntityID();"></iframe>
</p>
The reason why setTimeout is used is to ensure that the entity form class loads correctly, as this is one of the last things that Adxstudio/Portals loads last on the page. For obvious reasons, if this hasn’t loaded, then our JScript function will error. Putting this aside, however, the above solution gets us to where we want to be and means that we can achieve the same outcome as the CRM/D365E example demonstrated at the start of this post 🙂
Conclusions or Wot I Think
Adxstudio/Portals presents some interesting and different learning opportunities, both given its genesis as a separate product to its gradual integration as part of the CRM/D365E family. This can often mean that you have to abandon your base assumptions and ways of thinking when it comes to CRM/D365E development, and instead look at things from a more general approach. I would hope that, in time, we will begin to see the gradual introduction of common XRM object models within CRM Portals, as it is crucially important that there is a unified approach when developing Portal extensions in the future and that we are not in the situation where unsupported code becomes rampant across different Portal deployments. This latter concern would be my chief worry with the examples provided in this post, as there is currently no clear way of determining whether the approach taken is supported or considered “best practice” from an Adxstudio/Portal perspective. I would be interested in hearing from anyone in the comments below if they have any thoughts or alternative approaches that they would recommend to achieve the above requirement.