Friday, May 29, 2009

CRM 4.0 Show Associated-View in IFRAME (AssocViewer)

This post is complementary to the other posts that discuss presenting a CRM gird inside an IFRAME. As usually when you display an associated view inside an IFRME some of MS functionality breaks e.g. the automatic refresh when you add an existing member. This post uses the same technique as the N2NViewer but overrides the ms _locAssocOneToMany function in order to know when to refresh the grid.

The object exposes the following properties:
1. ParentId – this is the parent entity key. If not specified the viewer uses the current entity crmForm.ObjectId.
2. ParentOtc – this is the parent object type code. Again if not specified the crmForm.ObjectTypeCode is used.
3. RelationshipName – this is the relationship id as it appears in customization.
4. Tabset – this is the name of the tabset parameter which is required for the associated view to work. Use the iedevtoolbar to extract this parameter.

Enjoy...


function OnCrmPageLoad()
{
var assocViewer = new AssocViewer("IFRAME_RelatedContacts");
/* Optional - crmForm.ObjectId */
assocViewer.ParentId = 'D74D44AD-36D0-DC11-AA32-0003FF33509E';
/* Optional - crmForm.ObjectTypeCode */
assocViewer.ParentOtc = 1;
/* Mandatory - relationship schema name */
assocViewer.RelationshipName = "contact_customer_accounts"
/* Mandatory - tabset query string parameter */
assocViewer.Tabset = "areaContacts";
assocViewer.Load();
}

function AssocViewer(iframeId)
{
var av = this;
if (crmForm.FormType == 1)
{
return;
}

av.IFrame = document.all[iframeId];
if (!av.IFrame)
{
alert("Iframe " + iframeId + " is missing!");
}

var _locAssocOneToMany = null;
av.ParentId = crmForm.ObjectId;
av.ParentOtc = crmForm.ObjectTypeCode;
av.Tabset = null;
av.RelationshipName = null;

av.Load = function()
{
if (av.ParentId == null || av.ParentOtc == null || av.Tabset == null || av.RelationshipName == null)
{
return alert("Missing Parameters: ParentId or ParentOtc or Tabset Name!");
}
var security = crmFormSubmit.crmFormSubmitSecurity.value;
av.IFrame.src = "areas.aspx?oId=" + av.ParentId + "&oType=" + av.ParentOtc + "&security=" + security + "&tabSet=" + av.Tabset
av.IFrame.onreadystatechange = av.OnIframeReady;
}

av.OnIframeReady = function()
{
if (av.IFrame.readyState != 'complete')
{
return;
}

av.IFrame.contentWindow.document.body.scroll = "no";
av.IFrame.contentWindow.document.body.childNodes[0].rows[0].cells[0].style.padding = "0px";

_locAssocOneToMany = locAssocOneToMany;
locAssocOneToMany = av.locAssocOneToMany;
}

av.locAssocOneToMany = function(iType, sRelationshipName)
{
_locAssocOneToMany(iType,sRelationshipName);
if (sRelationshipName == av.RelationshipName)
{
av.IFrame.contentWindow.document.all.crmGrid.Refresh();
}
}
}

//Entry Point
OnCrmPageLoad();

35 comments:

Anonymous said...

Dear Adi,

Thank you soo much for posting this valuable information. This is what I was exactly looking for. Let me test it in my environment.

I have been a regular/avid reader of your blogs for the past 1 yr and find it one of the most finest and informative blogs for crm customization.
Thank you once again....

Regards
Prince

Anonymous said...

Hi Adi,

The iFrame is not refreshing for quote details. I have created an iFrame inside quotes for "quote details". I want tomake it dynamic. This is my code. Pls let me know where have I gone wrong

function OnCrmPageLoad()
{
var assocViewer = new AssocViewer("IFRAME_Quotedetails");
/* Optional - crmForm.ObjectId */
assocViewer.ParentId = crmForm.ObjectId;
/* Optional - crmForm.ObjectTypeCode */
assocViewer.ParentOtc = crmForm.ObjectTypeCode;
/* Mandatory - relationship schema name */
assocViewer.RelationshipName = "quote_details"
/* Mandatory - tabset query string parameter */
assocViewer.Tabset = "areaExistingProducts";
assocViewer.Load();
}

