Thursday, March 12, 2009

Microsoft CRM: Embedding Advanced Find Views in Entity Forms (Version 3)

[UPDATE: See Version 4 of the code in this post at]

So, I ran into a little problem using the New button override on an embedded AF view on a Contract Line entity. Apparently top.locAddObjTo() does not function properly on this particular record type. So, I modified the code to use the more appropriate locAddRelatedToNonForm() function. This function takes one more parameter, which I haven't identified, but apparently it's not required or is often set to a blank string. Best of all, this function works from the Iframe, and is the function used by the ordinary Associated View for custom entities. As of yet, I've only tested it with embedded AFs that display custom entities, but it appears to work from any "parent" entity form.

Version 3:

/// Summary: 
/// Provides a mechanism for replacing the contents of any Iframe on an entity form 
/// with any Advanced Find view. 
/// Param Description 
/// ---------- ------------------- 
/// iFrameId The id established for the target Iframe 
/// entityName The name of the entity to be found by the Advanced Find 
/// fetchXml FetchXML describing the query for the entity 
/// layoutXml LayoutXML describing the display of the entity 
/// sortCol The schema name of the entity attribute used for primary sorting 
/// sortDescend "true" if sorting the sortCol by descending values, or "false" if ascending 
/// defaultAdvFindViewId The GUID of an Advanced Find View for the entity; may that of a saved view 
/// entityTypeId (Optional) The Object Type ID for the entity. Setting this causes the system 
/// to overwrite the functionality of the "New" button to establish related records

function EmbedAdvancedFindView (iFrameId, entityName, fetchXml, layoutXml, sortCol, sortDescend, defaultAdvFindViewId, entityTypeId) { 
  // Initialize our important objects 
  var iFrame = document.getElementById(iFrameId); 
  var httpObj = new ActiveXObject("Msxml2.XMLHTTP"); 
  var url = "/AdvancedFind/fetchData.aspx"; 
  // Compile the FetchXML, LayoutXML, sortCol, sortDescend, defaultAdvFindViewId, and viewId into 
  // a list of params to be submitted to the Advanced Find form 
  var params = "FetchXML=" 
    + fetchXml 
    + "&LayoutXML=" 
    + layoutXml 
    + "&EntityName=" 
    + entityName 
    + "&DefaultAdvFindViewId=" 
    + defaultAdvFindViewId 
    + "&ViewType=1039" // According to Michael Hohne over at Stunnware, this is static 
    + "&SortCol=" 
    + sortCol 
    + "&SortDescend=" 
    + sortDescend; 
  // Establish an async connection to the Advanced Find form"POST", url, true); 
  // Send the proper header information along with the request 
  httpObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
  httpObj.setRequestHeader("Content-length", params.length); 
  // Function to write the contents of the http response into the iFrame 
  httpObj.onreadystatechange = function () { 
    if (httpObj.readyState == 4 && httpObj.status == 200) { 
      // Shorthand to the document of the Iframe 
      var doc = iFrame.contentWindow.document; 
      // Without a null src, switching tabs in the form reloads the src 
      iFrame.src = null; 
      // Write the contents of the response to the Iframe; 
      // Set some style elements of the Advanced Find window 
      // to mesh cleanly with the parent record's form = "0px"; = "#eaf3ff"; 
      // Should we overwrite the functionality of the "New" button? 
      if ((typeof(entityTypeId) != "undefined") && (entityTypeId != null)) { 
        var buttonId = "_MBopenObj" + entityTypeId; 
        var newButton = doc.getElementById(buttonId); 
        eval("newButton.action = 'locAddRelatedToNonForm(" + entityTypeId + ", " + crmForm.ObjectTypeCode + ", \"" + crmForm.ObjectId + "\",\"\");'");
  // Set it, and forget it!