- Home
- Blogs
- George Boobyer's blog
- Drupal Behaviors, Ajax and doing it once
Drupal Behaviors, Ajax and doing it once
After wrestling with this for a while this evening it struck me that it isn't a very well documented area - so I thought I'd make a quick post as much for my own notes as hopefully assistance for someone else.
The issue: You have some jQuery that runs once the page has loaded and you find that it runs on Ajax post backs .. Ugh!!
The end result is that you get the behaviour repeated every time the code runs - not nice.
The answer lies in the use of the jQuery .Once() - see http://drupal.org/update/modules/6/7#jquery_once
So your code becomes (in this example we collapse a list of features):
<?php Drupal.behaviors.FeatureList = { attach : function(context) { var n = $(".feature-list li").length; // If there are more then n list items collapse those after n and add a see more link if (n > 4) { $('.feature-list',context).once('dww',function() { $("<a href='javascript:void(0)' >See More</a>").insertAfter(".feature-list"); }) ; // create a toggle for the list so you can expand and collapse it $(".feature-list li:nth-child(n+4)").addClass("togDesc"); $(".seeMoreLi").live("click", function(){ $('.togDesc').toggleClass('togDesc'); $(this).addClass('seeLessLi'); $(this).removeClass('seeMoreLi'); $(this).html("<i class='icon-minus'></i> See Less"); }); $(".seeLessLi").live("click", function(){ $(".feature-list li:nth-child(n+4)").addClass("togDesc"); $(this).addClass('seeMoreLi'); $(this).removeClass('seeLessLi'); $(this).html("<i class='icon-plus'></i> See More"); }); } } }?>
Another useful technique in Drupal Commerce is to test to see if the variation (SKU) selection widgets are present (e,g, select size, colour etc). They get removed if there is only one variant (i.e. One colour or size). This can cause your display to mess up as the number of fields is not constant and will collapse. So test for the widgets (e.g. size, colour selectors) and again have this only happen once! In this instance we provide a style that we can target to give it a margin when the widgets are not present.
***Update*** see http://drupal.org/node/1029002 for a fix that made it into Commerce - nice! so you don't need to do this now
<?php// Add 'no widget' class to product description. Drupal.behaviors.productDescNoWidget = { attach: function ( context, settings ) { $('.productInfoBox',context).once('dsw',function() { if (!$('.attribute-widgets').length) { $('div.field-name-body').addClass("nowidgets") ; } else { $('div.field-name-body').addClass("widgets") ; } }); } }?>
Wrapping your code in the $('.feature-list',context).once('dww',function() will ensure that your code only runs once. It does this by putting a processed class on the element and not doing it if the class is found - Neat huh!
There are many other options that enable you to test the context of your behaviour such as:
<?php // this will display the context if you are not a full load if(typeof context == 'object' && context.toString().indexOf('HTMLDocument')!=-1){ alert('page load') ;//Page Load } else { alert('Context; typeof:'+typeof context+' | Var: '+context+' | toString: '+context.toString()+' | toSource: '+context.toSource()); } // see if you are a full document and not just a snippet if(context =='[object HTMLDocument]'){ alert('Full document'); }?>
Interrogating the context may be of value under certain circumstances and tells you a lot about what triggered the reload. But in my case Once was enough!
Contact Details
Blue-Bag Ltd
- info [at] blue-bag.com
- Telephone: 0843 2894522
- Blue-Bag HQ:
The Garage, Manor Farm
Chilcompton, Radstock
Somerset, BA3 4HP, United Kingdom - Telephone: (+44) 01761 411542
- Blue-Bag Brighton:
Unit 35 Level 6 North, New England House
New England Street, Brighton
BN1 4GH United Kingdom - Telephone: (+44) 07944 938204
- VAT GB 748125034
- UK Company Reg: 3932829