6

let say have element like this

<div class="watch-me" style="display: none;">Watch Me Please</div>

as we can see the element above style is display: none, how can i make script to watch this element. when that element style is change to display: block then there is some code will be trigger.

many thanks...

GusDeCooL
  • 5,639
  • 17
  • 68
  • 102

8 Answers8

17

As far as I know, the only way to do this would be with a timer.

I created a small jQuery plugin (yes, right here, right now) that does this against a jQuery set:

EDIT this plugin is now on GitHub: https://github.com/jacobrelkin/jquery-watcher

$.fn.watch = function(property, callback) {
   return $(this).each(function() {
       var self = this;
       var old_property_val = this[property];
       var timer;

       function watch() {
          if($(self).data(property + '-watch-abort') == true) {
             timer = clearInterval(timer);
             $(self).data(property + '-watch-abort', null);
             return;
          }

          if(self[property] != old_property_val) {
             old_property_val = self[property];
             callback.call(self);
          }
       }
       timer = setInterval(watch, 700);
   });
};

$.fn.unwatch = function(property) {
   return $(this).each(function() {
       $(this).data(property + '-watch-abort', true);
   });
};

Usage:

$('.watch-me').watch('style', function() {
   //"this" in this scope will reference the object on which the property changed
   if($(this).css('display') == 'block') { 
       //do something...
   }
});

To clear this property watcher:

$('.watch-me').unwatch('style');
Gili
  • 86,244
  • 97
  • 390
  • 689
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • and then what will be code in here? `//"this" in this scope will reference the object on which the property changed` – GusDeCooL Dec 31 '10 at 06:00
  • I wrote a related plugin to monitor computed values of individual styles (like color, width etc.) instead of the `style` attribute on the whole. Maybe of help: http://techfoobar.com/jquery-style-listener – techfoobar Jan 06 '13 at 17:01
  • 2
    You saved my hair ! how can i pass a beer ? :) – Vivek Sampara Jan 09 '13 at 07:15
  • in response to @user76061 comment. I don't know if that was sarcasm, but damnit! that was cool. I only hope I can one day be cool in this field...because now, sadly I am not. – dgo May 02 '14 at 22:20
9

You may use object.watch function however its non standard, there is already a cross-browser implementation Object.watch() for all browsers?

$('.watch-me').get(0).watch('style', handlerFunction);
Community
  • 1
  • 1
Amjad Masad
  • 4,035
  • 1
  • 21
  • 20
3
function startPolling()
{
    var handle = window.setInterval(function(){

        var element = $(".watch-me");
        if (element.css("display") == "block") {
            // trigger the event
            window.clearInterval(handle);
        }

    }, 100);
}

When you want to start watching simply write:

startPolling();
Roman
  • 10,309
  • 17
  • 66
  • 101
2

I wrote a jQuery plugin for watching changes on DOM element properties/attributes and CSS properties that some might find more intuitive/easier to use: jQuery.watch

In order to accomplish what you're after you would do something like this:

$('.watch-me').watch({
    'display': function( oldVal, newVal, elm ) {
        if (newVal == 'block') {
            // Do something
        }
    }
});

The plugin also supports tracking the return values of jQuery methods on watched elements, so you could for instance fire a callback when the return value of a jQuery method changes when called on a given element.

Xaxis
  • 1,935
  • 15
  • 17
1

check https://developer.mozilla.org/en/docs/Web/API/MutationObserver

var target = _DOM_;
var lastDisplayStyle = _DOM_.style.display;
var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        if (mutation.type === "attributes") {
            if (lastDisplayStyle !== _DOM_.style.display){
               // your code there
            }
        }
    });
});

var config = { attributes: true };
observer.observe(target, config);

P.S. watch / unwatch are deprecated. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/watch Do not use setInterval solutions!

1

Since you can't rely on the DOM Mutation Events due to no support for IE before 9, I think you'll be required to set a polling timer to watch. For example:

var watched = $('.watch-me');
var lastDisplay = watched.css('display');

// Peek at the property about twice per second
setInterval(function(){
  var curDisplay = watched.css('display');
  if (curDisplay!=lastDisplay){
    // Do what you want here.
    lastDisplay = curDisplay;
  }
},500);

If you want to cancel the watching after it changes once:

var watched = $('.watch-me');
var lastDisplay = watched.css('display');
var timer = setInterval(function(){
  if (watched.css('display')!=lastDisplay){
    // Do what you want here.
    clearInterval( timer );
  }
},500);
Phrogz
  • 296,393
  • 112
  • 651
  • 745
0

This might be considered not answering the question, but it would be better to use JQuery custom events and the .trigger method than using intervals and watching (which just consumes resources).

More to the point, elements can subscribe to new triggered events from objects that they are "watch"ing.

Take a look here:

http://www.sitepoint.com/jquery-custom-events/

Paul B. Hartzog
  • 341
  • 3
  • 6
0

This is highly experimental (you have been warned!) and might not be a good fit to your problem or answer to this question, but it has occurred to me that you can do two things:

1 - Override the jQuery's core .toggle method to add some data to the elements it gets applied to.

2 - Bind a changeData event handler to elements, as of jQuery 1.4.4

What that means is, you can make something happen whenever an element gets toggled. The same principle could apply to the .hide and .show methods, or any other methods for that matter.

// 1 - override .toggle()
var original = jQuery.fn.toggle;
jQuery.fn.toggle = function() {
    console.log("Override method: toggle()");

    // call the original toggle
    original.apply(this, arguments);

    // record the element's visibility
    $(this).data("visible", $(this).is(":visible"));

    return this;
};

// 2 - bind a changeData event handler to a 'watch list'
$('div').bind("changeData", function() {
    alert("Visibility changed to: " + $.data(this, 'visible'));
});

<!-- exhaustive test markup -->
<div id="test">Hello</div>
<div id="test2" style="display:none">Hello 2</div>

// go!
$(document).ready(function() {
    $("#test").toggle();
    $("#test2").toggle();
});

Try it out here: http://jsfiddle.net/karim79/nreqv/1/

karim79
  • 339,989
  • 67
  • 413
  • 406