Ajax Paging Through Records On Scroll

I've always thought one of the cooler features on dzone was how they paged through the entries as you scroll down the list. This seems a ton more user friendly then the traditional 'next/previous' links.

I decided to see how easy it would be to recreate this functionality using ColdFusion 8 and as usual the answer was 'pretty easy'. There is a bit of JavaScript, but it's nothing too difficult to wrap your head around.

Check the demo here first. I intentionally sleep the thread for 1 second so you can see the loading icon - so don't think that it's just slow :).

On to the code bits. The first thing I have going here in this example is a super simple cfajaxproxy:

<cfajaxproxy cfc="test" jsclassname="test" />

This lets me call the function to get the display data with JavaScript - which is important in this example rather then using binding or ColdFusion.navigate(). See, I'd rather that the user really not know what was going on - and using those other methods would swap out the contents of the container and give a loading icon while we made the Async call. Normally that's ok, I just wanted this to be seemless because later we'll append the page of data to our innerHTML rather then fully replacing it.

Next I create the JS variable representing the Ajax proxy and declare a few other variables that will be used later on:

var testProxy = new test();
var startRow = 1;
var loading = "";

The main JS functions that handle the data retrieval are here:

getData = function(){
   if(!loading){
      loading = true;
      testProxy.setCallbackHandler(populateData);
      var loadIcon = document.getElementById('loadingIcon');
      loadIcon.style.visibility = 'visible';
      var data = testProxy.getRecords(startRow);   
   }   
}

So when this function is called (we'll look at that later) it checks the global 'loading' variable to make sure it's not already getting some data. Next I set a callback handler for the proxy to the 'populateData' function. This ensures that I'll be able to hide the loading gif when the data retrieval is finished. Here's the callback function:

populateData = function(d){
   var container = document.getElementById('display');
   var loadIcon = document.getElementById('loadingIcon');
   container.innerHTML = container.innerHTML + d;
   loadIcon.style.visibility = 'hidden';
   loading = false;
}

The callback takes one argument, the result of the CFC invocation. This function takes that data and appends it so the innerHTML of the display container. Finally I reset the loading flag to false signifying that the request is complete. Here's the display container:

<div id="display" style="height: 100px; width: 300px; overflow-y: scroll;" onscroll="javascript:scrollAction();"></div>
<div id="loadingIcon" style="visibility: hidden;"><img src='/CFIDE/scripts/ajax/resources/cf/images/loading.gif'/></div>

So just a fixed height div with an that fires another JS function onscroll. That function looks like this:

scrollAction = function(){
   var container = document.getElementById('display');
   if(!loading){
      if(container.scrollTop+container.clientHeight == container.scrollHeight){
         startRow = parseInt(startRow) + 10;
         getData();
      }
   }   
}

Again I check that there is not a current request running by checking the 'loading' variable. The next line was a bit tricky:

if(container.scrollTop+container.clientHeight == container.scrollHeight)

So this checks the scrollTop variable against the scrollHeight to determine if the current scroll is at the bottom of the div (ready to get more records in other words). However since the div's height will grow everytime we append more data I had to ensure that the variable div height was accounted for. Adding the clientHeight to the scrollTop handled that nicely.

If the conditional passes then we increment the global startRow variable and call the getData() function.

Oh also - A quick load event in the body makes sure we intially load the first 'page' of data.

<body onload="getData(1);">

Full code for this demo is attached.



Comments
Very cool.
# Posted By Sam Farmer | 8/21/07 6:42 PM
This is very cool indeed. I've been looking for help in creating this functionality for dayS!

Although I was looking for a jquery equivalent of this but this will do :)

thanks again
# Posted By Bhaarat | 10/18/07 10:43 AM
Hi

Thanks for the great post. but can you or someone else out there please show how to do this with PHP. i don't know any cold fusion and even though this is a great feature i am unable to use it :(
# Posted By Olaf | 10/18/07 4:58 PM
This is very nice. i liked it.
I need to create the same in asp.net. i m using the UI suite called "componentArt" which has its own grid and callback trigger.
I m specially interested to know what happens on the server and how does the data get appended to exitsting records. Normally, asp.net grids render the whole tables with <table>...</table> instead of rows.
I appriciated your help in advance. Thanks
# Posted By Viraj Doshi | 1/4/08 9:13 PM
I made some change to this to pull from a database. Delete the Application.cfc file, you don't need it in this case.

make the following changes to the test.cfc to pull from a query.

<cfcomponent>

   <cfset variables.maxRows = 10 />
   <cffunction name="getRecords" access="remote" output="false" returntype="string">
      <cfargument name="startRow" required="true" />
      
      <cfset var returnStr = "" />
      
      <cfquery name="getdata" datasource="#application.datasource#">
         SELECT *
         FROM table
      </cfquery>
      
      <cfsavecontent variable="returnStr">
         <cfoutput query="getdata" startrow="#arguments.startRow#" maxrows="#variables.maxRows#">
         <li>ID: #variables.getdata.id[currentRow]# | Name: #variables.getdata.name[currentRow]#</li>
         </cfoutput>
      </cfsavecontent>
      <!--- simulate a long request --->
      <cfset sleep(1000) />
      <cfreturn returnStr />
   </cffunction>
</cfcomponent>
# Posted By Ryan Balchand | 6/2/09 3:40 PM

Calendar

Sun Mon Tue Wed Thu Fri Sat
   1234
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Subscribe

Enter your email address to subscribe to this blog.

Tags

actionscript ajax blogging cfsnippets coldfusion flash forms flex funny stuff javascript misc model-glue off topic personal project learn slidesix sql

Recent Comments

Chinese Birth Calendar Accuracy Test
mama to be said: ok so i will be 2 months shy of 18 when i have my baby. this calendar does not technically work for ... [More]

Fixing 'User Profile Service Failed The Logon' on Vista
Mike said: That fix worked although all i did was remove .bak and reset state to 0. User was able to log in to... [More]

Chinese Birth Calendar Accuracy Test
Melissa said: Wrong for my daughter, which it predicted to be a boy... we'll see for #2. Predicts a girl (maybe, f... [More]

Adding Auto Generated Code Downloads to BlogCFC
fweerw said: http://www.ibiblio.org/st... http://www.cambodia.ait.a...... [More]

Check Out The New SlideSix
Todd Sharp said: Thanks for the feedback Ben & Rachel! I'll keep it all in mind as I tweak things over the next ... [More]

RSS


adobe community experts

coldfusionbloggers

FullAsAGoog MXNA

Consumed By Feed-Squirrel.com