Friday, October 3, 2008

Playing with Notes

This post is more of an example about how one can utilize the “Show Fetch in IFRAME” post in order to consolidate customer information in a focal location.

Consider a scenario where a contact center service rep needs to see the customer’s related notes (annotations) as part of the case service workflow. In order to achieve that using out of box functionality the rep needs to open the customer’s account page, navigate to the notes tab and select the desired document out of all the notes (text and annotations). Most customers find it an unacceptable behavior as do I.

In order to transform the above behavior into a “One Click Process” procedure I’ve added a new IFRAME to the case entity called IFRAME_relatednotes and attached the iframe results to the customer’s lookup onchange event. Each time the customer lookup changes the iframe is filled with the selected customer annotations.

Follow the “Display Fetch in IFRAME” post in order to assign valid FetchViewer Notes Parameters.I’ve also added the FetchViewer Class functionally as part of this example for the sake of completeness.

var customerLookup;
function OnCrmPageLoad()
customerLookup = crmForm.all.customerid;

window.CustomerRelatedNotes = new FetchViewer("IFRAME_relatednotes");
CustomerRelatedNotes.LayoutXml = getLayoutXml();
CustomerRelatedNotes.Entity = "annotation";
CustomerRelatedNotes.QueryId = "{DDDFF6AE-2F52-4640-B2BB-2BA59DA0777C}";
//First Time
CustomerRelatedNotes.RegisterOnTab(0); //IFRAME ON THE DEFAULT TAB
//Consequent lookup selections
crmForm.all.customerid.attachEvent( "onchange" , function(){

The function construct a valid fetchexml depending on the customer selection taking the customer type into account.
If the customer lookup does not contain data then the fetch uses an empty GUID
function SetRelatedNotesFetchXml(){

var customerGuid = "{00000000-0000-0000-0000-000000000000}"
var customerType = "account"

if( customerLookup.DataValue != null )
customerGuid = customerLookup.DataValue[0].id;
customerType = customerLookup.DataValue[0].typename;

var fetchXml = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">';
fetchXml += '<entity name="annotation">';
fetchXml += '<attribute name="subject"/>';
fetchXml += '<attribute name="notetext"/>';
fetchXml += '<attribute name="filename"/>';
fetchXml += '<attribute name="annotationid"/>';
fetchXml += '<order attribute="subject" descending="false"/>';
fetchXml += '<filter type="and">';
fetchXml += '<condition attribute="isdocument" operator="eq" value="1"/>';
fetchXml += '</filter>';
fetchXml += '<link-entity name="' + customerType + '" from="' + customerType + 'id" to="objectid" alias="aa">';
fetchXml += '<filter type="and">';
fetchXml += '<condition attribute="' + customerType + 'id" operator="eq" uitype="' + customerType + '" value="' + customerGuid + '"/>';
fetchXml += '</filter>';
fetchXml += '</link-entity>';
fetchXml += '</entity></fetch>';

CustomerRelatedNotes.FetchXml = fetchXml;

function getLayoutXml(){
return '<grid name="resultset" object="5" jump="" select="1" icon="1" preview="1"><row name="result" id="annotationid"><cell name="subject" width="200" /><cell name="notetext" width="200" /><cell name="filename" width="80" /></row></grid>';

function FetchViewer( iframeId )
var Instance = this;
var vDynamicForm;
var m_iframeTab;
var m_iframeDoc;

Instance.Entity = "";
Instance.Iframe = null;
Instance.FetchXml = "";
Instance.QueryId = "";
Instance.LayoutXml = "";

Instance.RegisterOnTab = function( tabIndex )
Instance.Iframe = document.getElementById( iframeId );

if( !Instance.Iframe )
return alert( "Iframe " + iframeId + " is undefined" );

m_iframeDoc = getIframeDocument();
var loadingGifHTML = "<table height='100%' width='100%' style='cursor:wait'>";
loadingGifHTML += "<tr>";
loadingGifHTML += "<td valign='middle' align='center'>";
loadingGifHTML += "<img alt='' src='/_imgs/AdvFind/progress.gif'/>";
loadingGifHTML += "<div/><b>Loading View...</b>";
loadingGifHTML += "</td></tr></table>";
m_iframeDoc.body.innerHTML = loadingGifHTML;

if( parseInt( "0" + tabIndex ) == 0 ) Instance.Refresh();
else Instance.Iframe.attachEvent( "onreadystatechange" , RefreshOnReadyStateChange );

function RefreshOnReadyStateChange()
if( Instance.Iframe.readyState != 'complete' )


Instance.Refresh = function()
if( !Instance.Iframe )
return alert( "Iframe " + iframeId + " is undefined" );

m_iframeDoc = getIframeDocument();

Instance.Iframe.detachEvent( "onreadystatechange" , RefreshOnReadyStateChange );

var create = m_iframeDoc.createElement;
var append1 = m_iframeDoc.appendChild;
vDynamicForm = create("<FORM name='vDynamicForm' method='post'>");

var append2 = vDynamicForm.appendChild;
append2(create("<INPUT type='hidden' name='FetchXml'>"));
append2(create("<INPUT type='hidden' name='LayoutXml'>"));
append2(create("<INPUT type='hidden' name='EntityName'>"));
append2(create("<INPUT type='hidden' name='DefaultAdvFindViewId'>"));
append2(create("<INPUT type='hidden' name='ViewType'>"));
append1( vDynamicForm );

vDynamicForm.action = "/" + ORG_UNIQUE_NAME + "/AdvancedFind/fetchData.aspx";
vDynamicForm.FetchXml.value = Instance.FetchXml;
vDynamicForm.LayoutXml.value = Instance.LayoutXml;
vDynamicForm.EntityName.value = Instance.Entity;
vDynamicForm.DefaultAdvFindViewId.value = Instance.QueryId;
vDynamicForm.ViewType.value = 1039;

Instance.Iframe.attachEvent( "onreadystatechange" , OnViewReady );

function OnViewReady()
if( Instance.Iframe.readyState != 'complete' ) return; = 0;
Instance.Iframe.detachEvent( "onreadystatechange" , OnViewReady );
m_iframeDoc = getIframeDocument();
m_iframeDoc.body.scroll = "no"; = "0px";

function getIframeDocument(){
return Instance.Iframe.contentWindow.document;



Doug said...

Hi. I've implemented a version of what you describe here so that we can display notes from our tickets (incident in the CRM database) in a custom entity we've created called jobs.

This is nearly perfect for what I need to do. However, I want to be able to add notes and notice that I am restricted to Print, Export to Excel, and Delete. Is there a way I can enable a "New" button or "Add new note"?

Ian Luxton said...

Hi Adi,
One observation is that you might want to add the Note 'createdon' column, then sort descending from that.
I have managed to include the createdon column in the return view but am struggling to alter the sorting.
Doug, Yes you can add a button to the form and use JavaScript to open a window with a generated URL.
Great post!