How To Make Your Scripts Compatible With AJAX
AJAX Feature of SEO Layered Navigation Plus extension dynamically replaces parts of page HTML by removing HTML elements with old content and inserting elements with new content instead. Scripts attached to and working over removed elements stop working after old content is removed. Our extension does its best effort to attach same script to newly inserted HTML elements and indeed almost all dynamic behavior is working fine in newly inserted content.
Still in some cases manual effort is needed to make a script compatible with dynamic content replacement. This document discusses types of scripts, lists which kind of incomatibility is resolved automatically and provides practical guidance for maual resolution of incomatibilities which can't be manually resolved.
This document is highly technical. Magento JavaScript technical knowledge is expected.
Dynamic behavior on a page can be initialized and attached to HTML elements using several techniques:
- By using Magento declarative notation in HTML markup
- By initializing scripts imperatively either in
DOMContentLoaded
event handler (after all initial HTML is loaded) or directly in Javascript code (while loading/parsing/executing JavaScript tags or files).
Magento JavaScript initialization is described in detail here:
http://devdocs.magento.com/guides/v2.1/javascript-dev-guide/javascript/js_init.html
Scripts Initialized Via Magento Declarative Notation
With declarative notation scripts are initially attached to HTML elements with either of 2 following syntaxes:
via
data-mage-init
element attribute:<nav data-mage-init='{ "<component_name>": {...} }'></nav>
via
<script>
tags oftext/x-magento-init
type:<script type="text/x-magento-init"> { // components initialized on the element defined by selector "<element_selector>": { "<js_component1>": ..., "<js_component2>": ... } } </script>
After old content is deleted and new AJAX content is inserted into DOM, scripts bound to old HTML elements stop working and new instances of declaratively initialized scripts are created and attached to new content automatically.
In your script initialization code you can check if script is being initialized during initial page load or during AJAX refresh:
if ($(document).data('mana-replacing-content')) {
// script is being reinitialized after AJAX refresh
}
else {
// script is being initialized on initial page load
}
Scripts Initialized Imperatively
By using imperative notation, scripts can be initialized anywhere in your code, for instance while handling DOMContentLoaded
event:
$(function() {
// in some place your script is initialized. Initialization may include
// attaching event handlers to HTML elements, making changes to HTML
// elements, preparing initial component state
});
After old content is deleted and new AJAX content is inserted into DOM, scripts bound to old HTML elements using imperative notation stop working and imperatively created scripts are not reinitialized and not attached to newly inserted content.
Reinitialization of such scripts should be done manually by handling mana-before-replacing-content
and mana-after-content-replaced
events.
Handling Script Shutdown and Reinitialization Events
In most cases creating and attaching new script instances to new content is enough and no customization is needed. However, you might want to have more precise control over stopping old script instances (attached to content being removed) and over creating new script instances (attached to newly inserted content).
mana-before-replacing-content
Event
Before old content is removed, mana-before-replacing-content
event is triggered. Handling this event can be handy:
- state data of your script can be saved to some temporary storage so, that after new content is inserted, current script state can be restored into new instance of the script, the one bound to newly insterted HTML elements.
- timers or any long-running processes can be shut down
You can handle mana-before-replacing-content
event by using the following code snippet:
$(document).on('mana-before-replacing-content', function(event, $containers) {
// save state data to temporary storage
// shut down timers and release other resources
});
Event handler contains additional parameter $containers
- jQuery selector object of all top level elements being replaced. You can use this parameter to find all elements your script is working with.
mana-after-content-replaced
Event
Just after new content is inserted, mana-after-content-replaced
event is triggered. Handling this event can be handy:
- imperatively created scripts can be reinitialized
- state data of your script can be restored from temporary storage to which is was saved in
mana-before-replacing-content
event handler. - timers or any long-running processes can be restarted
You can handle mana-before-replacing-content
event by using the following code snippet:
$(document).on('mana-after-content-replaced', function(event, $containers) {
// reinitialize imperatively created scripts
// restore state data from temporary storage
// restart timers and reallocate other resources
});
Event handler contains additional parameter $containers
- jQuery selector object of all inserted top level elements. You can use this parameter to find all elements your script is working with.