SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Wizard Wolf_22's Avatar
    Join Date
    Jul 2005
    Posts
    1,714
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    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:
    Code:
    (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?

  2. #2
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by Wolf_22 View Post
    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.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  3. #3
    SitePoint Wizard Wolf_22's Avatar
    Join Date
    Jul 2005
    Posts
    1,714
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by paul_wilkins View Post
    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.

  4. #4
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by Wolf_22 View Post
    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?
    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:

    Code javascript:
    $('.toggle').on('click', document, (function(){
    Last edited by paul_wilkins; Jul 10, 2013 at 23:36.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  5. #5
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,051
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by Wolf_22 View Post
    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.
    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:

    HTML Code:
    <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:

    Code JavaScript:
    $(".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:

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

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

  6. #6
    SitePoint Wizard Wolf_22's Avatar
    Join Date
    Jul 2005
    Posts
    1,714
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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/3...imes-per-click (Someone else was experiencing the same problem.)

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

  7. #7
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,051
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Hi there,

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


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •