views:

2624

answers:

3

I'm using jQuery in my site and I would like to trigger certain actions when a certain div is made visible.

Is it possible to attach some sort of "isvisible" event handler to arbitrary divs and have certain code run when they the div is made visible?

I would like something like the following pseudocode:

$(function() {
  $('#contentDiv').isvisible(function() {
    alert("do something");
  });
});

The alert("do something") code should not fire until the contentDiv is actually made visible.

Thanks.

+11  A: 

There is no native event you can hook into for this however you can trigger an event from your script after you have made the div visible using the .trigger function

e.g

//declare event to run when div is visible
function isVisible(){
   //do something

}

//hookup the event
$('#someDivId').bind('isVisible', isVisible);

//show div and trigger custom event in callback when div is visible
$('#someDivId').show('slow', function(){
    $(this).trigger('isVisible');
});
redsquare
My limitation here is that I don't necessarily have access to the code that show()'s my div. So I would not be able to actually call the trigger() method.
frankadelic
How on earth do you not have access to the js that is hiding one of the divs on your page?
redsquare
The JS was provided by a development team outside my organization. It's also something of a "black box", so we don't want to modify that code if possible. It may be our only choice though.
frankadelic
you can always stamp over their js functions with your own implementation. Sounds grim however!
redsquare
+10  A: 

redsquare's solution is the logic answer.
but as an in- theory solution you can code a function which is selecting the elements classed by .visibilityCheck class (not all visible elements) and check their visibility property value; if true then do something. ok?
Afterward the function should be performed periodically using the setInterval() function. As you know, you can stop the timer using clearTimeout() and the timer ID upon the function's successful call-out.

function foo(){
    $('.visibilityCheck').each(function(){
        if($(this).is(':visible')){
            //do something
        }
    });
} //foo()
window.setInterval(foo, 100);

Also you can do some performance improvements on this, but the solution is basically ignored to be used in action, I think.

Sepehr Lajevardi
not good form to use an implied func inside setTimeout/setInterval. Use setTimeout(foo, 100)
redsquare
agree. http://is.gd/21fcd
Sepehr Lajevardi
+3  A: 

You could always add to the original .show method so you don't have to trigger events every time you show something or if you need it to work with legacy code:

jQuery(function($) {

    var _oldShow = $.fn.show;

    $.fn.show = function(speed, oldCallback) {
     return $(this).each(function() {
      var
       obj         = $(this),
       newCallback = function() {
        if ($.isFunction(oldCallback)) {
         oldCallback.apply(obj);
        }

        obj.trigger('afterShow');
       };

      // you can trigger a before show if you want
      obj.trigger('beforeShow');

      // now use the old function to show the element passing the new callback
      _oldShow.apply(obj, [speed, newCallback]);
     });
    }

    $('#test')
     .bind('beforeShow', function() {
      alert('beforeShow');
     })
     .bind('afterShow', function() {
      alert('afterShow');
     })
     .show(1000, function() {
      alert('in show callback');
     })
     .show();

});

This effectively lets you do something beforeShow and afterShow while still executing the normal behavior of the original .show() method. You could also create another method so you don't have to override the original .show() method.

Tres
This should be an accepted answer! Very useful.
Zlatev