function AssocViewer(iframeId)
{
var av = this;
if (crmForm.FormType == 1)
{
return;
}

av.IFrame = document.all[iframeId];
if (!av.IFrame)
{
alert("Iframe " + iframeId + " is missing!");
}

var _locAssocOneToMany = null;
av.ParentId = crmForm.ObjectId;
av.ParentOtc = crmForm.ObjectTypeCode;
av.Tabset = null;
av.RelationshipName = null;

av.Load = function()
{
if (av.ParentId == null || av.ParentOtc == null || av.Tabset == null || av.RelationshipName == null)
{
return alert("Missing Parameters: ParentId or ParentOtc or Tabset Name!");
}
var security = crmFormSubmit.crmFormSubmitSecurity.value;
av.IFrame.src = "areas.aspx?oId=" + av.ParentId + "&oType=" + av.ParentOtc + "&security=" + security + "&tabSet=" + av.Tabset
av.IFrame.onreadystatechange = av.OnIframeReady;
}

av.OnIframeReady = function()
{
if (av.IFrame.readyState != 'complete')
{
return;
}

av.IFrame.contentWindow.document.body.scroll = "no";
av.IFrame.contentWindow.document.body.childNodes[0].rows[0].cells[0].style.padding = "0px";

_locAssocOneToMany = locAssocOneToMany;
locAssocOneToMany = av.locAssocOneToMany;
}

av.locAssocOneToMany = function(iType, sRelationshipName)
{
_locAssocOneToMany(iType,sRelationshipName);
if (sRelationshipName == av.RelationshipName)
{
av.IFrame.contentWindow.document.all.crmGrid.Refresh();
}
}
}

//Entry Point
OnCrmPageLoad();


Regards
prince

Adi Katz said...

Indeed the quote and similar entities like invoice and order that add products as children behave completely different then your regular associated view. For example the product window is not a dialog but a window which complicated things. MS function which opens the product (openFrmObj) does not return a reference to the window which further complicates the process. To make this work you’ll need to make many unsupported customizations so I suggest you let it go.

physicist said...

Hi ,

i need to hide a custom queue that i 've created from the users with CSR role...is there any way i could achieve this? plz help

Adi Katz said...

Not sure how your comment is related to this post. I suggest opening a thread on ms forums. you’ll probably get an answer immediately.

physicist said...

I know that itz irrelavant but i wasn't getttin any workarnds or solutions so i thought i can ask u on this as ur blogs we quite helpful for me in the past.

Any way i've also posted it in MS forms titled " HIDE MS CRM Queues"...would be so kind enough to to look in to it and let me know if i can achieve this as this seems to be quite a crucial requirement for contact center implementations

Adi Katz said...

I Have made our Queue Manager wizard available for purchasing on our website.

if you're interested in developing it your self you'll need to use plug-ins.

Anonymous said...

I am having a slight problem with this code - perhaps someone can help me? I have found it works great in most cases, but I am trying to display the activities and history grids inside IFRAMEs on the Opportunity, and having problems with the refresh. I think it may be because these entities are a bit more complex, with some data on the activitypointer entity. If anyone can point the way to how to tweak this code for this scenario, I would be grateful!

Anonymous said...

Hi Adi,

One question. I want to put a filter to my associated view using your code. In my associated view I have 2 status- Draft and closed. I want to show only records in the draft mode.
How can I or where should I incorporate the filter using fetch xml in your code so that the iframe shows only records in draft mode. Can you pls advice.

Adi Katz said...

The associated view is a built in view. There isn’t any fetchxml involved with this view. You can use a different method as described here and build a fetchxml that mimics the associated view display.

Anonymous said...

Hi Adi,

Thanx for the link. I tried your code. Everything seems to be working. I am able to create records and put filter to it and its getting refreshed also.

The only issue which I am facing is when I try to retrieve one of the existing records from the iFrame instead of showing the record, its opening up a new form with blank data. I am not able to access the existing records but I can see the created records in the view inside the iframe.
Can you pls guide me where I am going wrong? Would you like to see the code?

Thanx

Anonymous said...

Hello Adi,

Glad to see you are still monitoring these comments.

I posted on 7/1 - I am having problems using this code for the Activity and History views (on the Opportunity entity) - the refresh is not working correctly.

Do you have any ideas how I might get this working? It would be a huge help for me.

Thanks

Adi Katz said...

The Assoc viewer overrides the locAssocOneToMany function. When you create an iframe that references the activity or history views you need to override the auto function. Try the following changes…

Replace line 29:
var _auto = null;

replace lines 56 and 57:
_auto = top.auto;
top.auto = av.auto;

replace the av.locAssocOneToMany(…) with:
av.auto = function auto(iObjectTypeCode,sFindValue)
{
/* original function call */
_auto(iObjectTypeCode,sFindValue);
av.iFrame.contentwindow.document.all.crmGrid.Refresh();
}

make sure this does not influence other grid refreshes

Adi Katz said...

About the opening of existing records. I made a quick change to the OnWindowOpen function. Try it now.

Anonymous said...

Hi Adi,

Tried your new code for "Display fetch in IFrame-part2" after you made the changes.
Now the moment I open the parent form inside which the Iframe is located a message comes "Iframe IFrame_quote_fltsch is undefined". IFrame_quote_fltsch is the name of my Iframe and it is located in the first tab. I've given the url as about:blank and removed the check from restrict cross-frame scripting. Now the Iframe is totaly blank.
Pls advice

Anonymous said...

Adi,

Your code for activity and history worked great, however I have one wrinkle.

