Home >
Example of paginated content loaded via AJAX (2)
Yesterday I blogged about one way to handle paginated content loaded via AJAX. The concept was rather simple: Use AJAX to load content and support paging within the div used to load the content. This is handy for cases where a user is viewing one main page and would like to paginate throughout sub or related pages.
The reader who asked about this mentioned - and unfortunately I missed it - the ability to handle sorts as well. I decided to go ahead and look at how I could modify the scripts to support it. As before - please note this is just one way - and also note that the server side code was whipped up quickly and could be done much better. Ok, so with that out of that, let's talk about the sorting.
As with the last entry, I began working outside of AJAX completely. I had built a simple CFM file that paginated over 32 rows of fake data. I began working on that file first to ensure the sorting would work ok. I took my fake data and abstracted it a bit using a UDF. I also added simple sorting to it. Again, if you aren't a ColdFusion developer, you can just pretend this is written within your own language (just be sure to add 10-20 more lines of code ;).
<cffunction name="getData" returnType="query">
<cfargument name="sort" type="string">
<cfset var x = "">
<cfset var q = queryNew("id,body,posted,rating")>
<cfloop index="x" from="1" to="32">
<cfset queryAddRow(q)>
<cfset querySetCell(q, "id", x)>
<cfset querySetCell(q, "body", "This is review #x#")>
<cfset querySetCell(q, "posted", dateAdd("d", -1*x, now()))>
<cfset querySetCell(q, "rating", x*2)>
</cfloop>
<cfquery name="result" dbtype="query">
select *
from q
order by #arguments.sort#
</cfquery>
<cfreturn result>
</cffunction>
Next up I added a simple form to handle the sorting.
<cfparam name="url.sort" default="posted desc">
<cfset data = getData(url.sort)>
<form style="display:inline" onChange="this.submit()">
Sort by: <select name="sort">
<option value="posted desc" <cfif url.sort is "posted desc">selected</cfif>>Newest</option>
<option value="posted asc" <cfif url.sort is "posted asc">selected</cfif>>Oldest</option>
<option value="rating desc" <cfif url.sort is "rating desc">selected</cfif>>Highest Rated</option>
<option value="rating asc" <cfif url.sort is "rating asc">selected</cfif>>Lowest Rated</option>
</select>
</form><br/>
Again - it's a bit verbose but it was written up quickly. We allow for sorting by posted date and rating as well as supporting both ascending and descending sort. The form auto-posts when changed, and note I did not use a POST method. This will append the sort value to the query string. The next change was to append the corrent sort to pagination links:
<a href="reviews.cfm?start=#url.start-perpage#&sort=#urlEncodedFormat(url.sort)#">Previous</a>
<a href="reviews.cfm?start=#url.start+perpage#&sort=#urlEncodedFormat(url.sort)#">Next</a>
The next modification (and I'll post the entire zip at the end) is to the display of data. I added the posted and rating to the display so we can see the sort working.
<cfloop query="data" startrow="#url.start#" endrow="#min(url.start+perpage-1,data.recordCount)#">
<p>
Posted: #dateFormat(posted)#<br/>
Product rating (higher is better): #rating#
</p>
</cfloop>
I verified this worked in the browser. I could sort, paginate, resort, and it all worked fine. So next up was to return to the page with jQuery in it. Running the code there I noticed (as I expected) that any change to the sort reloaded the entire page. The auto-form submit was 'escaping' the div and causing the page to reload.
My fix for this was two-fold. First off I removed the auto-post from the form. Now changing the drop down field won't do a thing (especially with no submit button). Then in my jQuery document.ready block, I simply added:
$("#sort").live("change", function() {
$("#reviews").load("reviews.cfm?sort="+escape($(this).val()))
})
Booyah. I wish it took more lines of code to work. Really. Anyway, all I've done is add a second live binding to the application. This time it listens to the drop down. Notice I'm using live. Since the form reloads within the div I need a 'constant' connection that handles the reloading of the form. WHen the form changes, I simply grab out the sort value and append it to my URL. (I've set it up so that sorting always sends you back to page one.) That's it.
So I hope this is helpful. I enjoy building out these small demos in jQuery as it a) gives me practice and b) provides real-world jQuery examples. Are folks digging this style of post? If not - let me know. Ok, so now for the code. First up is the ColdFusion results.cfm page.
<cffunction name="getData" returnType="query">
<cfargument name="sort" type="string">
<cfset var x = "">
<cfset var q = queryNew("id,body,posted,rating")>
<cfloop index="x" from="1" to="32">
<cfset queryAddRow(q)>
<cfset querySetCell(q, "id", x)>
<cfset querySetCell(q, "body", "This is review #x#")>
<cfset querySetCell(q, "posted", dateAdd("d", -1*x, now()))>
<cfset querySetCell(q, "rating", x*2)>
</cfloop>
<cfquery name="result" dbtype="query">
select *
from q
order by #arguments.sort#
</cfquery>
<cfreturn result>
</cffunction>
<cfparam name="url.start" default="1">
<cfif url.start lt 1>
<cfset url.start = 1>
</cfif>
<cfparam name="url.sort" default="posted desc">
<!--- number of items per page --->
<cfset perpage = 10>
<cfset data = getData(url.sort)>
<form style="display:inline">
Sort by: <select name="sort" id="sort">
<option value="posted desc" <cfif url.sort is "posted desc">selected</cfif>>Newest</option>
<option value="posted asc" <cfif url.sort is "posted asc">selected</cfif>>Oldest</option>
<option value="rating desc" <cfif url.sort is "rating desc">selected</cfif>>Highest Rated</option>
<option value="rating asc" <cfif url.sort is "rating asc">selected</cfif>>Lowest Rated</option>
</select>
</form><br/>
<cfoutput>
Reviews #url.start# to #min(url.start+perpage-1,data.recordCount)#.<br/>
<cfif url.start gt 1>
<a href="reviews.cfm?start=#url.start-perpage#&sort=#urlEncodedFormat(url.sort)#">Previous</a>
<cfelse>
Previous
</cfif>
-
<cfif url.start+perpage lt data.recordCount>
<a href="reviews.cfm?start=#url.start+perpage#&sort=#urlEncodedFormat(url.sort)#">Next</a>
<cfelse>
Next
</cfif>
<cfloop query="data" startrow="#url.start#" endrow="#min(url.start+perpage-1,data.recordCount)#">
<p>
Posted: #dateFormat(posted)#<br/>
Product rating (higher is better): #rating#
</p>
</cfloop>
</cfoutput>
And here is the front end jQuery.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#reviews").load("reviews.cfm")
$("#reviews a").live("click",function() {
$("#reviews").load($(this).attr("href"))
return false
})
$("#sort").live("change", function() {
$("#reviews").load("reviews.cfm?sort="+escape($(this).val()))
})
})
</script>
<style>
#reviews {
background-color:#c0c0c0;
padding: 10px;
}
</style>
</head>
<body>
<h1>Product X</h1>
<p>
The best product you will ever buy!
</p>
<h2>Reviews</h2>
<div id="reviews"></div>




