jQuery event to trigger action when a div is made visible

jQuery event to trigger action when a div is made visible

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.

Solutions/Answers:

Solution 1:

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 extension:

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]);
    });
  }
});

Usage example:

jQuery(function($) {
  $('#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.

Solution 2:

The problem is being addressed by DOM mutation observers. They allow you to bind an observer (a function) to events of changing content, text or attributes of dom elements.

With the release of IE11, all major browsers support this feature, check http://caniuse.com/mutationobserver

The example code is a follows:

$(function() {
  $('#show').click(function() {
    $('#testdiv').show();
  });

  var observer = new MutationObserver(function(mutations) {
    alert('Attributes changed!');
  });
  var target = document.querySelector('#testdiv');
  observer.observe(target, {
    attributes: true
  });

});
<div id="testdiv" style="display:none;">hidden</div>
<button id="show">Show hidden div</button>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>

Solution 3:

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');
});

Solution 4:

You can use jQuery’s Live Query plugin.
And write code as follows:

$('#contentDiv:visible').livequery(function() {
    alert("do something");
});

Then everytime the contentDiv is visible, “do something” will be alerted!

Solution 5:

redsquare’s solution is the right answer.

But as an IN-THEORY solution you can write a function which is selecting the elements classed by .visibilityCheck (not all visible elements) and check their visibility property value; if true then do something.

Afterward, the function should be performed periodically using the setInterval() function. You can stop the timer using the clearInterval() upon successful call-out.

Here’s an example:

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

window.setInterval(foo, 100);

You can also perform some performance improvements on it, however, the solution is basically absurd to be used in action. So…

Solution 6:

The following code (pulled from http://maximeparmentier.com/2012/11/06/bind-show-hide-events-with-jquery/) will enable you to use $('#someDiv').on('show', someFunc);.

(function ($) {
  $.each(['show', 'hide'], function (i, ev) {
    var el = $.fn[ev];
    $.fn[ev] = function () {
      this.trigger(ev);
      return el.apply(this, arguments);
    };
  });
})(jQuery);