I have both grids on one form in two separate IFRAMEs. What I am seeing is that when you complete and activity the activities grid refreshes correctly, but the history grid does not. The auto function does not seem to get called in this scenario.

Any ideas as to how to get the history grid to refresh when you open and complete an activity from the IFRAME holding the activity grid?

Thank so much in advance for any guidance you can give - you have been so helpful to date!

Anonymous said...

Dear Adi,

I'm sorry for the previous post. It seems to be working now. I gave a wrong id for my iFrame which I figured out. Anyways eventually its working and I can retrieve the existing records from the view. Thanx a million it works like charm....!!

Anonymous said...

¿Where I have to put de code in order to work? ¿Do I have tu put it in OnLoad event?? please your help. Thanks.

Adi Katz said...

Yes, put the code in the onload event and change the OnCrmPageLoad content with the correct associated view information

Anonymous said...

Hi adi

I would like to know how has anonymous added the same code for displaying pending activities and history in two iframes.I am creating two iframes on the case entity to display pending on one and history on the other.

Kindly help.Thanx for all the useful customizations posted on your blog.

regards

Anonymous said...

Hi,

Thanks, it helped for me to solve my problem. Keep posting...

Joe.com said...

Hi Adi

Great post, thank you.

Is there any way to make the associated view writeable?

Joe

Adi Katz said...

What do you mean by writable? CRM grid is not editable. You can create a master detail from. Take a look at the following post:
http://mscrm4ever.blogspot.com/2008/09/crm-master-detail-page-part-1.html

Joe.com said...

Hi Adi,

Sorry I meant editable. Thanks for the link.

I've read in several places that inline editing of records in the CRM grid may be available in CRM 5.0 - can you shed any light on this?

Thanks

Joe

Shawn said...

Hi Adi,

The code is working great for my views of one-to-many relationships, but is obviously not for many-to-many ones since you wrote this to override the locAssocOneToMany function. Would it be possible to modify this to work for views of many-to-many relationships?

Thanks,
Shawn

Adi Katz said...

Joe - can't say much about crm 5.0.
shawn - follow this link for many2many viewer
http://mscrm4ever.blogspot.com/2009/04/crm-40-many-2-many-iframe-viewer.html

Shawn said...

Hey Adi,

I tried your many-to-many solution and it works perfectly. Thanks so much for all the work you've done on your blog. Just discovered it yesterday when looking for a better view solution and after perusing it I see that there are lot of gems on it. I'm going to try your script loader next. It'll save me a lot of headaches.

Thanks!

Shawn

Anonymous said...

Hi Adi,

Great posts! I've been using both of the viewers without any issues, until recently...

I have 4 of the 1 to Many Iframes on the account entity, and until recently its been running without issues. Now all of a sudden, each form that has this code on it is causing IE to "lock up" for about 20-30+ seconds between clicks (CPU spikes to 50% too)

this is happening on our case entity as well (2 - 1 to many's there too)

**all other entities work as they should without any pauses.

Anonymous said...

Hi Adi

I was customized in your instruct. It's only run local. When run to network, it's not display. Why? Please help me.

Andy said...

Hi Adi,

Awesome scripting. You responded to a question about using this script for activities with the following:

replace the av.locAssocOneToMany(…) with:
av.auto = function auto(iObjectTypeCode,sFindValue)
{
/* original function call */
_auto(iObjectTypeCode,sFindValue);
av.iFrame.contentwindow.document.all.crmGrid.Refresh();
}

I think I'm understanding this wrong - can you clarify?

Thanks!

Andy said...

Hi Adi,

This was great. Hope this doesn't show up twice - my first comment didn't appear, maybe I didn't save it.

Back on July 15 2009 you responded to a question about using this code for activities by instructing the person who asked to replace certain parts of the code. I think I'm understanding this replacement incorrectly:

replace the av.locAssocOneToMany(…) with:
av.auto = function auto(iObjectTypeCode,sFindValue)
{
/* original function call */
_auto(iObjectTypeCode,sFindValue);
av.iFrame.contentwindow.document.all.crmGrid.Refresh();
}

What is the /* original function call */? I'm doing that wrong - can you clarify? My IFRAME refrshes when an activity is closed, but not when a new one is created.

Thanks!

Irinel BIRSAN said...

This solution suppose to work even for read-only forms, because i got an empty grid when the form is in reda-only state

Irinel BIRSAN said...

I have just found a solution for my post. It is working for read only forms but you have to deeal somehow with the iframe src. For the read only forms the path is different. My solution was not to change the path but to add the areas.aspx page in the readonly folder adding to the name a suffix(1 for account, 2 for contact and so on)

Anonymous said...
This comment has been removed by the author.
Anonymous said...

Hi Adi,
I am a very newbie to CRM. I designed an entity which has no relationships. It has a small workflow to send email and assign cases. Users also add their notes. Now my question is how can we show the history of each actiivty performed by the user for every record in an IFRAME? Can you please help me out with this?

Thanks!