Facebook Application Development
Ray... thanks so much! You don't know how useful these last two posts have been. Keep up the great work and real-world demos of Cf + jQuery.
~Eric
Thanks for the info. If my data is less than 5000 rows, I normally sort on the client instead of the server. I hope the newer browser (compiled JS) will make this even a better option. I like Flex since sorting on the client is very fast.
Hi Ben,
I was wondering if you would be so kind to help me with a small ajax scripting problem.
Im working on a project and I would like to have two separate sets of navigation tabs that load content to two different DIV's independently through Ajax.
One, a horozontal set (primary) that loads content to a div situated in the header section of the page, and the other a vertical set of navigation tabs "secondary" that loads content into different div in the body section of the page.
Here is the project that im working on:
http://www.paulm.se/newsite
the .js is here: http://www.paulm.se/newsite/js.js
I'd be more than grateful for any assistance
Best regards
Paul
Hi Ben,
I was wondering if you would be so kind to help me with a small ajax scripting problem.
Im working on a project and I would like to have two separate sets of navigation tabs that load content to two different DIV's independently through Ajax.
One, a horozontal set (primary) that loads content to a div situated in the header section of the page, and the other a vertical set of navigation tabs "secondary" that loads content into different div in the body section of the page.
Here is the project that im working on:
http://www.paulm.se/newsite
the .js is here: http://www.paulm.se/newsite/js.js
I'd be more than grateful for any assistance
Best regards
Paul