Easily build powerful client-side AJAX paging, using jQuery
AJAX, ASP.NET, JavaScript, jQuery, UI By Dave Ward. Updated October 15, 2008Note: This post is part of a long-running series of posts covering the union of jQuery and ASP.NET: jQuery for the ASP.NET Developer.
Topics in this series range all the way from using jQuery to enhance UpdatePanels to using jQuery up to completely manage rendering and interaction in the browser with ASP.NET only acting as a backend API. If the post you're viewing now is something that interests you, be sure to check out the rest of the posts in this series.

When I suggest that developers consider using web services and a more client-centric approach to solve their UpdatePanel performance problems, the lack of paging is often their first objection.
Conventional ASP.NET wisdom seems to hold that the GridView/UpdatePanel combo is king when asynchronously paging through a data source. If you’ll give me a few minutes of your time, I’d like to challenge that notion!
In this post, I’m going to show you how to implement great client-side paging, using jQuery and ASP.NET AJAX. I’ll be building on foundation laid in two previous posts: Use jQuery and ASP.NET AJAX to build a client side Repeater and How to easily enhance your existing tables with simple CSS. If you haven’t yet, I recommend that you read those posts first, so that we’re all on the same page.
This post will be a bit longer than those were, but I’ve tried to divide the ordeal into granular steps that break the monotony as much as possible:
- Setting up a page method to retrieve individual pages of data.
- Using jQuery to consume that page method and render its result.
- Adding progress indication during the initial load.
- Adding the basic HTML paging controls.
- Wiring up event handlers for the paging controls.
- Implementing the paging functions that those handlers call.
- Adding progress indication during the paging operations.
- Using a page method to dynamically determine the size of the data source.
Retrieving a particular “page” of data
Our existing GetFeedBurnerItems page method accepts a PageSize parameter, which specifies how many items it should return. To implement paging, we need to add a new parameter: Page.
This second argument will specify which page items will be returned from.
[WebMethod] public static IEnumerable GetFeedburnerItems(int PageSize, int Page) { XDocument feedXML = XDocument.Load("http://feeds.encosia.com/Encosia"); var feeds = from feed in feedXML.Descendants("item") select new { Date = DateTime.Parse(feed.Element("pubDate").Value) .ToShortDateString(), Title = feed.Element("title").Value, Link = feed.Element("link").Value, Description = feed.Element("description").Value, }; return feeds.Skip((Page - 1) * PageSize).Take(PageSize); }
Using the supplied Page argument, our service uses IQueryable’s Skip() extension method to return the correct page of results.
The purpose of the subtraction is to make the Page argument 1-based. I don’t think the notion of a “page 0″ makes much sense in this scenario, so I prefer they start at 1.
Consuming the service and rendering the result
Now that our service is modified to provide paged results, we can consume the first page of results similar to how we did in the previous examples.
// Set this to any integer you like. 5-7 works well // with the FeedBurner data source. var pageSize = 5; $(document).ready(function() { // Display the first page of results initially. DisplayRSSTable(1); }); function DisplayRSSTable(page) { $.ajax({ type: "POST", url: "Default.aspx/GetFeedBurnerItems", data: "{'PageSize':'" + pageSize + "', 'Page':'" + page + "'}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(msg) { // Render the resulting data, via template. ApplyTemplate(msg); } }); } function ApplyTemplate(msg) { // Changed the template extension from .tpl to .htm, // to avoid the request being blocked by some IIS installs. $('#Container').setTemplateURL('RSSTable.htm', null, { filter_data: false }); $('#Container').processTemplate(msg); }
Since we’ll be calling the page method from other parts of the code, it made sense to refactor that functionality into a separate function: DisplayRSSTable.
Other than that, this is basically the same code that you’ve seen in the previous jQuery templating examples.
Adding initial progress indication on page load
FeedBurner is a great service, but tends to be a bit slow. Due to that latency on the response, the initial page often takes a few seconds to render. This has prompted several of you to ask about adding progress indication, which is a great idea.
There are many perfectly legitimate ways of accomplishing this, but I want to focus on minimizing the harshness of the transition between progress indication and content display. Jumping from a simple loading indicator to a full table is jarring.
One way to smooth that transition is to use a structure very similar to the final content’s template:
<div id="Container"> <table id="RSSTable" cellspacing="0"> <thead> <tr> <th></th> </tr> </thead> <tbody> <td class="loading"></td> </tbody> </table> </div>
The .loading CSS class is defined as follows:
table tbody .loading { /* Since the table may be empty, set a decent default height. */ height: 350px; /* Center an animated progress indicator over the table body. */ background-image: url(images/progress-indicator.gif); background-position: center center; background-repeat: no-repeat; }
The end result is an empty table, with a centered progress indicator inside its single 350px tall body cell.
Adding paging controls to the HTML template
Now that the first page of results is coming through smoothly, we need to add a paging interface to get at the rest of the data. To keep this from running longer than a Steve Yegge post, let’s stick with a simple previous/next system.
Since it’s logically a part of the rendered template, I decided to add the paging controls to the template itself:
<table id="RSSTable" cellspacing="0"> <thead> <tr> <th width="80">Date</th> <th>Title / Excerpt</th> </tr> </thead> <tbody> {#foreach $T.d as post} <tr> <td rowspan="2">{$T.post.Date}</td> <td><a href="{$T.post.Link}">{$T.post.Title}</a></td> </tr> <tr> <td>{$T.post.Description}</td> </tr> {#/for} </tbody> </table> <a id="PrevPage" class="paging">Previous Page</a> <a id="NextPage" class="paging">Next Page</a>
This template is very similar to the template that was used in the past two posts. The important changes are:
- The post title and excerpt are rearranged to be vertically oriented.
- The date column is fixed width, to maintain consistent column widths.
- Of course, the paging controls are added to the bottom of the table.
After implementing these changes, our rendered table is shaping up nicely:

Initializing the paging interface elements
Now that we’ve got the template rendering those anchor tags, the next step is to add functionality to make them do something:
// Initialize this and store globally for tracking state. var currentPage = 1; // The feed has 15 items, and we're displaying 5 per page. var lastPage = 3; function UpdatePaging() { // If we're not on the first page, enable the "Previous" link. if (currentPage != 1) { $('#PrevPage').attr('href', '#'); $('#PrevPage').click(PrevPage); } // If we're not on the last page, enable the "Next" link. if (currentPage != lastPage) { $('#NextPage').attr('href', '#'); $('#NextPage').click(NextPage); } }
UpdatePaging adds an href attribute of # to one or both of the paging anchor tags, thereby making them active links. This is primarily to give your users a good UI hint that they can click the links. The anchor’s actual navigation functionality won’t be needed.
.click() is jQuery’s way of attaching click handlers to elements. In this case, we’re wiring up a couple of functions that will handle the actual task of changing pages.
Putting it together, DisplayRSSTable needs to be updated to call UpdatePaging immediately after every template rendering:
function DisplayRSSTable(page) { $.ajax({ type: "POST", url: "Default.aspx/GetFeedBurnerItems", data: "{'PageSize':'" + pageSize + "', 'Page':'" + page + "'}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(msg) { // Render the resulting data, via template. ApplyTemplate(msg); // Wireup appropriate paging functionality. UpdatePaging(); } }); }
By doing this, we can be sure that the paging functionality always reflects the currently rendered page.
Making it all work: implementing the paging functions
Finally, it’s time to implement the PrevPage and NextPage functions that are responsible for actually changing pages.
This is where you really appreciate that the navigation links are generated as part of the template. That allows us to fire off a DisplayRSSTable and not worry about updating the navigation click handlers. Those updates to the paging controls will be automatically handled by the UpdatePaging after the requested page’s template renders.
function NextPage(evt) { // Prevent the browser from navigating needlessly to #. evt.preventDefault(); // Entertain the user while the previous page is loaded. DisplayProgressIndication(); // Load and render the next page of results, and // increment the current page number. DisplayRSSTable(++currentPage); } function PrevPage(evt) { // Prevent the browser from navigating needlessly to #. evt.preventDefault(); // Entertain the user while the previous page is loaded. DisplayProgressIndication(); // Load and render the previous page of results, and // decrement the current page number. DisplayRSSTable(--currentPage); }
The call to preventDefault cancels the browser’s navigation to #. It doesn’t interfere with the paging functionality to allow that navigation, but allowing it will unnecessarily send mixed signals to your users.
Using the currentPage global variable, we can use our original DisplayRSSTable function to request one page up or down from the current page.
Progress indication during paging requests
Since each page request takes a couple seconds to complete, it’s important to provide progress indication during that time. This can be implemented in the same way as the initial page load progress indication. We’ll even reuse the same .loading CSS class.
function DisplayProgressIndication() { // Hide both of the paging controls, // to avoid click-happy users. $('.paging').hide(); // Clean up our event handlers, to avoid memory leaks. $('.paging').unbind(); // Store the height of the content area of the table. var height = $('#RSSTable tbody').height(); // Replace the entire content area with a single row/cell. $('#RSSTable tbody').html('<tr><td colspan="2"></td></tr>'); // Set that row's height to be the same as previous. $('#RSSTable tbody tr').height(height); // Add our centered progress indicator animation to it. $('#RSSTable tbody td').addClass('loading'); }
This function does the following:
- Hides the paging controls and clears any event handlers on them.
- Determines the current height of the table’s content area.
- Drops the entire content area and replaces it with a single cell.
- Sets that cell’s containing row’s height to the previously determined value.
- Add the .loading class to that cell, so that a progress animation appears centered over the same areas that the content used to occupy.
Dynamically determine the size of our data
So far, we’ve been working under the assumption that there will always be 15 elements in the data source and that it will never change at run time. While this might be a workable assumption for my RSS feed, it certainly would not be for most other data sources.
We need to dynamically detect the size of our data.
The first step in implementing this functionality is to interrogate our data source on the server side. This page method will return the total number of items in the feed:
[WebMethod] public static int GetFeedBurnerItemCount() { XDocument feedXML = XDocument.Load("http://feeds.encosia.com/Encosia"); return feedXML.Descendants("item").Count(); }
Using the $.ajax() syntax that I have previously described, we can request the count of data items from our new page method. Using that and the global pageSize variable, it’s easy to determine the lastPage:
// Initialize this to 1, so that "Next" is disabled until // GetItemCount returns and we know there's a second page. var lastPage = 1; function GetRSSItemCount() { $.ajax({ type: "POST", url: "Default.aspx/GetFeedBurnerItemCount", data: "{}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(msg) { // msg.d will contain the total number of items. // Divide and round up to find total number of pages. lastPage = Math.ceil(msg.d / pageSize); // Wireup appropriate paging functionality. UpdatePaging(); } }); }
Now that we’re doing things more correctly, it makes more sense to initialize the lastPage variable at one. Until we’ve called our new GetFeedBurnerItemCount method and know the size of the data, we have no reason to assume there is more than one page of data.
To put this in action, we can add it to the $(document).ready handler:
$(document).ready(function() { // On page load, display the first page of results. DisplayRSSTable(1); // Simultaneously, begin loading the total item count. GetRSSItemCount(); });
The end result is that both paging controls will originally be in a disabled state, until GetRSSItemCount is able to verify that at least (pageSize + 1) items exist in the data source.
If you’re implementing paging against a relatively static data source, like my RSS feed, there’s no need to add this functionality. However, I’m providing the added flexibility in hopes that it will make this more easily adaptable to your particular situation.
Conclusion
This has been a long post, but hopefully each individual part was digestible. As with most things, deconstructing the problem into manageable pieces makes the overall task easy. A few more thoughts include:
Error Handling. If you use this code, please do add error and timeout handling to your service calls. For the sake of brevity and clarity, I don’t address error handling in posts not specifically about that topic. However, you should never do that in production.
Caching. Depending on your data source, you may want to make use of the Cache class in your page method. For instance, this RSS example would benefit massively from Caching. However, you may just as likely be paging into a huge data source, in which case it wouldn’t make any sense to Cache.
Do keep it in mind though. With caching, paging through this example is almost instantaneous after the initial load.
That’s it. I hope you found this helpful.
Download the source
Similar posts
What do you think?
I appreciate all of your comments, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to another comment, use the threading feature by clicking "Reply to this comment" before submitting your own.
19 Mentions Elsewhere
- 2008 August 21 - Links for today « My (almost) Daily Links
- Easily build powerful client-side AJAX paging, using jQuery « Rich Internet Applications
- Dew Drop - August 21, 2008 | Alvin Ashcraft's Morning Dew
- 50 Excellent AJAX Tutorials | Tutorials | Smashing Magazine
- 50 Excellent AJAX Tutorials | POLPDESIGN
- 50+ Great Ajax Tutorial | Tech User, Blogger and Designers References
- Base Blog » Client site Ajax Paging using JQuery
- 50 Excellent AJAX Tutorials | How2Pc
- Best Ajax Tutorials and Dynamic Solution for PHP ,Asp.net.Ruby On Rrails | Click On Tech
- 150 AJAX Tutorials » TemplateLite.com
- Best of 158 Ajax Framework,JavaScript Libraries and Toolkit Tutorials | Click On Tech
- Ajax Frameworks,JavaScript Libraries and Toolkit Tutorials | Dev Techie
- 50 Excellent AJAX Tutorials | 9Tricks.Com - Tips - Tricks - Tutorials
- AJAX Sample – Others- 阿維實驗室
- 15 Very Useful Hand-Picked AJAX Tutorial - Ntt.cc
- AJAX | Hello Tea
- Geek is a Lift-Style. » 50 Excellent AJAX Tutorials
- Visoft, Inc. Blogs | Microsoft Announces Visual Studio 2010 and .NET 4.0
- Simple Asp.net Jquery Ajax paging « .notes



I’m really liking the ‘grass roots’ movement of jQuery-ASP.NET-LINQ for the three tiers of web development, and your blog has been (IMO) one of the driving forces behind that. Keep up the great work Dave!
Awesome! :D
I’ve been working on a pure HTML/JavaScript web site (no server side processing) that consumes remote web services. Your blog has been very helpful showing me the way with .Net Web Services and jQuery. Thank you!
Why introduce asp.net AJAX? This could have been done by just using jQuery and an .ashx page.
Since the JSON serialized services are built into ASP.NET 3.5 anyway, I don’t see much harm in using a mechanism that’s more familiar to most. Not having to think about the JSON serialization removes some friction from the ordeal.
Hi Dave,
Very nice example !
Where can we find more info on the code generation
language used in the html template
#foreach etc.
LA Guy
It’s called jTemplates. They have in-depth documentation on all of its functionality at this site: http://jtemplates.tpython.com/
Thanks a lot for the post Dave! Very informative! Would anyone know how to simulate ASP.NET Webservices in PHP? I’m trying to achieve the same result but using PHP, instead of asp.net.
Several PHP libraries to serialize JSON are listed here: http://www.json.org/
You could use one of those to create a PHP script that acted as the “service”. Keep in mind that if you serialize it into a flat JSON array yourself, anywhere you see me use msg.d, you’d use msg (without the .d).
Cool, thanks Dave! I will give this a try.
I had a feeling this was what we were building to here. Coincidentally I’ve been doing a very similar thing here at work, and ever since I read the first post about jQuery and Server-Side controls, I’ve been using it for my needs. Originally I was using the tablesorter plugin for my project, but as the amount of things submitted to our SQL Database grew, I recently made the decision that I’d have to do serverside paging instead, simply because of how much it killed our performance… that and we became longer than the allowed length of a JSON serialized string. Haha.
So live and learn I guess.
Hello Dave,
Another great post as usual. You really started it, at least for me, abandoning too heavy asp.net ajax library for the sake of simplicity and level of control in jQuery.
I’m looking forward to many more good posts from you, and asp.net ajax client side only library from MS, they promised.
Great writeup.
A very important consideration is the fact that we completely lose SEO on the dynamically loaded data.
Not necessarily… We can create real urls for next and prev, like /products.aspx?p=3&s=10. Then if JS is enabled we jump in with jQery and prevent clicks, and if there is no JS (e.g. bot visits site) we leave it as is. Yes, it means making server side paging as well, but that is the only way to do it right.
That’s right, Milan. I specifically chose the <a> tag so that it could be improved along those lines in the future.
Though, at that point, it would probably make sense to use the user control rendering method from this post: http://encosia.com/2008/02/05/boost-aspnet-performance-with-deferred-content-loading/
That way, you’d be using the same “template” on client and server side. The paging would still work similarly though, passing a parameter to the user control rendering service.
Hi Dave,
I am using the following code
$(“#btnSaveQry”).click(function (e) {
var query = $(“#txtQueryBox”).val();
$.ajax({
type: “POST”,
url: “SteamTools.asmx/getRecord”,
data: “{‘strSqlQuery’: ‘” + query + “‘}”,
contentType: “application/json; charset=utf-8″,
dataType: “json”,
success: function (msg) {
if (msg.d != “”) {
var again = true;
while (again == true) {
var answer = prompt(“Please enter a name for your query”, “”);
if ($.trim(answer) != “”) {
$(“#myHiddenElement”).val(answer);
again = false;
}
else {
if (answer == null) {
return false;
}
alert(“Query name required”);
again = true;
}
}
return true;
}
else {
alert(“Invalid query. Please make sure the query being saved is a valid SQL query”);
e.preventDefault();
return false;
}
},
error: function () {
alert(“Invalid query. Please make sure the query being saved is a valid SQL query”);
e.preventDefault();
return false;
}
});
});
Protected Sub btnSaveQry_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSaveQry.Click
If Session.Item(“Pin:”) Is Nothing Then
Try
Dim fullID As String = HttpContext.Current.User.Identity.Name
fullID = fullID.Substring(fullID.LastIndexOf(“\”) + 1)
Session.Add(“Pin:”, fullID)
Catch
ClientScript.RegisterStartupScript(Me.GetType(), “noSession”, SteamTools.MBox( _
“Session timed out. Please go back to the STEAM page and click the ‘Admin’ button.”))
Response.Redirect(“default.aspx”)
Return
End Try
End If
Try
‘check if the name has already been used by this user (can’t have duplicate names by the same user)
Dim dr As SqlDataReader = SteamDB.getRecordSet(“SELECT Query_Name FROM Steam_Queries WHERE PIN=” & Session.Item(“Pin:”), pubStrReqConn)
While dr.Read
If SteamTools.DecodeQuotes(dr.Item(“Query_Name”)).ToUpper = myHiddenElement.Value.ToUpper Then
ClientScript.RegisterStartupScript(Me.GetType(), “sameQryName”, SteamTools.MBox( _
“You already have a query saved under this name. Please choose a different name”))
dr.Close()
Return
End If
End While
dr.Close()
SteamDB.saveRecord(“INSERT INTO Steam_Queries (PIN,Query_Name,Query) VALUES (‘” & Session.Item(“Pin:”) & “‘,’” & SteamTools.EncodeQuotes(myHiddenElement.Value) & “‘,’” & SteamTools.EncodeQuotes(txtQueryBox.Text) & “‘)”, pubStrReqConn)
SteamDB.addToLog(Session.Item(“Pin:”), False, “Saved a query”, pubStrReqConn)
ClientScript.RegisterStartupScript(Me.GetType(), “savedQry”, SteamTools.MBox( _
“Query saved successfully”))
fillQueryList()
btnQry_Click(sender, e)
Catch ex As SqlException
ClientScript.RegisterStartupScript(Me.GetType(), “errorQry”, SteamTools.MBox( _
“Error saving query”))
SteamDB.addToLog(Session.Item(“Pin:”), True, “Error saving query. ” & ex.Message, pubStrReqConn)
Return
End Try
End Sub
The issue is the server click is executed first than teh success function of ajax call. How to execute the ajax Success function and then the server click event.
Thanks,
Dave, do web services in ASP.NET utilize any sort of caching? I’m wondering, because if you have a lot of page requests, wouldn’t that hammer RSS feed server?. I mean if you have, lets say 100 hits a minute, wouldn’t your webservice request 100 rss requests as well? I’m relatively new to asp.net and not sure if that’s a false logic. If i’m correct, what would u do to implement some sort of caching.
Thanks a lot!
By default, there’s no caching.
For something like this example, I would definitely recommend caching the data on the server side. In other cases, the entire dataset might be too large for caching to make sense.
Hey Dave, great post. I don’t actually use jquery or templating of any kind, but your tips on paging were very valuable. Much simpler than the ways I was thinking of handling paging for the application I’m working on :).
This is a great article. Just what I was looking for.
I’m having serious performance issues with UpdatePanels right now. I’ve been trying to eliminate as much viewstate as possible, but I still get hit when all my user controls need to go through their event lifecycle again.
does google or any search engine indexes this kind of pages?
No.
Hi Dave,
I just started using jQuery for ajax/javascript stuff on my websites, and I find your articles on this matter highly interesting. I have tryed to make a webmethod that can pull some data form a database and make json string out of it, but I’m not quite there yet caould you help me on this matter ?
The webmethod:
[WebMethod]
public static string LoadRoles()
{
RoleHandler roleManager = new RoleHandler();
List roles = roleManager.GetRoles();
StringBuilder html = new StringBuilder();
int c = 1;
html.Append(“[");
foreach (Role role in roles)
{
html.Append("{\"id\":\"" + role.Id + "\",\"rolename\":\"" + role.RoleName + "\"}");
if (c != 4)
{
html.Append(",");
}
c = c + 1;
}
html.Append("]“);
return html.ToString();
}
As I’m new to json i don’t know if this is the right way of doing it, but it sure does not work.
I must have been sleeping, i found that it was quite simple and ended up with this :
[WebMethod]
public static IEnumerable LoadRoles(int PageSize, int Page)
{
RoleHandler roleManager = new RoleHandler();
List roles = roleManager.GetRoles();
return roles.Skip((Page – 1) * PageSize).Take(PageSize);
}
And now every thing is working just fine ;o)
Then i just need to find a way to format my dates.
If you want to format the dates on the server side, you could iterate through the collection that GetRoles() returns and select a subset of fields through an anonymous type (as I do in these RSS examples). Then, you would be free to format the dates as you select them.
Something like:
And that was exactly what i did and got it working ;o)
Can you tell me how to emplement event handlers to links in the template generated data. I have tryed with the following, but with no luck :
function addClickHandlers() {
$(“a.remote”, this).click(function(e) {
e.preventDefault;
$(“#RSSTable”).load(this.href, addClickHandlers);
alert(‘Testing event handler’);
});
}
$(document).ready(addClickHandlers);
I don’t know it is possible to do it like this when the template is in seperat file. But as i have understand jQuery i need to set the event handlers this way due to memory leak issues.
preventDefault should be called as a method:
It’s probably throwing a JavaScript error on that line and not making it to the alert.
Hi Dave,
That is right, but I do not get an error without the () and it still does not work after I added it.
But do you think that it will work at all when the template is placed in seperate file ?
Sorry, I missed that you were calling that in document.ready. You should call your addClickHandlers function after the template is rendered, similar to how I call UpdatePaging in the example above.
To add click handlers to the template, before it’s rendered, you’d have to edit the template to include onclick attributes.
After getting everything working thanks to your help, i would like to know if this could be made as a jQuery plugin ?
You can make basically any jQuery code into a jQuery plugin. I’m not sure how much you’d really in this case though, since a jQuery plugin can’t help with the template or the web service itself.
I know that i can’t add the template and web service, but if I had a set of options like :
jQuery.fn.test = function(settings){
settings = jQuery.extend({
getRecords : “page.aspx/method”,
getRecordCount : “page.aspx/method”,
getTemplateUrl : “template.html”
}, settings);
};
then i can set the options in $(document).ready(function(). This is taken from the docs at jQuery, but what i don’t understand is how to add the functions to the plugin so that it all works when i load the template like :
$(“Container”).test(options . . .);
You find find this post by Matt Berseth useful.
The funny thing with your examples is that .NET is the smallest part. You can even forget about it and everything is javascript throught jQuery.
You’re right.
As long as you can get JSON from it without too much trouble, you could definitely do this with any platform/language. ASP.NET just happens to be my platform of choice right now.
Dave, a blog post from Rick Strahl led me here. Your blog is an inspiring discovery for me. I have a question about making this code download more reusable.
I am trying to add the code to a usercontrol. How may I take your example, drop the files in the “~/usercontrols/” directory and be able to add this user control to any page?
I love the templating with jquery idea, and I am looking to integrate it with aspnet themes.
Your main obstacle will be the page method. Page methods only work with ASPX pages. You can accomplish the same thing with an ASMX or WCF web service though.
Other than that, it should just be a matter of rearranging files and changing path references.
Great web site … why don’t you have live demos for each article?
thanks,
Mark
Thanks.
No live demos because the site runs on Linux. I’ll set Mono up someday, but just haven’t had the time to fool with it yet.
I assign an id to my td inside the template. But I am unable to get the value or set the background color for td id=”CalendarEvent_Title”.
These 2 lines of codes do not work:
var thedate = $(‘#CalendarEvent_EventDate’).val();
$(‘#CalendarEvent_EventDate’).css(‘background’, ‘yellow’)
function btnTestClick(evt)
{
var myDate = new Date()
var todayDate = myDate.getMonth() + ‘/’ + myDate.getDate() + ‘/’ + myDate.getFullYear();
var thedate = $(‘#CalendarEvent_EventDate’).val();
if (todayDate == thedate) {
$(‘#CalendarEvent_WidgetTitle’).css(‘background’, ‘yellow’)
$(‘#CalendarEvent_EventDate’).css(‘background’, ‘yellow’)
};
};
{#foreach $T.d as post}
{$T.post.StartDate} – {$T.post.EndDate}
{$T.post.Title}
{$T.post.Description}
{#/for}
Dave,
Not sure if the thread dead already…
I just don’t know where to write it – fell free to move it to another thread if you like.
Anyway, I was wondering, would it make any sense to return XML to a client and apply XSLT to make HTML.
All client side JS formatting trick are good, but seemed wrong in general.
Which one is more light-weighted: JS or XSLT formatting?
Besides, we can easily host numerous XSLT for same XML data (as well as numerous JS ;-)
But with XSLT approach you can delegate XML to HTML formatting to a designer, while with JS it’ll be a programmer burden most likely.
What do ya think?
I think XSLT is a great templating solution, but just couldn’t find widespread adoption because it’s complicated for a lot of people to understand. Maybe if there were better tooling more commonly available.
Unfortunately, it’s probably too late to revive it at this point. Peoples’ opinions of technologies are set early, and then they rarely revisit them objectively after that.
It’s really a shame too, because XSLT is very fast compared to other methods (including this one).
I do remember “old good time” when we use struts (good old MVC stuff ;-) to make web sites.
Get data from Oracle / M$ SQL, convert to XML – neither one can feed you XML directly at that time.
We use XSLT to produce HTML from XML _on server_.
The idea was to move this burden to a client one day.
Basically _decouple_ presentation/view from business logic.
A web designer were able to update XSLT and we don’t need to change a single line of code.
And he can tune it easily without any programmer help.
Sigh… Long time.
I _actually_ thought, M$ will come VS add-on one day to generate/edit/debug XSLT transformations, as they widely adopt XML everywhere.
Never happens…
Too many mistakes… (On my side to chose the right approach)
> XSLT… just couldn’t find widespread adoption because it’s complicated for a lot of people to understand.
Gee, I don’t think jQuery is any easier.
No doubt, it’s more flexible, but we are talking about “right tool for right job”, right?
Or people (programmer && designers) get smarter over last decade or so? ;-)
Hi Dave,
I used your way to generate inner pages to be loaded inside JQuery tab panels, pages are working very nice when runing but not when navigating with tab panel.
please review this issue.
I don’t understand the question.
great article
however i want to know how can we implement it by displaying page numbers instead of next and previous ?
You’d need to add some logic on the server-side that would divide the total number of items by the page size and return that number of pages to the client-side. Then just render a link for each page and wire-up an event on them to call DisplayRSSTable with the appropriate page number.
What about browser history, Dave? What would be involved in inserting browser history points so that clicking the back button in the browser returns the user to the previous page of data?
This jQuery plugin allows you to do that without too much trouble: http://stilbuero.de/jquery/history/
i have a complex html which i render and display in div after ajax call, i want to know how jquery never run on the rendered html
how can i attach jquery functions on the rendered data ?
If you’re using jQuery 1.3+, the easiest way to handle that is to use the LiveQuery functionality. For example, this click event handler would work on any element matching the selector, regardless of when it’s added to the DOM:
Hi Dave,
It was the nice article to learn. However i have one thing can we do sorting also? Did you wrote somewhere about sorting like you did paging?
I haven’t written about that specifically.
If you want client-side paging, check out the TableSorter plugin.
For server-side paging, you would add click handlers to the thead cells, add a “sort order” parameter to the service method, and update the service method’s LINQ statement to order the result before applying the paging.
You also might be interested in plugins like jqGrid and DataTables.
Hi Dave,
I have below doubts:
1) If i have 10 different pages and each contains one different grid then do i need to prepare 10 templates (.htm) files? while loading the htm file is not create one more hit to the server for getting this htm file?
2) For each table we have to write our own sorting and paging?
3) plugins then which is the good plugin that will work as GridView works? there are number of names DataTables, jqGrid, TableSorter … which one is standard faithful and applicable.
currently, i am doing paging as you described and regarding sorting i am thinking to do as you advised by adding events to thead cells of the table. But i found that for each template i have to do sorting and paging then it is more manual and error prone also will create big js file.
Please advice.
Hey,
Using this solution, I’m returning data from Oracle that contains something like this: “four score and seven years ago..” I’m expecting the seven to be bold, however, I don’t see anything. Am I missing something? Is there a contraint that prevents this?
The
{ filter_data: false }option to processTemplateURL (as seen in the example above) prevents jTemplates from filtering HTML on the client-side. Assuming your code has that option set, it sounds like your HTML is being filtered before it gets to the browser. Have you looked in Firebug to be sure it’s coming back how you expected it to in the response?Hi Dave
This is just an amazing article – I wonder why I first came across it now. I am new to jQuery, so do you have any idea of how to add paging numbers – e.g. something like:
Previous 1 2 3 4 5 6 7 8 9 10 … Next
in C# I would do something like this:
rowCount = rowCount / pageSize + (rowCount % pageSize != 0 ? 1 : 0);
I’ve assumed a fixed number of pages here for simplicity. Assuming you get that data to the client-side somehow, you might do something like this to add numbered links under the table:
how i user paging like this << >>
I tried this on my own code and I’m using jsRender. I have tried to implement the paging as shown but I have a problem where the page doubles in value and calls the GetResults web method more than once. For example if the page is set to 2 it will double it to 4 and call the web method 4 times. The next time I press the Next link it will do it 8 times. I don’t understand what I’m doing wrong. Could it be because I’m using jsRender??
Any help appreciated.
I wouldn’t expect JsRender itself to cause an issue like that. It’s fairly similar to jQuery Templates and jTemplates overall, with mostly just syntactical differences.
If I had to guess without seeing code, I think it sounds like you’re attaching duplicated events to the “Next” button during each paging operation, which explains that 1, 2, 4, 8 progression. If you’re using .live(), .delegate(), or the corresponding forms of .on(), you don’t need to re-bind those events again when the page changes.