CRM2011 has an interesting new feature called subgrids or grids. Basically they are UI elements that show related data on a form. You can load up a form and then load the related records for that forms records in a subgrid. You can then access that data, and even add rows into the subgrid without really leaving your master record. Grids are used throughout CRM2011 and can be used with custom entities just as well. Here an example on the default Opportunities form:
The name in green text above are the CRM names of the grids assigned in the properties of each grid on the form designer. Double click on each grid and you can see the unique grid name.
The name of all grids are case sensitive in Jscript. So, the question arises -- how does Jscript read the contents of these grids? And how do you access them with onLoad and onSave events on a form? The interesting issue is that when you run any Jscript to access these forms on an onLoad you witness a fascinating behaviour - the grids load AFTER the rest of the form has loaded. As a result your Jscript accessing the grid contents will fail due the fact that the grid content has not fully loaded when the rest of the page has loaded. It may take a second or more for all the grids to load after the onLoad event fires. All the code samples of people asking this question do not address how to access grids on an onLoad, except this one. Using this self-referential call to continuously wait for the grid container to appear caused a loop to occur for me that doesn't stop. Furthermore it doesn't check for the contents of the grid, but rather just the container of the grid. There does not seem to be a way to check whether the contents of the grid (.control) has fully loaded!
Using an onSave of course is easier because the grids have already loaded and as a result you don't have to check to see if the content in the grids is fully loaded. The code below shows how to read the content of the grids on an onLoad event. Notice that there are 2 routines. One calls the other and allows for the form to load. Both can be used with onLoad and onSave, but for onSave you can call the routine with a 0ms wait time since you don't really have to wait for anything to load.
function waitTimeout(obj,ms)
{
// alerts can be removed, used for debugging
alert('subgridname='+obj+' timeout='+ms); //check values passed in
setTimeout("JS_RefreshSubgrid('"+obj+"')",ms);
// call grid reading routine after timeout of ms milliseconds
}
function JS_RefreshSubgrid(subgridname)
{
alert('called JS_RefreshSubgrid with param '+subgridname); //did we get into the routine successfully?
var s = document.getElementById(subgridname);
// set s to the container of the grid with timeout val (ms)
alert('s.readyState= '+s.readyState);
// NOTE: only container of the state will show you the readyState which is
// 'complete' when container loaded
var gridControl = document.getElementById(subgridname).control;
// set the gridControl to the control method -- the contents of the grid -- // you cannot call gridControl.readyState unfortunately as the result is
// always 'undefined'
alert('gridControl.readystate: '+gridControl.readyState);
// gridControl.refresh(); NOTE: on an onSave calling .refresh() will cause the grid in question to reload
// making the following code fail when iterating through the routines
alert(subgridname+' has '+ gridControl.getRecordsFromInnerGrid().length + ' rows.');
// get num of rows in grid, if grid not fully loaded this will be 0 !!!
// loop through each row and access each field and show the contents of the grid
for (var intRowNumber = 0; intRowNumber < gridControl.getRecordsFromInnerGrid().length; intRowNumber++)
{
for (var intCellNumber = 0; intCellNumber < gridControl.getRecordsFromInnerGrid()[intRowNumber][3].cells.length; intCellNumber++)
{
alert(gridControl.getRecordsFromInnerGrid()[intRowNumber][3].cells[intCellNumber].outerText);
}
}
}
Here's the call to the waitTimeout routine configured in the Form onLoad trigger:
If there is a different way to do this I sure would like to know as this seems like a hack to load the grid values through an onLoad event.