The idea is that it should be possible to load a block on a page without creating a new controller. Consider this as a partial-page reload framework.
In our own private frontend framework we've implemented ajax carts, ajax wishlists and live search without writing large scripts to do this.
In short, have an action source:
<a href="#" data-ho-ajax-link="cart">foo</a>
And have target:
<div data-ho-ajax="<?php echo $this->getNameInLayout(); ?>" data-ho-ajax-group="cart">
...
</div>
When the action is called, the target is reloaded.
When a customer presses their add to cart button (which can be a link or a form) you want to add the product to the cart but only reload the cart.sidebar
block. You could achieve this by creating a new controller that only has the cart.sidebar
block, serialize the response, send the response to the browser an replace the appropriate divs.
The problem with this approach is, that if a third party developer adds a block that shows some cart related data or renames the cart.sidebar block to something else, the implementation breaks.
To fix this we need a generalized javascript API that developers can easily hook into without breaking compatibility. We are using a data- attribute API to specifiy which parts of the page interact (links, forms) and which parts need to be reloaded when the action has completed.
We can have two action sources, data-ho-ajax-link
and data-ho-ajax-form
and direct API calls.
We have the following cart button
<a title="<?php echo Mage::helper('catalog')->__('Add to Cart') ?>"
class="btn btn-cart btn-default"
data-ho-ajax-link="cart"
href="<?php echo $this->getAddToCartUrl($_childProduct) ?>"
rel="nofollow">
<?php echo Mage::helper('catalog')->__('Add to Cart') ?>
</a>
You can see the data-ho-ajax-link
attribute that specifies that it is a link that is going to reload parts of the page and the content of that attribute specifies that it needs to reload all the cart
blocks.
Forms are still experimental, since the form is serialzed and does a POST over javascript, which can cause problems with file uploads
<form method="get" class="form-search" role="search" data-ho-ajax-form="ajaxsearch">
<div class="input-group">
<input id="ajaxsearch-input" type="text"
name="<?php echo $catalogSearchHelper->getQueryParamName() ?>"
value="<?php echo $catalogSearchHelper->getEscapedQueryText() ?>"
class="form-control"
autocomplete="off"
maxlength="<?php echo $catalogSearchHelper->getMaxQueryLength();?>"
placeholder="<?php echo $this->getSearchPlaceholder();?>"
/>
<span class="input-group-btn">
<button type="submit" title="<?php echo $this->__('Search') ?>" class="btn btn-default" id="ajaxsearch-button"><?php echo $this->__('Search') ?></button>
</span>
</div>
</form>
Here you can see the data-ho-ajax-form
element which specifies that the form is going to reload parts of the page and the content of that attribute specifies that is needs to reload all ajaxsearch
blocks.
You can refresh the page directly
$(document).hoAjax('refreshPage', 'cart');
In the template of the block that needs to be reloaded, we add two attributes, one with the name of the block and another with the group name
<div class="cart" data-ho-ajax="<?php echo $this->getNameInLayout(); ?>" data-ho-ajax-group="cart account">
...
</div>
When loading calling an action that has the group cart
the script searches the DOM to find all blocks with data-ho-ajax-group = cart.
The messages are appended to a special messages block which we render fixed at the top of the page. the messages block has the group all
and always gets refreshed on each page load.
Refreshes all the blocks that are in a certain group.
$(document).hoAjax('refreshPage', 'cart');
Get all dynamic blocks on the page
var group = cart; //can be undefined to get all blocks
$(document).hoAjax('getBlocks', group);
Get a single block by the name in the layout
var blockName = 'cart.header';
$(document).hoAjax('getBlocks', blockName);
We trigger the following events:
//when a link is pressed, this is triggered immediately
$link.trigger('requestStart.hoajax');
$link.trigger('requestStartGroup.hoajax.'+group);
//when a form is submitted, this is triggered immediately
$form.trigger('requestStart.hoajax');
$form.trigger('requestStartGroup.hoajax.'+group);
//After the response has returned, before rendering all blocks
$(document).trigger('responseStart.hoajax');
$(document).trigger('responseStartGroup.hoajax.'+group);
//Before a block is inserted into the HTML.
$(document).trigger('responseFinishBlockPrepare.hoajax.'+blockName);
//When a certain block is rendered
$(document).trigger('responseFinishBlock.hoajax.'+blockName);
//After the response has returned, after rendering all blocks
$(document).trigger('responseFinish.hoajax');
$(document).trigger('responseFinishGroup.hoajax.'+group);
You can use them in the following way:
$(document).on('responseFinishGroup.hoajax.cart', function(){
//Do some additional stuff
});
For each request the ho_ajax handle
is loaded as well as the ho_ajax_[current_controller_handle]
, for example: ho_ajax_catalogsearch_result_index
or ho_ajax_catalog_product_view
.
Credits for the idea go to https://github.com/hws47a/VF_EasyAjax. I've completely rewritten the module to suit H&O's needs for building our Magento webshops.