Basic LiveGrid
The LiveGrid behavior is a powerful concept with tremendous applications for web design. But how do you get the blasted thing working? Hopefully this quick tutorial will describe the process and get you going. I do not like to provide cut and paste code. I believe that the anoying task of having to extrapolate and type it in yourself brings real learning.
I am assuming that you have read the RicoAjaxEngine.pdf at the openrico website and somewhat understand it. You should also read the RicoLiveGrid.pdf document, even though I will probably repeat most of what is in the book.
Note: You need rico-1.1-beta2 for this, and you will need some patches which I show at the bottom.
First Step: Static Content
You serve an html page that is the launching page for the grid. Somewhere in the page's html there is a div tag with an embedded table tag. This div and table tags together comprise the LiveGrid. This "togetherness" is a change in beta2 that tends to frustrate new comers. Do not forget the div tag.
The table tag must have an id. This will be the id of the grid.
The table contains the data for the first X+1 rows, where X is the number of rows you want to show on your grid. So, if you want to show 10 rows on your grid, this first page must contain the data for the first 11 rows. I'll explain soon why the extra row. By default the grid does not call the server to obtain data until you actually scroll, which is why by default you must provide the first rows. I will cover how to preload data later.
In your initialization method for the page, you create a Rico.LiveGrid object as follows:
That's it. No need to create anything else. The first parameter is the id of the table tag -- mygridtab in this example. The pagesize parameter is the number of rows you will display on the livegrid at a time -- 10 in this example. The totalrows parameter is the total number of rows that make up the dataset being shown on the grid. The 'SERVERURL' value is the url on your server that will supply the data to the grid. It is NOT the url that will serve this source page. I use java servlets, and in creating this example my requests went to http://127.0.0.1:8080/ricoexp/GridServlet. Thus, the value for the url was "/ricoexp/GridServlet".
For now ignore the gridopt parameter -- I will cover it later (however, realize that if used it must be an array).
At this point, rico takes over and performs 3 basic steps. First, it creates the scroll bar for the grid dynamically. The scrollbar is created using div tags and the onscroll css attribute. The scrollbar div tag is inserted into the document as the next sibling of the grid's main div.
And third, rico will register the url request for you, and it will create an internal response handler called 'tableid'+'_updater'. A very frustating source of errors is forgetting the "R"; for our example, this handler is called "mygridtab_updater". All responses regarding grid content, should be directed to this updater using the xml tag:
Now the page is displayed and you should have a lovely table with a scroll bar next to it and only 10 rows showing.
Next Step: Scrolling
When you scroll, the grid receives the scroll event and calls the url you defined in the grid creation, as follows:
This means that the grid wants you to send, in nicely formatted rico-style xml, the content for 56 rows starting with the 79th row; the first row is offset zero. This page_size is NOT the same as the grid's creation pagesize parameter. You will need to iterate through your dataset and return ONLY the given rows -- row offset 78 through offset 133 inclusive. The grid contains a buffer manager that controls which rows are required -- hence the potentially odd numbers. The buffer allows the grid to reduce the load on the server and provide a smoother scrolling experience.
I find adding the nbsp entity to the xml to be quite helpful. Also, make sure that you escape in xml several important characters. See the following rico forum a discussion on this XML and Ampersands. If you have Firefox, you can make sure the xml is valid by going directly to the url of the scroll request. If firefox shows text, then you are not setting the content-type from the server correctly to "text/xml". Also, if the xml has any problems, firefox will show you those problems -- very very handy.
The contents of the tag should be normal html for displaying 's. At this point the most common problems are:
Creation Options
The gridopt parameter above contains a number of handy options for the grid. For example, it allows you to add custom parameters to the scrolling http request, or start the grid on a row other than 1, or display a header showing the visible rows.
To add additional parameters to the http request, you need to create an array of name-value pairs and then set the requestParameters attribute on the gridopt array. For example:
This will change the http get request above to be:
To get the grid to start at a different offset, you can use the prefetchOffset option. This option also allows you to prefetch the first set of rows. When you prefetch the data, the launching html page must still contain 11 rows (for our example), but they are without content.
livegrid is the actual Rico.LiveGrid object. offset is the offset (zero based) of the top-most row being displayed. The following onscroll function is based on the openrico demo:
Watch Your Height
One of my hardest problems to solve was related to the height of the rows in the table. Rico and the scrollbar are counting on the fact that they can calculate the scroll offset by multiplying the line height and the row offset. If the line heights are not consistent, the behavior will break. At best the scrolling will seem odd, but most likely the scrollbar will be completely off. It is critical that you use CSS to control the layout of your table so it is always drawn correctly. Here is my style -- which is borrowed from the openrico demos.
Patches
Conclusion
Well, happy griding to all at this time! I would like to cover sorting of grid columns later on and start tackling other rico behaviors. Perhaps the accordion is next! Thanks go to all the great people who have created such an awesome library!
I am assuming that you have read the RicoAjaxEngine.pdf at the openrico website and somewhat understand it. You should also read the RicoLiveGrid.pdf document, even though I will probably repeat most of what is in the book.
Note: You need rico-1.1-beta2 for this, and you will need some patches which I show at the bottom.
First Step: Static Content
You serve an html page that is the launching page for the grid. Somewhere in the page's html there is a div tag with an embedded table tag. This div and table tags together comprise the LiveGrid. This "togetherness" is a change in beta2 that tends to frustrate new comers. Do not forget the div tag.
The table tag must have an id. This will be the id of the grid.
<div>
<table id="mygridtab">
...
</table>
</div>
<table id="mygridtab">
...
</table>
</div>
The table contains the data for the first X+1 rows, where X is the number of rows you want to show on your grid. So, if you want to show 10 rows on your grid, this first page must contain the data for the first 11 rows. I'll explain soon why the extra row. By default the grid does not call the server to obtain data until you actually scroll, which is why by default you must provide the first rows. I will cover how to preload data later.
In your initialization method for the page, you create a Rico.LiveGrid object as follows:
new Rico.LiveGrid( 'mygridtab', pagesize, totalrows, 'SERVERURL', gridopt );
That's it. No need to create anything else. The first parameter is the id of the table tag -- mygridtab in this example. The pagesize parameter is the number of rows you will display on the livegrid at a time -- 10 in this example. The totalrows parameter is the total number of rows that make up the dataset being shown on the grid. The 'SERVERURL' value is the url on your server that will supply the data to the grid. It is NOT the url that will serve this source page. I use java servlets, and in creating this example my requests went to http://127.0.0.1:8080/ricoexp/GridServlet. Thus, the value for the url was "/ricoexp/GridServlet".
For now ignore the gridopt parameter -- I will cover it later (however, realize that if used it must be an array).
At this point, rico takes over and performs 3 basic steps. First, it creates the scroll bar for the grid dynamically. The scrollbar is created using div tags and the onscroll css attribute. The scrollbar div tag is inserted into the document as the next sibling of the grid's main div.
Note: If you do not see a scroll bar appearing, make sure you have patched the rico code as described below.Second, rico will set the height of the grid's div tag to hide the extra row you provided above -- the 11th row. That odd 11th row is used by the grid to give a sense of smooth scrolling. Although it seems redundant do not give into the temptation to throw away the 11th row; rico demands it!
And third, rico will register the url request for you, and it will create an internal response handler called 'tableid'+'_updater'. A very frustating source of errors is forgetting the "R"; for our example, this handler is called "mygridtab_updater". All responses regarding grid content, should be directed to this updater using the xml tag:
<response type="object" id="mygridtab_updater">
Now the page is displayed and you should have a lovely table with a scroll bar next to it and only 10 rows showing.
Next Step: Scrolling
When you scroll, the grid receives the scroll event and calls the url you defined in the grid creation, as follows:
GET /ricoexp/GridServlet?id=mygridtab&page_size=56&offset=78&_=
This means that the grid wants you to send, in nicely formatted rico-style xml, the content for 56 rows starting with the 79th row; the first row is offset zero. This page_size is NOT the same as the grid's creation pagesize parameter. You will need to iterate through your dataset and return ONLY the given rows -- row offset 78 through offset 133 inclusive. The grid contains a buffer manager that controls which rows are required -- hence the potentially odd numbers. The buffer allows the grid to reduce the load on the server and provide a smoother scrolling experience.
Note: I debugged a problem forever, blaming it on rico, only to find out I was returning the wrong number of rows. And believe me, it will really confuse rico and you!The return xml should look something like:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE xsl:stylesheet []>
<ajax-response>
<response type="object" id="mygridtab_updater">
<rows update_ui="true">
<tr>
<td>row 78</td>
<td>something</td>
</tr>
...
<tr>
<td>row 133</td>
<td>nothing</td>
</tr>
</rows>
</response>
</ajax-response>
I find adding the nbsp entity to the xml to be quite helpful. Also, make sure that you escape in xml several important characters. See the following rico forum a discussion on this XML and Ampersands. If you have Firefox, you can make sure the xml is valid by going directly to the url of the scroll request. If firefox shows text, then you are not setting the content-type from the server correctly to "text/xml". Also, if the xml has any problems, firefox will show you those problems -- very very handy.
The contents of the
- an invalid id in the response tag -- do not forget the "r"
- not sending the correct rows or too many rows according to the request. It might manifest itself in javascript errors saying that htmlrow does not have attributes.
- not setting the content-type to text/xml on the http response
- totalrows is not consistent. Make sure the totalrows value you used when creating the grid is the same as the totalrows value you use when iterating through the dataset at the server. In other words, totalrows cannot change from one scroll request to the next.
Creation Options
The gridopt parameter above contains a number of handy options for the grid. For example, it allows you to add custom parameters to the scrolling http request, or start the grid on a row other than 1, or display a header showing the visible rows.
To add additional parameters to the http request, you need to create an array of name-value pairs and then set the requestParameters attribute on the gridopt array. For example:
var reqparams = [ "hi=0", "hey=1" ];
var gridopt = { requestParameters: reqparams }
var gridopt = { requestParameters: reqparams }
This will change the http get request above to be:
GET /ricoexp/GridServlet?id=mygridtab&page_size=56&offset=78&hi=0&hey=1&_=
To get the grid to start at a different offset, you can use the prefetchOffset option. This option also allows you to prefetch the first set of rows. When you prefetch the data, the launching html page must still contain 11 rows (for our example), but they are without content.
var gridopt = {
requestParameters: reqparams,
prefetchOffset: 37 }
requestParameters: reqparams,
prefetchOffset: 37 }
Note: Make sure rico is patched as described below, or this will not work.To display a header that gets updated when the grid scrolls, you can use the onscroll option. The option takes as a value, a function with two parameters. For example:
var gridopt = { onscroll: function(livegrid,offset) { /* change header */ } }
or
var gridopt = { onscroll: myfunction }
...
function myfunction(livegrid,offset) {
/* change some header */
}
or
var gridopt = { onscroll: myfunction }
...
function myfunction(livegrid,offset) {
/* change some header */
}
livegrid is the actual Rico.LiveGrid object. offset is the offset (zero based) of the top-most row being displayed. The following onscroll function is based on the openrico demo:
function gridHeader( livegrid, offset ) {
$(livegrid.tableId+"header").innerHTML = (offset+1) + " - " + (offset+livegrid.metaData.getPageSize()) + " of " +
livegrid.metaData.getTotalRows() ;
}
where the launching html contains,
<div id="mygridtabheader"<>/div>
$(livegrid.tableId+"header").innerHTML = (offset+1) + " - " + (offset+livegrid.metaData.getPageSize()) + " of " +
livegrid.metaData.getTotalRows() ;
}
where the launching html contains,
<div id="mygridtabheader"<>/div>
Watch Your Height
One of my hardest problems to solve was related to the height of the rows in the table. Rico and the scrollbar are counting on the fact that they can calculate the scroll offset by multiplying the line height and the row offset. If the line heights are not consistent, the behavior will break. At best the scrolling will seem odd, but most likely the scrollbar will be completely off. It is critical that you use CSS to control the layout of your table so it is always drawn correctly. Here is my style -- which is borrowed from the openrico demos.
.gridtab { float:left; }
.gridtab table { table-layout: fixed; }
.gridtab td { height: 15px; white-space: nowrap; line-height: 12px; overflow: hidden; }
The grid's main div is the one to which I apply the gridtab class. Notice the use of the overflow: hidden style on the td tag to avoid wrapping of the content that would make the row higher..gridtab table { table-layout: fixed; }
.gridtab td { height: 15px; white-space: nowrap; line-height: 12px; overflow: hidden; }
Patches
- This patch solves a problem with the scrollbar not being displayed on Firefox. See Issue 34 on rico.tigris.org.
@@ -2059,7 +2074,7 @@
this.div = table.parentNode;
this.table = table
this.rowHeight = rowHeight;
- this.div.style.height = this.rowHeight * visibleRows;
+ this.div.style.height = (this.rowHeight * visibleRows) + "px";
this.div.style.overflow = "hidden";
this.buffer = buffer;
this.liveGrid = liveGrid; - This patch enabled prefetchOffset to work correctly. See Issue 35.
@@ -2184,10 +2199,10 @@
this.unprocessedRequest = null;
this.initAjax(url);
- if ( options.prefetchBuffer || options.prefetchOffset > 0) {
+ if ( options.prefetchBuffer || options.prefetchOffset >= 0) {
var offset = 0;
- if (options.offset ) {
- offset = options.offset;
+ if (options.prefetchOffset >= 0) {
+ offset = options.prefetchOffset;
this.scroller.moveScroll(offset);
this.viewPort.scrollTo(this.scroller.rowToPixel(offset));
} - This patch makes the scrolling smoother. It is an optional patch, but I would highly recommend it. See Issue 41.
--- rico.js (revision 31)
+++ rico.js (working copy)
@@ -1874,6 +1874,21 @@
if ( this.scrollTimeout )
clearTimeout( this.scrollTimeout );
+ var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
+ if (scrollDiff != 0.00) {
+ var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
+ if (r != 0) {
+ this.unplug();
+ if ( scrollDiff < 0 ) {
+ this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
+ }
+ else {
+ this.scrollerDiv.scrollTop -= r;
+ }
+ this.plugin();
+ }
+ }
+
var contentOffset = parseInt(this.scrollerDiv.scrollTop /
this.viewPort.rowHeight);
this.liveGrid.requestContentRefresh(contentOffset);
this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
@@ -1882,6 +1897,7 @@
this.metaData.options.onscroll( this.liveGrid, contentOffset );
this.scrollTimeout = setTimeout( this.scrollIdle.bind(this), 1200 );
+ this.lastScrollPos = this.scrollerDiv.scrollTop;
},
scrollIdle: function() {
Conclusion
Well, happy griding to all at this time! I would like to cover sorting of grid columns later on and start tackling other rico behaviors. Perhaps the accordion is next! Thanks go to all the great people who have created such an awesome library!
