views:

837

answers:

6

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

 });

});
A: 

?:

$('div.actions-column', $row).show(); // .hide()

UPDATE:

It is better to use jQuery closest([expr]):

var $tgt = $(e.target);
var $row = $tgt.closest('.row');

instead of:

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;           
}
eu-ge-ne
A: 

Try:

$row.find (".actions-column").hide ();

And

$row.find (".actions-column").show();
AlbertEin
+4  A: 

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.
Paolo Bergantino
It's worth noting that the JS best practices on class selectors differs from the CSS best practices, since JS does not have a native class selector. CSS, however, does and there the element tag should be omitted. Reference: http://code.google.com/speed/page-speed/docs/rendering.html
PatrikAkerstrand
+1  A: 

Try using jQuery's live() method. It uses event delegation internally to perform its actions so you won't even have to think about setting up event delegation properly.

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

Unless you really wanted to do this with jQuery then of course something can be managed with a line of CSS:

div.row:hover div.actions-column { display:block; }
A: 

I agree with poopdeck, it's by far the most efficient way. Mouseover effects tend to be consumption heavy and often fails to update when moving the mouse quickly. Css pseduo hover never fails and is consistent.

Just my five...

/T

Tommy