Tuesday, February 10, 2009

Displaying an Image in an IFRAME


This seems like a very simple requirement. But when it comes to implementation, you might find that fitting this requirement into an already existing functionality such as the CRM the annotations (notes) facility, is not as strait forward as it sounds.

Wanting to display a user avatar, a company logo or even a product image is a very acceptable requirement. And since CRM does not allow such facility out of box, I figured it would be nice to show you how this could be done in just a few minutes.

The simplest solution would be to place all images under the ISV folder then create an IFRAME, where desirable, and set its SRC attribute to a specific URL through script. This also requires the user or application to adhere to a strict naming convention such as a contact FirstName + LastName.gif or an account accountid.jpg or accountnumber.bmp and so forth.

For the sake of discussion the rest of my code bits would refer to the account entity and presenting an account logo inside a dedicated iframe e.g. IFRAME_accountlogo.

Your code might look like the following lines:


var accountLogo = "/isv/images/accounts/missing.gif";
If (crmForm.accountnumber.DataValue != null)
{
accountLogo = "/isv/images/accounts/" + crmForm.accountnumber.DataValue + ".gif";
}
document.all.IFRAME_accountlogo.src = accountLogo;


This process is quite limiting since it requires the involvement and communication with a power user or an administrator who need to put the images in their respective folders. They also need to manage the changes and deletions of images from that folder for obvious reasons. By now this looks like a bad strategy and we need to come up with a better and more manageable solution.

Can I upgrade the above solution? The answer is of course you can! You can automate this type of process by allowing the user to upload the image to a specified location and saving the image name to a new dedicated attribute you set on the entity e.g new_accountimagename.

The client side script might look like the following lines:


var accountLogo = "/isv/images/accounts/missing.gif";
if (crmForm.new_accountimagename.DataValue != null)
{
accountLogo = "/isv/images/accounts/" + crmForm.new_accountimagename.DataValue;
}
document.all.IFRAME_accountlogo.src = accountLogo;


You might argue, and rightly so, that this type of solution does not completely resolve the need for our administrator to manage these folders, and CRM already has an uploading facility (for annotations), so why not use that?!
Obviously this type of solution only answers a partial requirement and we need to come up with a better one yet again.

So how do you take advantage of CRM’s annotation facility? And how can you bind the upload process to an IFRAME?

If you ask a developer, with no relevant knowledge of dynamics, how to do that with asp.net he would probably tell you that you need to read the binaries from the database and render them back to the calling image on the client.

e.g.




Wait a minute, this looks very familiar. And indeed it is! as CRM already uses this type of functionality inside the email entity. When you track an email with an inline image from outlook client CRM saves the inline image as attachment and present it inside the email body.

e.g.


image001.png


So I asked my self why would ms send the attachment entity type if this type of functionality is only for attachments? And as it appears if you change the AttachmentType parameter from 1001 to 5 (annotation object type code) and set the attachmentid to an annotationid you receive the desired results.

e.g.





And your onload script should look like:


var annotationid = getAccountLogoAnnotationId();
var iframeDoc = document.all.IFRAME_accountlogo.contentWindow.document;
var image = iframeDoc.createElement('img');
image.src = prependOrgName("/Activities/Attachment/download.aspx?AttachmentType=5&AttachmentId=") + annotationid;
iframeDoc.body.appendChild(image);


The getAccountLogoAnnotationId function should use a fetchxml to retrieve the annotationid. The best way of doing that is telling the user to upload the image under a well known name and creating a constant fetchxml request as follows.














Is this type of solution consider supported? My first gut feeling is actualy yes. I don’t see why ms would downgrade this type of solution to only support email attachment. The only thing that might change is the actual url. This seems a good enough solution for a 5 minute work.

Eventually you might mimic the entire functionality your self by creating a download.aspx page, reading the image binaries from the filtered annotation view and render the result your self.

For a complete example of how to use an Ajax fetch call to CRM follow this post.

19 comments:

raj said...

where can i write the funcion()?

