Chinmay Nagrale Chinmay Nagrale - 7 days ago 5
Ajax Question

Using History.js to store data and then use data for ajax loading for pages

I'm working on a completely ajaxified website. The following is the code for ajax loading for pages. I'm trying to use history.js into this code, but after incorporating the the code, it only changes the url but not the content. What I trying to do is, when the state changes, data which is stored in the state and then use ajax to load the page.

Before history.js:

$(document).ready(function(){
$(".navButton").click(function() {
$("#main").fadeOut();
var a = $(this).attr('id');
$.post('functions/ajax.php?id='+a, {}, function(response){
//$('#container').html(unescape(response));
///$('#container').fadeIn();
setTimeout("finishAjax('main', '"+escape(response)+"')", 400);
});
});
});
function finishAjax(id, response){
$('#'+id).html(unescape(response));
$('#'+id).fadeIn();
}


After history.js:

$(function() {
ajaxifyLinks();
$(".navButton").click(function() {
$("#main").fadeOut();
var a = $(this).attr('id');
$.post('functions/ajax.php?id='+a, {}, function(response){
//$('#container').html(unescape(response));
///$('#container').fadeIn();
setTimeout("finishAjax('main', '"+escape(response)+"')", 400);
});
});
});
function ajaxifyLinks() {
$(".navButton").click(function() {
var a = $(this).attr('id');
var name = $(this).attr('name');
History.pushState(a, document.title, '?action='+name);
return false;
});
}
History.Adapter.bind(window,'statechange',function() {
var State = History.getState();
var data = State.data;
$("#main").fadeOut();
$.post('functions/ajax.php?id='+data, {}, function(response){
//$('#container').html(unescape(response));
///$('#container').fadeIn();
setTimeout("finishAjax('main', '"+escape(response)+"')", 400);
});
ajaxifyLinks();
});
function finishAjax(id, response){
$('#'+id).html(unescape(response));
$('#'+id).fadeIn();
}

Answer

Based on the fiddle that you provided in the comments on your question, it appears that this issue was caused by the call to finishAjax(). I have updated your fiddle with some minor changes, which should solve the problem. The changes are as follows:

  • Removed the string concatenation ('"+escape(response)+"' ) from the response parameter of finishAjax(). This concatenation, when combined with the following change, results in the escaped string being surrounded by single quotes. When the parameter is later unescaped, it attempts to unescape the single quotes, too.

Theoretically, you shouldn't even need to escape/unescape the response variable, as the variable's value will be passed.

  • Switched the call to finishAjax() from within setTimeout() such that it is a function, rather than a string. This is slightly more efficient, and may also make refactoring just that tiny bit easier (as it will appear in your IDE's 'find usage' functionality).

Hope this helps!

Edit:

There are a few other issues with your code, namely:

  • you have an uncaught reference error on Line 2 of npm.js. You will need to include either commonJS or requireJS, preferably commonJS, in your HTML's header, before you include npm.js. Or, even better, take a look at using Webpack, to compile your javascript into a single bundle file.

    If you haven't used Webpack before, have a look at this tutorial: https://github.com/AriaFallah/WebpackTutorial

  • You are passing an object as a GET parameter to ajax.php, where you need to pass a string. You can fix this by changing your code in History.Adapter.bind to the following. (NOTE: I used a snippet, as the code formatting with both the code tag and the double/triple back-ticks isn't working properly)

History.Adapter.bind('window', 'statechange', function() {
 var State = History.getState();
 var data  = State.data;
 $("#main").fadeOut();

 $.post('/functions/ajax.php', { id: data }, function(response) {
   setTimeout(function() {
      finishAjax('main', escape(response);
      ajaxifyLinks();
    }), 400);
 });
});

I also noticed that sometimes the ajaxifyLinks() function was called before finishAjax() had been executed, due to the code not being invoked from within setTimeout(). I've restructured things slightly to fix this.

In addition to this, upon inspection, your State.data object is actually an empty object, as shown below. You may want to use a different property in the State object, or ensure that you add the required data to State.data.

Chrome Developer Console - Inspection

I would strongly recommend having a look at the Firebug (if you use Firefox) or the Chrome Developer Console, if you use Chrome. You can add a breakpoint to the code you want to inspect, and when you interact with your site, it will stop execution when it hits that breakpoint, allowing you to see the value of each variable, etc (as above).

Also, it makes some of these issues very easy to spot. For example, the following image shows how I found the parameter issue. Notice in the red squares that the id is [object%20object] (%20 is URI encoding for 'space'), whereas in the blue it is a numeric id:

enter image description here

Hopefully this helps.