This discussion is archived
1 2 3 4 Previous Next 57 Replies Latest reply: Oct 25, 2010 12:57 PM by Sc0tt Go to original post RSS
  • 30. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    Hi Gary,

    Thanks for sharing

    As it happens, I may need to do a double-scrolling report next month, so I'll have to give it a go!

    Regards

    Andy
  • 31. Re: Horizontal scrolling report
    676351 Newbie
    Currently Being Moderated
    Hello Gary,
    Thanks for the great post. Applying your template taught me a lot for a project i'm working on. However we plan on abandoning the usage due to it being slow.

    For example, If I run the app with "template: 15. Standard Report", the page loads 100 records in around 15 seconds. When i run with "template: 15. Scrolling Report: Horizontal and Vertical 2900", the page loads the same 100 records in approx. 80 seconds. My app has 40 columns. (one change i did make was to freeze 4 columns instead of just one)

    Did anyone else notice a slow page loading time when using this template? any solution suggestions would be appreciated. The screen was a hit with the users, but the wait time was disappointing.

    Thanks again.

    Edited by: user8018253 on Mar 13, 2009 2:36 PM
  • 32. Re: Does anyone know how to freeze column headings?
    664408 Newbie
    Currently Being Moderated
    Hey Andy,
    where are Before Rows:, Before Column Headings:,Column Heading Template:,After Column Heading: etc in APEX report...Iam not able to find these anywhere. Can yopu please help.
  • 33. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    Hi Gary,

    I now have a double-scrolling report template ready: [http://apex.oracle.com/pls/otn/f?p=267:89]

    This was based on Theme 18's Standard report template but could be adjusted for any template I would imagine.

    There are only two settings in the template that I changed - Before Rows and After Rows.

    The OLD Before Rows was:
    <table cellpadding="0" border="0" cellspacing="0" summary="">#TOP_PAGINATION#
    <tr><td><table cellpadding="0" border="0" cellspacing="0" summary="" class="t18Standard" id="#REGION_STATIC_ID#">
    The OLD After Rows was:
    </table><div class="t18CVS">#EXTERNAL_LINK##CSV_LINK#</div></td></tr>#PAGINATION#</table>
    The NEW Before Rows is:
    <style type="text/css">
    #tableBR {margin:0px; border:0px; padding:0px; table-layout:fixed; white-space:nowrap; width:100%}
    #tableTR {margin:0px; border:0px; padding:0px; table-layout:fixed; white-space:nowrap; width:100%}
    #tableBL {margin:0px; border:0px; padding:0px; table-layout:fixed;}
    #tableTL {margin:0px; border:0px; padding:0px; table-layout:fixed;}
    #tableBR div {margin:0px; border:0px; padding:0px;}
    #tableTR th {white-space:nowrap; text-align:left;}
    #tableTL th {white-space:nowrap; text-align:left;}
    #tableBR td {white-space:nowrap;}
    #tableBL td {white-space:nowrap;}
    #BR {overflow-x:scroll; overflow-y:scroll; padding:0px;}
    #TR {overflow-x:hidden; overflow-y:hidden; padding:0px;}
    #BL {overflow-y:hidden; padding:0px;}
    #TL {overflow-x:hidden; padding:0px;}
    </style>
    <table cellpadding="0" border="0" cellspacing="0" summary="">#TOP_PAGINATION#
    <tr><td>
    <table cellpadding="0" border="0" cellspacing="0" style="border:1px solid #D4D8D9; background-color:#EEEEEE">
      <tr>
        <td style="vertical-align:top"><div id="TL"></div></td>
        <td style="vertical-align:top"><div id="TR"></div></td>
      </tr>
      <tr>
        <td style="vertical-align:top"><div id="BL"></div></td>
        <td style="vertical-align:top"><div id="BR" onscroll="javascript:scrollOthers();">
          <table cellpadding="0" cellspacing="0" class="t18Standard" id="tableBR">
    The NEW After Rows is:
          </table>
        </div></td>
      </tr>
    </table><div class="t18CVS">#EXTERNAL_LINK##CSV_LINK#</div></td></tr>#PAGINATION#</table>
    <script type="text/javascript">
    var tl = document.getElementById("TL");
    var tr = document.getElementById("TR");
    var bl = document.getElementById("BL");
    var br = document.getElementById("BR");
    function setWidths()
    {
      var tBR = br.getElementsByTagName("TABLE")[0];
      var tot = 0;
      var brRows = tBR.rows;
      var c;
      var r;
      for (r = 0; r < brRows.length; r++)
      {
        for (c = 0; c < brRows[r].cells.length; c++)
        {
          if (w[c] == 0)
          {
            brRows[r].cells[c].style.display = "none";
          }
          else
          {
            brRows[r].cells[c].style.width = w[c];
          }
        }
      }
    }
    function splitTable()
    {
      var tBR = br.getElementsByTagName("TABLE")[0];
      var tBRRow1 = tBR.rows[0];
      var tBRRow1Clone = tBR.rows[0].cloneNode(true);
      var tTR = tBR.cloneNode(false);
      tTR.id = "tableTR";
      tr.appendChild(tTR);
      tTR.appendChild(tBRRow1Clone);
      tr.innerHTML += "";
      var tBRBody = tBR.tBodies[0];
      tBRBody.removeChild(tBRRow1);
      br.innerHTML += "";
      tTR = document.getElementById("tableTR");
      var tTL = tTR.cloneNode(false);
      tl.appendChild(tTL);
      tTL.id = "tableTL";
      var tTRRow1 = tTR.rows[0];
      var tTRRow1Cell1 = tTRRow1.cells[0];
      var tTRRow1Clone = tTRRow1.cloneNode(false);
      var tTRRow1Cell1Clone = tTRRow1Cell1.cloneNode(true);
      tTL.appendChild(tTRRow1Clone);
      tTRRow1Clone.appendChild(tTRRow1Cell1Clone);
      tTL = document.getElementById("tableTL");
      tTR.rows[0].deleteCell(0);
      tl.innerHTML += "";
      tr.innerHTML += "";
    
      var tBLClone = tBR.cloneNode(false);
      bl.appendChild(tBLClone);
      tBLClone.id = "tableBL";
      tBL = document.getElementById("tableBL");
      tBR = document.getElementById("tableBR");
      var rows = tBR.rows;
      var r;
      var cClone;
      var rClone;
      var tBLRow;
      for (r = 0; r < rows.length; r++)
      {
        rClone = tBR.rows[r].cloneNode(false);
        cClone = tBR.rows[r].cells[0].cloneNode(true);
        rBLRow = tBL.appendChild(rClone);
        rBLRow.appendChild(cClone);
        tBR.rows[r].deleteCell(0);
      }
      br.innerHTML += "";
      bl.innerHTML += "";
    }
    function scrollOthers()
    {
      tr.scrollLeft = br.scrollLeft;
      bl.scrollTop = br.scrollTop;
    }
    function setDivHeight(h)
    {
      br.style.height = h;
      bl.style.height = h - 18;
    }
    function setDivWidth(w)
    {
      br.style.width = w;
      tr.style.width = w - 18;
    }
    setWidths();
    splitTable();
    </script>
    The only other settings are on the report's region settings themselves - these are to set heights and widths as the report template can be used for any report, so height/width settings may vary.

    The report region's Region Header setting is:
    <script type="text/javascript">
    var w = new Array(100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100);
    </script>
    This is an array of column widths - there should be one number per column displayed. Any column with a width setting of 0 will be hidden.

    The report region's Region Footer setting is:
    <script type="text/javascript">
    setDivHeight(300);
    setDivWidth(500);
    </script>
    This sets the height of the bottom tables and the width of the right-hand tables.

    Finally, on the Report Attributes setting for the region, I have set the following:

    Pagination Scheme: - No Pagination Selected -
    Enable Partial Page Refresh: No
    Number of Rows: 1000
    Maximum Row Count 1000

    As the report should include ALL rows, all pagination should be switched off and the number of rows should be enough to include all rows in the report.


    In the report template, I am defining a 2x2 table, each cell containing a DIV. The DIV in the bottom-right will contain the actual report data. When the page is loaded, the script underneath this 2x2 table will clone the first row in the table (the headings) and copy these into a new table created in the top-right DIV and remove it from the bottom-right table. Then, the first cell in both tables bottom-right and top-right are cloned into new tables in the top-left and bottom-left DIVs and then removed from their original location. The cell widths are set before this happens (just to keep things simple) - hence specifying the Array in the region header. The DIV width should be set to be the total of all of the columns left in the bottom-right table. Note that the width of the top-right DIV and the height of the bottom-left DIV are 18px less than that of the main report region - this is the allow for the width of the scrollbars.

    Andy
  • 34. Re: Horizontal scrolling report
    greich Newbie
    Currently Being Moderated
    Thanks for the code. 2 questions.

    Where do alter the code to allow for more than one froze column?

    How do I default the height of the header row?
  • 35. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    Hi Gary,

    To move more than one column into the fozen tables on the left - these are the bits that move the cells into the left-hand tables:
      var tTRRow1 = tTR.rows[0];
      var tTRRow1Clone = tTRRow1.cloneNode(false);
      tTL.appendChild(tTRRow1Clone);
    *****
      var tTRRow1Cell1 = tTRRow1.cells[0];
      var tTRRow1Cell1Clone = tTRRow1Cell1.cloneNode(true);
      tTRRow1Clone.appendChild(tTRRow1Cell1Clone);
      tTR.rows[0].deleteCell(0);
    *****
      tTL = document.getElementById("tableTL");
      tl.innerHTML += "";
      tr.innerHTML += "";
      var tBLClone = tBR.cloneNode(false);
      bl.appendChild(tBLClone);
      tBLClone.id = "tableBL";
      tBL = document.getElementById("tableBL");
      tBR = document.getElementById("tableBR");
      var rows = tBR.rows;
      var r;
      var cClone;
      var rClone;
      var tBLRow;
      for (r = 0; r < rows.length; r++)
      {
        rClone = tBR.rows[r].cloneNode(false);
        rBLRow = tBL.appendChild(rClone);
    *****
        cClone = tBR.rows[r].cells[0].cloneNode(true);
        rBLRow.appendChild(cClone);
        tBR.rows[r].deleteCell(0);
    *****
      }
      br.innerHTML += "";
      bl.innerHTML += "";
    }
    The parts within the ***** markers can be placed in a loop, so you can move as many columns as you need. Note that the deleteCell(0) method will always remove the first available cell in a row, so there is no need to change these lines.

    The header rows are styled using:
    #tableTR th {white-space:nowrap; text-align:left;}
    #tableTL th {white-space:nowrap; text-align:left;}
    You can add line-height and/or height into these

    Andy

    Edited by: ATD on Apr 22, 2009 2:29 PM
  • 36. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    I've created a second report template to handle multiple fixed columns for the report: [http://apex.oracle.com/pls/otn/f?p=267:86]

    The template's After Rows setting for this is:
          &lt;/table&gt;
        &lt;/div&gt;&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/table&gt;&lt;div class="t18CVS"&gt;#EXTERNAL_LINK##CSV_LINK#&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;#PAGINATION#&lt;/table&gt;
    &lt;script type="text/javascript"&gt;
    var tl = document.getElementById("TL");
    var tr = document.getElementById("TR");
    var bl = document.getElementById("BL");
    var br = document.getElementById("BR");
    function setWidths()
    {
      var tBR = br.getElementsByTagName("TABLE")[0];
      var tot = 0;
      var brRows = tBR.rows;
      var c;
      var r;
      for (r = 0; r &lt; brRows.length; r++)
      {
        for (c = 0; c &lt; brRows[r].cells.length; c++)
        {
          if (w[c] == 0)
          {
            brRows[r].cells[c].style.display = "none";
          }
          else
          {
            brRows[r].cells[c].style.width = w[c];
          }
        }
      }
    }
    function splitTable(fixedColumns)
    {
      var tBR = br.getElementsByTagName("TABLE")[0];
      var tBRRow1 = tBR.rows[0];
      var tBRRow1Clone = tBR.rows[0].cloneNode(true);
      var tTR = tBR.cloneNode(false);
      tTR.id = "tableTR";
      tr.appendChild(tTR);
      tTR.appendChild(tBRRow1Clone);
      tr.innerHTML += "";
      var tBRBody = tBR.tBodies[0];
      tBRBody.removeChild(tBRRow1);
      br.innerHTML += "";
      tTR = document.getElementById("tableTR");
      var tTL = tTR.cloneNode(false);
      tl.appendChild(tTL);
      tTL.id = "tableTL";
      var tTRRow1 = tTR.rows[0];
      var tTRRow1Clone = tTRRow1.cloneNode(false);
      tTL.appendChild(tTRRow1Clone);
      
      var fCol;
      var tTRRow1Cell1;
      var tTRRow1Cell1Clone;
      for (fCol = 0; fCol &lt; fixedColumns; fCol++)
      {
        tTRRow1Cell1 = tTRRow1.cells[0];
        tTRRow1Cell1Clone = tTRRow1Cell1.cloneNode(true);
        tTRRow1Clone.appendChild(tTRRow1Cell1Clone);
        tTR.rows[0].deleteCell(0);
      }
      tTL = document.getElementById("tableTL");
      tl.innerHTML += "";
      tr.innerHTML += "";
    
      var tBLClone = tBR.cloneNode(false);
      bl.appendChild(tBLClone);
      tBLClone.id = "tableBL";
      tBL = document.getElementById("tableBL");
      tBR = document.getElementById("tableBR");
      var rows = tBR.rows;
      var r;
      var cClone;
      var rClone;
      var tBLRow;
      for (r = 0; r &lt; rows.length; r++)
      {
        rClone = tBR.rows[r].cloneNode(false);
        rBLRow = tBL.appendChild(rClone);
        for (fCol = 0; fCol &lt; fixedColumns; fCol++)
        {
          cClone = tBR.rows[r].cells[0].cloneNode(true);
          rBLRow.appendChild(cClone);
          tBR.rows[r].deleteCell(0);
        }
      }
      br.innerHTML += "";
      bl.innerHTML += "";
    }
    function scrollOthers()
    {
      tr.scrollLeft = br.scrollLeft;
      bl.scrollTop = br.scrollTop;
    }
    function setDivHeight(h)
    {
      br.style.height = h;
      bl.style.height = h - 18;
    }
    function setDivWidth(w)
    {
      br.style.width = w;
      tr.style.width = w - 18;
    }
    setWidths();
    splitTable(3);
    &lt;/script&gt;
    The splitTable() call now passes, as a parameter, the number of columns I want fixed in the report. This call could be made from the report's Region Footer, so the template can then be used to fix any number of columns.

    Andy
  • 37. Re: Horizontal scrolling report
    greich Newbie
    Currently Being Moderated
    The report template works great.

    Thanks for the hard word Andy.
  • 38. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    You're welcome, Gary!

    Andy
  • 39. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    Hi Gary,

    OK - I've updated my report template to remove the javascript calls at the bottom - so that they can be called from the report region's Region Footer instead - AND to include a new setRowHeight function to allow us to fix the height of all rows. The default row height is in the template and defined as 25

    So, now my report template's Before Rows setting is:
    &lt;style type="text/css"&gt;
    #tableBR {margin:0px; border:0px; padding:0px; table-layout:fixed; white-space:nowrap; width:100%}
    #tableTR {margin:0px; border:0px; padding:0px; table-layout:fixed; white-space:nowrap; width:100%}
    #tableBL {margin:0px; border:0px; padding:0px; table-layout:fixed;}
    #tableTL {margin:0px; border:0px; padding:0px; table-layout:fixed;}
    #tableBR div {margin:0px; border:0px; padding:0px;}
    #tableTR th {white-space:nowrap; text-align:left;}
    #tableTL th {white-space:nowrap; text-align:left;}
    #tableBR td {white-space:nowrap;}
    #tableBL td {white-space:nowrap;}
    #BR {overflow-x:scroll; overflow-y:scroll; padding:0px;}
    #TR {overflow-x:hidden; overflow-y:hidden; padding:0px;}
    #BL {overflow-y:hidden; padding:0px;}
    #TL {overflow-x:hidden; padding:0px;}
    &lt;/style&gt;
    &lt;table cellpadding="0" border="0" cellspacing="0" summary=""&gt;#TOP_PAGINATION#
    &lt;tr&gt;&lt;td&gt;
    &lt;table cellpadding="0" border="0" cellspacing="0" style="border:1px solid #D4D8D9; background-color:#EEEEEE"&gt;
      &lt;tr&gt;
        &lt;td style="vertical-align:top"&gt;&lt;div id="TL"&gt;&lt;/div&gt;&lt;/td&gt;
        &lt;td style="vertical-align:top"&gt;&lt;div id="TR"&gt;&lt;/div&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td style="vertical-align:top"&gt;&lt;div id="BL"&gt;&lt;/div&gt;&lt;/td&gt;
        &lt;td style="vertical-align:top"&gt;&lt;div id="BR" onscroll="javascript:scrollOthers();"&gt;
          &lt;table cellpadding="0" cellspacing="0" class="t18Standard" id="tableBR"&gt;
    and the After Rows setting is now:
          &lt;/table&gt;
        &lt;/div&gt;&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/table&gt;&lt;div class="t18CVS"&gt;#EXTERNAL_LINK##CSV_LINK#&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;#PAGINATION#&lt;/table&gt;
    &lt;script type="text/javascript"&gt;
    var tl = document.getElementById("TL");
    var tr = document.getElementById("TR");
    var bl = document.getElementById("BL");
    var br = document.getElementById("BR");
    var rh = 25;
    function setRowHeight(h)
    {
      rh = h;
    }
    function setWidths()
    {
      var tBR = br.getElementsByTagName("TABLE")[0];
      var tot = 0;
      var brRows = tBR.rows;
      var c;
      var r;
      for (r = 0; r &lt; brRows.length; r++)
      {
        brRows[r].style.height = rh;
        for (c = 0; c &lt; brRows[r].cells.length; c++)
        {
          if (w[c] == 0)
          {
            brRows[r].cells[c].style.display = "none";
          }
          else
          {
            brRows[r].cells[c].style.width = w[c];
          }
        }
      }
    }
    function splitTable(fixedColumns)
    {
      var tBR = br.getElementsByTagName("TABLE")[0];
      var tBRRow1 = tBR.rows[0];
      var tBRRow1Clone = tBR.rows[0].cloneNode(true);
      var tTR = tBR.cloneNode(false);
      tTR.id = "tableTR";
      tr.appendChild(tTR);
      tTR.appendChild(tBRRow1Clone);
      tr.innerHTML += "";
      var tBRBody = tBR.tBodies[0];
      tBRBody.removeChild(tBRRow1);
      br.innerHTML += "";
      tTR = document.getElementById("tableTR");
      var tTL = tTR.cloneNode(false);
      tl.appendChild(tTL);
      tTL.id = "tableTL";
      var tTRRow1 = tTR.rows[0];
      var tTRRow1Clone = tTRRow1.cloneNode(false);
      tTL.appendChild(tTRRow1Clone);
      
      var fCol;
      var tTRRow1Cell1;
      var tTRRow1Cell1Clone;
      for (fCol = 0; fCol &lt; fixedColumns; fCol++)
      {
        tTRRow1Cell1 = tTRRow1.cells[0];
        tTRRow1Cell1Clone = tTRRow1Cell1.cloneNode(true);
        tTRRow1Clone.appendChild(tTRRow1Cell1Clone);
        tTR.rows[0].deleteCell(0);
      }
      tTL = document.getElementById("tableTL");
      tl.innerHTML += "";
      tr.innerHTML += "";
    
      var tBLClone = tBR.cloneNode(false);
      bl.appendChild(tBLClone);
      tBLClone.id = "tableBL";
      tBL = document.getElementById("tableBL");
      tBR = document.getElementById("tableBR");
      var rows = tBR.rows;
      var r;
      var cClone;
      var rClone;
      var tBLRow;
      for (r = 0; r &lt; rows.length; r++)
      {
        rClone = tBR.rows[r].cloneNode(false);
        rBLRow = tBL.appendChild(rClone);
        for (fCol = 0; fCol &lt; fixedColumns; fCol++)
        {
          cClone = tBR.rows[r].cells[0].cloneNode(true);
          rBLRow.appendChild(cClone);
          tBR.rows[r].deleteCell(0);
        }
      }
      br.innerHTML += "";
      bl.innerHTML += "";
    }
    function scrollOthers()
    {
      tr.scrollLeft = br.scrollLeft;
      bl.scrollTop = br.scrollTop;
    }
    function setDivHeight(h)
    {
      br.style.height = h;
      bl.style.height = h - 18;
    }
    function setDivWidth(w)
    {
      br.style.width = w;
      tr.style.width = w - 18;
    }
    &lt;/script&gt;
    The report region's Region Header is:
    &lt;script type="text/javascript"&gt;
    var w = new Array(150,100,150,100,100,100,100,100,100,100,100,100,100,100,100,100,100);
    &lt;/script&gt;
    This defines the column width (in pixels) for each column - any column width of 0, hides that column

    and the report region's Region Footer is now:
    &lt;script type="text/javascript"&gt;
    setDivHeight(300);
    setDivWidth(600);
    setRowHeight(25);
    setWidths();
    splitTable(3);
    &lt;/script&gt;
    setDivHeight() and setDivWidth() will set the dimensions (in pixels) of the scrollable region of the report
    setRowHeight() will override the default value specified in the template for the height of ALL rows within the entire report
    setWidths() sets the width of the columns within the report based on the values in the Region Header script
    splitTable(n) will perform the split to move the header row AND the specified number of fixed columns into separate tables to leave the main body of the report as the scrollable region

    Andy
  • 40. Re: Horizontal scrolling report
    530062 Newbie
    Currently Being Moderated
    Hi,
    Is it possible to implement this in an interactive report. There are no report templates in IR and cant find before and after rows etc in region template that is assigned to interactive reprot region.

    Appreciate if anyone can help me make it work for interactive reprots.

    Thanks,
    Bhavesh
  • 41. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    Hi,

    You won't have a report template that you can edit. Whilst it MAY be possible to do it purely using javascript on the page, I have not yet found a way to get this to work if you use pagination as this uses Ajax. if someone can tell me how this can be done (that is, calling javascript when paginating through an Interactive Report), then I may be able to have a look at this.

    Andy
  • 42. Re: Horizontal scrolling report
    Postie Newbie
    Currently Being Moderated
    Andy

    Any chance you can export this example & email to me
    dca at nzpost.com

    can't seem to get working..

    I am getting these errors
    #EXTERNAL_LINK##CSV_LINK#
    #PAGINATION# 2Nlp1081011100761A003New Lynn DelNlp108
    #EXTERNAL_LINK##CSV_LINK#

    Thanks
    Dean

    Edited by: Postie on Oct 7, 2009 1:49 PM
  • 43. Re: Horizontal scrolling report
    skahlert Newbie
    Currently Being Moderated
    @ Andy!

    Hello Andy! Just wanted to say big thanks to you for the splendid work! Got your solution running for one report! Looks and behaves fine!
    Nice work!

    Just one question: I have a page with several reports and wanted to use the scroll functionality for two of them. Of course they both differ in column numbers and table width.
    As it appears, I can use the feature for onyl one report on a page as using the template for a second one messes up the alignment of the first report. Furthermore, the second report is not scrollable at all, although I assigned the column values and div width. Is there some possibility to solve that? Have you had similar results?

    Thanks and have a nice day!

    Regards,

    Sebastian
  • 44. Re: Horizontal scrolling report
    ATD Guru
    Currently Being Moderated
    Hi Dean,

    I don't have that page in a standalone application, so can't email it to you.

    Those settings are the ones that should be in the After Rows setting on the template - and should be displayed correctly if entered in the right place. Have you been trying this on an apex.oracle.com workspace?

    Andy

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points