Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Event Delegation + Child Targeting Help

I display a bunch of posts from users on a page. I have the main parent div with the class name 'posts' and each post is outputted in a div with class name 'row' inside of it. So there's a whole lot of div.row's inside the div.posts. Each look like this.

<div class="row clearfix">
    <div class="left-column">
        <img src="..." title="" />
    </div>
    <div class="main-column">
        <div class="row-text">Post Text...</div>
        <div class="row-date">Posted Date...</div>
    </div>
    <div class="actions-column">
        <a href="#">Link</a>
        <a href="#">Link 2</a>
        <a href="#">Link 3 etc.</a>
    </div>
</div>

Via CSS the actions-column is set to display:none by default. When a user mouseover's a post (div.row) I want to show the actions-column. My initial way of doing it was by setting a mouseover even for each row and that was taking it's toll on the browser and slowing things down. I did some research and stumbled upon event delegation and decided to give it a try. So far I am able to identify which row is being targeted, however, I cannot figure out how to target it's child-div with the class 'actions-column'.

Code so far...

$(window).load(function(){

    $('.posts').mouseover(function(e){
        var $row, $tgt = $(e.target);

        if ($tgt.hasClass("row")) {
            $row = $tgt;
        } else { 
            if ($tgt.parent().parent().hasClass('row'))
                $row = $tgt.parent().parent();

            else if ($tgt.parent().hasClass('row'))
                $row = tgt.parent();    

            else
                return false;       
        }

        //code here to select div.actions-column and show it

    });

    $('.posts').mouseover(function(e){
        var $row, $tgt = $(e.target);

        if ($tgt.hasClass("row")) {
            $row = $tgt;
        } else { 
            if ($tgt.parent().parent().hasClass('row'))
                $row = $tgt.parent().parent();

            else if ($tgt.parent().hasClass('row'))
                $row = tgt.parent();    

            else
                return false;       
        }

        //code here to select div.actions-column and hide it

    });

});
like image 884
Seth Avatar asked Jan 28 '26 08:01

Seth


2 Answers

You could use live:

$('div.row').live('mouseover', function() {
    $(this).find('div.actions-column').show();
}).live('mouseout', function() {
    $(this).find('div.actions-column').hide();
});

As the documentation notes:

When you bind a "live" event it will bind to all current and future elements on the page (using event delegation).

A couple more notes:

  • I see you are using the $(window).load() event. You probably want $(document).ready()
  • You should take advantange of jQuery's chaining capabilities instead of querying for $('.posts') twice, you can just append the second call at the end (like I did in my example above) - this is much more efficient and the preferred way of doing multiple things to 1 selector in jQuery.
  • The code you are trying to write to find the next div.row up the HTML tree has already been implemented by jQuery's closest() method.

You could do something like this with it:

$('div.posts').hover(function(e) {
    var row = $(e.target).closest('div.row');
    $row.find('div.actions-column').show();
}, function(e) {
    var row = $(e.target).closest('div.row');
    $row.find('div.actions-column').hide();
});

But this is not necessary because of the live functionality I showed above.

  • Think about the efficiency of your queries. If you only have a single <div> with a class of posts, consider giving it an id attribute. This is by far the most efficient method of selecting elements in a document, and it makes sense to give it to elements that only occur once.
  • Whenever you are querying for an element by class, it is good practice to include the tag name before the class (unless you expect it to be in many different tags, of course) - so instead of looking for .row, make a habit of looking for div.row instead. It's just faster.
like image 190
Paolo Bergantino Avatar answered Jan 30 '26 22:01

Paolo Bergantino


I realize this has already been answered, but since jQuery 1.5 adds an explicit "delegate" method, that might be a better solution now. Since this thread will come up in searches, I post this answer for other people searching for it. (I also refactor for further conciseness by using "hover" and "toggle()" instead of mouseenter/mouseleave + show()/hide().)

http://api.jquery.com/delegate/

$('div.row').live('mouseover', function() {
    $(this).find('div.actions-column').show();
}).live('mouseout', function() {
    $(this).find('div.actions-column').hide();
});

with jQuery 1.5 or higher could be written as:

$(".posts").delegate("div.row", "hover", function(){
    $(this).find("div.actions-column").toggle();
});

See it in action:

http://jsfiddle.net/SM6Jv/

enter image description here

like image 33
Dennis Avatar answered Jan 30 '26 22:01

Dennis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!