I use Ben Almans's jQuery BBQ and jQuery hashchange plugins on pagination links. Both work as expected in Opera and Firefox but do not in IE 8 (surprised, huh?). IE also works good with ajax, back button and hashchange, but fails when I clicking the reload button and shows raw ajax response instead of running it in previously loaded page.
So here is my ugly code and some explanations about features that Im trying to implement in my pagination:
1) Search engines friendly links (server responds html or js depending on javascript availability on client side).
2) Dynamically changeable url when JS is turned on (using the '#' symbol).
3) History and back button support.
4) Minimizing double requests (do not make ajax request if same content was loaded with html page).
JS:
$(function ($) {
if (ajax_init) {
$('.pagination a').live("click", function () {
$.bbq.pushState({page: $.deparam.querystring($(this).attr('href')).page});
return false;
});
$(window).bind("hashchange", function(e) {
var anchor = $.deparam.fragment().page;
var query = $.deparam.querystring().page;
if (ajax_load(anchor, query)) {
$(ajax_div).css('opacity', '0.4');
$(ajax_div + '-processing').removeClass('hidden');
$.ajax({
type: 'GET',
url: $.param.querystring('', {page: anchor}),
dataType: 'script',
cache: false
});
}
});
$(window).trigger('hashchange');
}
});
function ajax_load(anchor, query) {
if ((anchor && anchor !== query && !(!query && anchor == 1)) || $('#noscript').length < 1) {
return true;
}
else {
return false;
}
}
Template (Rails view):
<div id="products-container" >
<div id="products-processing" class="hidden">
<%= image_tag "spinner.gif" %>
</div>
<div id="products">
<div id="noscript">
<%= render "products_list.erb" %>
</div>
<script type="text/javascript">
var ajax_init = true;
var ajax_div = '#products';
var anchor = $.deparam.fragment().page;
var query = $.deparam.querystring().page;
if (!ajax_load(anchor, query)) {
url = anchor ? anchor : (query ? query : 1);
$.bbq.pushState({page: url});
}
else {
$('#noscript').hide();
$('#products-processing').removeClass('hidden');
}
</script>
</div>
<div id="products-min-height"></div>
</div>
AJAX template (Rails js view):
$('#products').html('<%= escape_javascript(render "products_list") %>').css('opacity', '1');
UPD: IE doesnt send request type header (or Rails cant determine it) while refreshing. So Rails generates JS view instead of HTML. Solved by:
respond_to do |format|
request.format.js? ? (format.js {render :index}) : (format.html {render :index})
end
Is there a better solution?
IE appears to ask for "*/*" on refresh, and rails seems to think javascript is a better response than html. Because refreshing should only happen for html, telling rails that "*/*" means html fixes this issue:
before_filter :set_request_type
...
protected
def set_request_type
request.format = :html if request.format == "*/*"
end