Adi Katz said...

Inside the onload event box of the entity that shows the image.

For example: if you're interested in displaying a company logo then add the script to the account entity onload event.

hpreis said...

Hello... I've implemented your solution. When the form loads, the picture is shown very shortly and then the iFrame is blank. So no picture will be shown in the iFrame after one second. Could you imagine, what's the reason for this behaviour?
Thanks in advance

Adi Katz said...

Did you implement the iframe on the default (first) tab?

hpreis said...

when i implement the iFrame on the first tab, I've seen nothing. The following code works:
var iframeDoc = crmForm.all.IFRAME_image.contentWindow.document;
iframeDoc.write("[<]html[>][<]body[>][<]img src='" + prependOrgName("/Activities/Attachment/download.aspx?AttachmentType=5&AttachmentId=10186578-D733-DE11-B04F-000C29566137") + "'[>][<]/body[>][<]/html[>]");

When i implement the iFrame on an other tab, the described behaviour appears.

When I set your code to an onChange event of a field, the picture is shown. I use the product entity.

Thank you for your help...

hpreis said...

It seems, that the (update) Form is loading twice the iFrame Content and set the default iFrame Source which is: about:blank.

Stephanie said...

Hi,
Did you manage to get this working or is the image still disappearing? I'm having the same problem and can't figure it out. Any suggestions?

Many thanks in advance.

Bill said...

hello !

my image disappear too...
did you solve this problem ?

Thx :)

Dave Berry said...

Once again, capital work, Adi!

Adi Katz said...

Cheers

Anonymous said...

hi,

where should i put the fetchxml code

Shai said...

if the image disappear add line before:
crmForm.all.IFRAME_image.src="";

Alejandro Cesetti said...

Hi Adi.
I have used this code, and it is not working for me either.
What I did to make it work was to remove the following lines:

var iframeDoc = document.all.IFRAME_accountlogo.contentWindow.document;
var image = iframeDoc.createElement('img');
image.src = prependOrgName("/Activities/Attachment/download.aspx?AttachmentType=5&AttachmentId=") + annotationid;
iframeDoc.body.appendChild(image);

and change them for the following one:

crmForm.all.IFRAME_accountlogo.src = "/Activities/Attachment/download.aspx?AttachmentType=5&AttachmentId=" + annotationid;

With this only change, it started to work.
But..when I installed the Update Rollup 7 it stopped working. The issue here is a new security constraint added by Microsoft (http://mscrmuk.blogspot.com/2009/11/ur-7-breaks-attachment-download-code.html).
Has anyone overcome this issue?

Thanks in advance.

Unknown said...

Hi,

I have a web application that uses iframes and I want to display that web page in an IFrame of Microsoft Dynamics CRM.

I have been doing some test and can't visualize the web page. Is it possible to view an iframe web page?
I also have been doing some test with sample iframe web pages from internet and still with same problem.

I hope you could help me.

Thanks,

Diana

Anonymous said...

Update Rollup 7 appears to have introduced a new RPC Security Token that is sends when requesting attachment downloads. There is example code in the CRM SDK that shows how to automatically download a specific CRM attachment, but no longer works now because of the new token.

Dave Berry said...

Tito-Z came up with some code to work in a post-UR7 environment (with a little assistance from me). Unfortunately, it requires IE8, but the solution can be found at: http://crmentropy.blogspot.com/2010/10/tito-zs-iframe-embedded-image-code.html

yogev izhak said...

hi all!

try also that solution:

http://blogs.msdn.com/b/crm/archive/2009/12/16/tips-tricks-displaying-contact-images-in-microsoft-dynamics-crm.aspx

Ben said...

As mentioned by link from Dave, the Fetch Xml working fine on Rollup 11 for me, but image is cropped at the bottom dut to the Web Service response length (as the images is sent as a base64 string); too bad...

Anonymous said...

sir,
now i am use for crm dynamic, so i want to do to load image in the site of cotact detail, the code atre written me is html or any thing pls guide me
sanfgamitra