Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firing event on DOM attribute change

Is there any way to trigger event (may be custom) on attribute change?

Let's say, when IMG src is changed or DIV's innerHtml?

like image 710
ts. Avatar asked Dec 30 '10 10:12

ts.


People also ask

How do you detect change in DOM?

“MutationObserver” is a Web API provided by modern browsers for detecting changes in the DOM. By using this API you can listen to changes in DOM, like added or removed nodes, attribute changes or changes in the text content of text nodes and make changes.

What is DOM mutation?

The MutationObserver interface provides the ability to watch for changes being made to the DOM tree. It is designed as a replacement for the older Mutation Events feature, which was part of the DOM3 Events specification.

Which method is triggered when an element is added to the DOM?

We can detect if an element has been added to DOM using the MutationObserver object. This provides the ability to observe for changes being made to the DOM tree.


4 Answers

Note: As of 2012, Mutation Events have been removed from the standard and are now deprecated. See other answers or documentation for how to use their replacement, MutationObserver.

You are referring to DOM Mutation Events. There is poor (but improving) browser support for these events. Mutation Events plugin for jQuery might get you some of the way.

like image 114
Dean Burge Avatar answered Sep 25 '22 07:09

Dean Burge


How to setup a MutationObserver, mostly copied from MDN but I've added my own comments for clarity.

window.MutationObserver = window.MutationObserver     || window.WebKitMutationObserver     || window.MozMutationObserver; // Find the element that you want to "watch" var target = document.querySelector('img'), // create an observer instance observer = new MutationObserver(function(mutation) {      /** this is the callback where you          do what you need to do.          The argument is an array of MutationRecords where the affected attribute is          named "attributeName". There is a few other properties in a record          but I'll let you work it out yourself.       **/ }), // configuration of the observer: config = {     attributes: true // this is to watch for attribute changes. }; // pass in the element you wanna watch as well as the options observer.observe(target, config); // later, you can stop observing // observer.disconnect(); 

Hope this helps.

like image 31
Mats Avatar answered Sep 23 '22 07:09

Mats


If you only need something specific then a simple setInterval() will work, by checking the target attribute(s) every few milliseconds:

var imgSrc = null;
setInterval(function () {
   var newImgSrc = $("#myImg").attr("src");
   if (newImgSrc !== imgSrc) {
      imgSrc = newImgSrc;
      $("#myImg").trigger("srcChange");
   }
}, 50);

Then bind to the custom "srcChange" event:

$("#myImg").bind("srcChange", function () {....});
like image 30
David Tang Avatar answered Sep 22 '22 07:09

David Tang


There is no native dom changed event you can hook into.

Good article here which tries to provide a solution in the form of a jquery plugin.

Code from article

$.fn.watch = function(props, callback, timeout){
    if(!timeout)
        timeout = 10;
    return this.each(function(){
        var el      = $(this),
            func    = function(){ __check.call(this, el) },
            data    = { props:  props.split(","),
                        func:   callback,
                        vals:   [] };
        $.each(data.props, function(i) {
              data.vals[i] = el.css(data.props[i]); 
        });
        el.data(data);
        if (typeof (this.onpropertychange) == "object"){
            el.bind("propertychange", callback);
        } else if ($.browser.mozilla){
            el.bind("DOMAttrModified", callback);
        } else {
            setInterval(func, timeout);
        }
    });
    function __check(el) {
        var data    = el.data(),
            changed = false,
            temp    = "";
        for(var i=0;i < data.props.length; i++) {
            temp = el.css(data.props[i]);
            if(data.vals[i] != temp){
                data.vals[i] = temp;
                changed = true;
                break;
            }
        }
        if(changed && data.func) {
            data.func.call(el, data);
        }
    } }
like image 26
redsquare Avatar answered Sep 25 '22 07:09

redsquare