Solution: Scripts not working after Ajax replaces part of page
Adam Cook Jan 9, 2013 9:19 PMI'm far from an expert at js and jQuery, so I welcome collaboration and corrections on this solution. This is all from the context of a catalog's large product view when using ajax to switch between grouped products.
First, the issue:
- BC updates the product information via an ajax call when you click the 'add to cart' button or make selections between product groupings.
- When BC does this, it entirely reloads page_content.html. The net result: all the script bindings that were attached to those tags are wiped out.
- The scripts are never rebound to the tags because that initially occurs when the DOM is being created. Content changes via an ajax call don't recreate the DOM.
Possible solutions:
- Hardcode the affected scripts inside page_content.html. Don't just link a script file to it. It has to be hardcoded. This is not recommended, as it is bad coding practice to place scripts inline with our html.
- Avoid the use of scripts in that area (good luck).
- Use delegation with .on() to rebind. I believe this is the best option, and it's the one I am going to demonstrate.
To avoid inline scripts, I like using an external script.js file. It keeps my document clean from script clutter and it's easier to manage my scripts. Also, I want a solution I can implement one time, in one place, instead of with every situation I encounter. Below is an example of how my scripts are organized. The areas in bold are the specific solution.
jQuery.noConflict();
function scriptlist() {
var $ = jQuery;
var Engine = {
utils : {
functionName : function(){
// Do stuff in here
},
functionName2 : function(){
// do something else
}
},
ui : {
functionName : function(){
// Do stuff in here
},
functionName2 : function(){
// do something else
}
}
};
if ( $(element).length ) { Engine.utils.functionName(); }
if ( $(element2).length ) { Engine.utils.functionName2(); }
if ( $(element3).length ) { Engine.ui.functionName(); }
if ( $(element4).length ) { Engine.ui.functionName2(); }
};
jQuery('body').on('click.productSubmitInput', function(){
jQuery.ready(scriptlist());
});
scriptlist();
The key here was the use of the .on() jQuery method. Here is how it works:
- I attached on() to the body element on the page with jQuery('body').on()
- It's attached to the body, because the body is outside of page_content.html and won't have it's binding removed during the ajax call. Events register all the way up their ancester elements on the page, so on() can pick up the event all the way up to the body.
- Told it to look for a certain event: 'click.productSubmitInput'
- When the event occurs, it should trigger ready() to refresh the DOM. jQuery.ready()
- and run my functions against it, thereby rebinding my document.



