Drupal 7.x Behaviors / AJAX Issue

I’m using a Drupal 7.x View to display field data corresponding to a custom content type. Nothing really special here as far as Drupal or PHP is concerned but when I try to use Drupal behaviors to make one of the divs “expandable,” I run into problems: the jQuery I’m using works after first-time page request–everything is toggled correctly–but as soon as I activate an AJAX call using the Drupal Views filter input, the jQuery associated with the toggle button “gets lost.”

Here’s the code I’m using which I load through Drupal’s “template.php” file:

(function ($) {
    Drupal.behaviors.mymodule = {
        attach: function(context, settings){

            $(function(){

                //The toggle.
                $('.toggle').click(function(){
                    if($(this).attr('title') == 'Show More'){
                        console.log('a');                        
                        $(this).attr('title','Show Less');
                        $(this).addClass('open');
                        $(this).removeClass('close');
                        $(this).parent('.field-content').removeClass('more');
                        $(this).parent('.field-content').addClass('less');
                    }else{
                        console.log('b');
                        $(this).attr('title','Show More');
                        $(this).addClass('close');
                        $(this).removeClass('open');
                        $(this).parent('.field-content').removeClass('less');
                        $(this).parent('.field-content').addClass('more');
                    }
                });

            });
        }
    }
})(jQuery);

Long story short, any hyperlink that has the class of “toggle” gets this logic assigned to it. So when John Doe clicks on one of these, the DIV expands to show the other information. Everything works during a fresh page request, but as soon as someone uses the Views filter input (the thing that makes the AJAX call), this functionality stops working correctly.

One thing I did notice in Firebug is this: when the page is loaded for the first time, it takes two clicks of the link to make ‘a’ and ‘b’ show up in the console. However, after the AJAX request, it only takes 1 click for both ‘a’ and ‘b’ to appear… (As if both conditions get fired off with only 1 click…)

Thoughts?

If the filters result in elements being removed then recreated on the page, that can result in the loss of any events that used to be attached to them.

I see what you’re saying but I think everything is being recreated with the same names, etc. I’ll do a WinDiff on the before / after markup to verify this–I actually did that earlier but it was only a skim-through and not a thorough analysis.

But would the same be true if the elements still have the same class names, etc.? For example, if I have <a href=“#” class=“toggle”> at the beginning and after the AJAX call, it still has that same markup (but was just recreated), would the events still be attached then? In this case, it would be more about the “instance” of the element, but I never thought that should matter as long as the same structure of the elements are present.

No, it would not.

jQuery does have something though that used to be called live events. This is where the event is attached to the document, where events that bubble up to there are captured and handled. Such live events have been deprecated now, and are rolled in to jQuery’s .on() method.

For example:


$('.toggle').on('click', document, (function(){

As Paul says, if an element is removed and then recreated, it will not have its original event handlers re-applied to it, irrespective of its markup.

Maybe you want to look at event delegation.

E.g. imagine that the <li> elements are dynamically removed and then reinserted:

<ul id="myList>
  <li class="myListElement">one</li>
  <li class="myListElement">two</li>
  <li class="myListElement">three</li>
</ul>

And the <li> elements have the following click handler:

$(".myListElement").on("click", function(){
  alert("Hello!");
});

Any list elements that were recreated would ignore the click handler.
To get round this, you attach the handler to a parent element, that is present when the document renders initially, then specify the child element as an additional parameter:

$("#myList").on("click", ".myListElement", function(){
  alert("Hello!");
});

Then, any <li> elements that are inserted into the list via AJAX will also respond to clicks.

Figured out what was going on… I had used “bind()” on the toggle but needed to unbind() it before binding it…

Anyway, I hope that makes sense. Got the idea from here: http://stackoverflow.com/questions/3984684/drupal-jquery-click-event-being-called-three-times-per-click (Someone else was experiencing the same problem.)

Thanks guys. Your idea(s) led me down that path. :slight_smile:

Hi there,

Glad you got your problem sorted :slight_smile:
Just out of interest, could you share your final solution (including a bit of HTML so that I can recreate it on my PC)?