register log on
Knowledge base
 

Dynamically execute child report and display its result within parent report cell using AJAX

KB Artcile # 2630
Arnica WebReport uses AJAX (Asynchronous JavaScript And XML) technologies to dynamically execute another report (or any other service, e.g. web form) in the context of the current record, and display the result within the record's cell. The walk-through below provides the instructions for implementing this type of report. Another purpose of this walk-through is to demonstrate how to create report cell output with free-form formatting, by placing report cells not only horizontally from left to right, as in conventional report or spreadsheet output, but also using vertical space. This technique is useful when displaying child report output within the same record as its dimensions might require custom placement of other report columns within the record for better presentation.

To create the whole solution, we need two reports: parent report (Products) and child report (TransactionHistory). Parent report shows line items for each product with a hyperlink in each record to execute child report and display transaction history within the same record of the parent report.

The parent report has many columns, we need to make these columns not visible online (to suppress default left to right column placement), and create a custom column called ProductPresentation, which contains references to columns and custom placement within one continuous cell.



For the data definition type of the ProductPresentation custom column we select Column Template in order to allow specifying HTML code, which defines how other columns are placed relative to one another.



Complete column template is included below. HTML content includes evaluatable expressions referencing the actual columns between delimiters <% and %>.

<div class="aaContainer" style="padding:6px;">
<table class="aaContainerTable">
<tr>
<td rowspan="8" style="width:300px;">
<img src="<%oData.oGlobalParameter.DemoURI%>FormServer/Output/Proxy.aspx?
                              Method=ExecuteScript&ScriptCode=DEMO7AWGetProductPhoto&
                              ProductPhotoID=<%transform(sourcedata.productphotoid)%>" /></td>
<td style="font-weight:bold;width:150px;color:#555555;">Name</td>
<td><%alltrim(sourcedata.name_)%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Sell Start Date</td>
<td><%dtoc(ttod(sourcedata.SellStartDate))%></td>
</tr>

<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Product Category</td>
<td><%transform(sourcedata.ProductCategoryName)%></td>
<td style="font-weight:bold;width:150px;color:#555555;">List Price</td>
<td><%transform(sourcedata.ListPrice, '99,999,999.99')%></td>
</tr>

<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Product Subcategory</td>
<td><%transform(sourcedata.ProductSubcategoryName)%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Standard Cost</td>
<td><%transform(sourcedata.STANDARDCOST, '99,999,999.99')%></td>
</tr>

<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Class</td>
<td><%alltrim(nvl(sourcedata.class_, 'NA'))%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Product Number</td>
<td><%transform(sourcedata.ProductNumber)%></td>
</tr>
<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Color</td>
<td><%alltrim(nvl(sourcedata.color, 'NA'))%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Weight</td>
<td><%transform(nvl(sourcedata.Weight, ''), '99,999,999.99')%>&nbsp;
                    <%alltrim(nvl(sourcedata.WEIGHTUNITMEASURECODE, ''))%></td>
</tr>
<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Product Line</td>
<td><%alltrim(sourcedata.productline)%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Size</td>
<td><%transform(nvl(sourcedata.size, 'NA'))%>&nbsp;
                    <%alltrim(nvl(sourcedata.SIZEUNITMEASURECODE, ''))%></td>
</tr>

<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Product ID</td>
<td><%transform(sourcedata.ProductID)%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Reorder Point</td>
<td><%transform(sourcedata.REORDERPOINT)%></td>
</tr>


<tr>
<td style="font-weight:bold;width:150px;color:#555555;">Ready To Sell</td>
<td><%oServer.oSystem.ConvertBooleanToString(sourcedata.FINISHEDGOODSFLAG)%></td>
<td style="font-weight:bold;width:150px;color:#555555;">Safety Stock Level</td>
<td><%transform(sourcedata.SAFETYSTOCKLEVEL)%></td>
</tr>

<tr>
<td></td>
<td></td>
<td><a name="a<%transform(sourcedata.productid)%>" id="a<%transform(sourcedata.productid)%>"
                       href="JavaScript:getTransactionList(<%transform(sourcedata.productid)%>)"
                       class="aaTextLink" style="font-weight:bold;">Show Transactions</a></td>
<td></td>
<td></td>
</tr>

<tr id="r<%transform(sourcedata.productid)%>" style="visibility: hidden; display: none;">
<td></td>
<td colspan="4" ><div id="d<%transform(sourcedata.productid)%>" >&nbsp;</div></td>
</tr>
</table>
</div>

Thus, using standard HTML we customized presentation of the parent report output to look like this:



Note, that in the code above, the Show Transactions hyperlink references JavaScript function getTransactionList(). This JavaScript function is defined and saved in the report header, which may be accessed via report properties page:





Below is the complete content of the JavaScript:

<script>

var nCurrentIndex        = 0;
function GetXMLHTTPObject()
{
    var XMLHttp = [
        function () {return new XMLHttpRequest()},
        function () {return new ActiveXObject("Msxml2.XMLHTTP")},
        function () {return new ActiveXObject("Msxml3.XMLHTTP")},
        function () {return new ActiveXObject("Microsoft.XMLHTTP")}
    ];

    var oXMLHTTP = null;
    for (var i=0; i < XMLHttp.length; i++) {
        try {
            oXMLHTTP = XMLHttp[i]();
        }
        catch (e) {
            continue;
        }
        break;
    }
    return oXMLHTTP;
}

function handler()
{
    if (oReq.readyState == 4 ) {
        if (oReq.status == 200) {
            var oOriginalElement      = document.getElementById("d" + nCurrentIndex);
            var oTempElement          = document.createElement(oOriginalElement.tagName);
            oTempElement.id           = oOriginalElement.id;
            oTempElement.className    = oOriginalElement.className;
            oTempElement.innerHTML    = oReq.responseText;
            oOriginalElement.parentNode.replaceChild(oTempElement, oOriginalElement);
        }
    }
}

var oReq = GetXMLHTTPObject();

function getTransactionList(nIndex)
{
   var oEl                   = document.getElementById("r" + nIndex);
   oEl.style.visibility      = ((oEl.style.visibility == "hidden") ? "" : "hidden");
   oEl.style.display         = ((oEl.style.display == "none") ? "" : "none");
   var oLk                   = document.getElementById("a" + nIndex);
   oLk.innerHTML             = ((oEl.style.visibility == "hidden") ? "Show Transactions" : "Hide Transactions");
   if (oEl.style.visibility == "")
   {
        nCurrentIndex        = nIndex;
        cURI = "<%oData.oGlobalParameter.DemoURI%>WebReport/Output/proxy.aspx?";
cURI = cURI + "Method=LoadReportPage<ReportCode=DEMO7AWTransactionHistoryEmbedded&ProductID=";
        cURI = cURI + nIndex + "&SessionToken=<%oServer.oUserSession.cSessionToken%>&IsCompleteHTMLPage=0"; if (oReq != null) { var oEl = document.getElementById("d" + nCurrentIndex); oEl.innerHTML = "Please wait, processing..." oReq.open("GET", cURL, true); oReq.onreadystatechange = handler; oReq.send(); } else { alert("Fail"); } } }
In the script above, the highlighted line provides a reference to the child report passing identifier of the ProductID (for which to show the transaction list), as well as includes WebReport API parameter IsCompleteHTMLPage=0, which tells the child report to include only inner body content of the generated child report HTML output as this content will be dynamically inserted into the HTML page of the parent report which already has HTML document top level declaration  tags.

Child report (TransactionHistory) was configured to display the following columns:




Child report was also setup to use a filter by ProductID to properly filter records in the context of the selected record of the parent report:

10-13-2010 11-57-35 AM.png




Thus, with a click on the Show Transactions hyperlink, content generated by the child report is merged with the page displaying parent report output:


10-13-2010 11-53-42 AM.png

The JavaScript included in the parent report header content also changes the hyperlink caption from Show Transactions to Hide Transactions; click on the Hide Transactions hyperlink removes child report presentation from the parent report. Repeated click on Show Transactions hyperlink re-executes child report in real-time and re-displays transaction history data.