O'Reilly

Introducing MooTools ElementSpy

By on  

One part of MooTools I love is the ease of implementing events within classes. Just add Events to your Implements array and you can fire events anywhere you want -- these events are extremely helpful. ScrollSpy and many other popular MooTools plugins would be nothing without events. And think of DOM elements without events...terrible! Not knowing when someone clicked, hovered, etc. would completely defeat the purpose of JavaScript!

I wanted to take basic element events further. Sure I know when the value of an input changes (via onChange), but what about when another attribute changes? Or a style change? Or the change in a storage value? ElementSpy allows you to assign periodical checks on element attributes or other aspects of elements.

The MooTools Javscript

var ElementSpy = new Class({
	Implements: [Options,Events],
	options: {
		interval: 100
	},
	initialize: function(element,attribute,options) {
		this.setOptions(options);
		this.element = document.id(element);
		this.val = this.getter(attribute);
		this.interval;
		this.worker = function() {
			var value = this.getter(attribute);
			this.fireEvent('check',[this.val,value]);
			if(value != this.val) {
				this.fireEvent('change',[this.val,value]); //old,new
				this.val = value;
			}
			else {
				this.fireEvent('stagnate',[value]); //current
			}
		}.bind(this);
	},
	start: function() {
		this.interval = this.worker.periodical(this.options.interval);
		this.fireEvent('start');
		return this;
	},
	stop: function() {
		$clear(this.interval);
		this.fireEvent('stop');
		return this;
	},
	getter: function(attribute) {
		return $type(attribute) == 'function' ? (attribute.bind(this.element))() : this.element.get(attribute);
	}
});

The following are arguments, options, and events for ElementSpy:

Arguments

  • element: The element to spy on.
  • attribute: The attribute to spy on *or* a function that returns a value.
  • options: The class options.

Options

  • interval: (defaults to 100) The frequency in milliseconds that the element should be checked.

Events

  • change: Fired when the value has changed.
  • check: Fired every time the element is checked.
  • start: Fired when an element starts being spied on.
  • stop: Fired when you stop spying on an element

The MooTools ElementSpy Usage

var element = document.id('my-image');
/* simple: just watch an attribute */
var spy = new ElementSpy(element,'src', { 
	duration: 200,
	onChange: function(old,nu) { //alert when the image's SRC has changed!
		alert('Image SRC changed from ' + old + ' to ' + nu);
	}
});
//start spying on the image SRC!
spy.start();

This first usage is about as basic as it gets -- listening for an image SRC change.

/* difficult: watch a style */
var element2 = document.id('button2');
var spy2 = new ElementSpy(element2,function() {
	return this.getStyle('cursor');
}, { 
	duration: 200,
	onChange: function(old,nu) {
		alert('Change!  Value changed from [' + old + '] to ' + nu + ']');
	},
	onCheck: function(old,nu) {
		console.log('Check:  Value changed from [' + old + '] to ' + nu + ']');
	}
});
spy2.start();
element2.addEvent('click',function() {
	this.setStyle('cursor','pointer');
	(function() { spy2.stop(); }).delay(2000);
});

This second, more advanced solution listens for a change in CSS cursor and allows me to fire events accordingly.

Please keep in mind that this class can be harsh on the browser if overused so please use with care! I'd also like to hear your thoughts on the class. Like it? Dislike? Have improvement ideas? Let me know!

Track.js Error Reporting

Recent Features

Incredible Demos

  • Prevent Page Zooming in Mobile Browsers

    Ever since I got my iPhone, I've been more agreeable in going places that my fiancee wants to go. It's not because I have any interest in checking out women's shoes, looking at flowers, or that type of stuff -- it's because my iPhone lets...

  • MooTools Accordion: Mouseover Style

    Everyone loves the MooTools Accordion plugin but I get a lot of requests from readers asking me how to make each accordion item open when the user hovers over the item instead of making the user click. You have two options: hack the original plugin...

Discussion

  1. there is a typo in the stop options.

    “start: Fired when you stop spying on an element”

    great post (As usually)!

  2. David, this is very useful! Thank you! BTW, It looks like Harald Kirschner’s Observer class, but more functional :) Mootools FTW!!11

  3. Nice idea, David. Do you think this could be combined with native Javascript getter/setters for browsers that support them? I understand getters and setters are not very standard or supported, but it would be cool to use them when possible, right?
    https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Creating_New_Objects/Defining_Getters_and_Setters

  4. Guillermo Rauch

    Nice idea. Not sure if I’d implement it as a standalone Class myself though.

    Also, I would avoid the timer if DOMAttrModified is available:

    if (document.implementation.hasFeature('MutationEvents','2.0')){
      // subscribe to DOMAttrModified
    } else {
      timer
    }
    

    There’re many ways to approach this problem. Another would be to create a custom MooTools event.

  5. Also, another way to detect support is to check for the presence of the MutationEvent constructor

    if (document.implementation.hasFeature(‘MutationEvents’,’2.0′) || ‘MutationEvent’ in window)

  6. This is a sweet plugin, Thanks David !

  7. Sweet plugin, awesome site!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!

Recently on David Walsh Blog

  • Loading Static Templates for Intern Testing

    I use Intern by SitePen for all of my JavaScript functional testing.  Intern has loads of features other functional test frameworks don't and it's completely Promise-based -- something I got very used to when I used the Dojo Toolkit every day. Async test creation can...

  • Convert Video to mp3

    Let's all be honest for a moment:  we've all ... not paid for ... music.  Whether it was via a file sharing app like Kazaa or Napster, or it was downloading and seeding on bittorrent, or maybe even downloading a music video and ripping its audio,...

  • Sort git Branches by Date

    I'll be first person to admit I don't do as much git repository maintenance as I should.  I rarely delete branches which have been merged, so a git branch execution shows me a mile-long list of branches that likely aren't relevant.  The best way to find branches I've recently...

  • Best Tools and Resources for Web Professionals in 2015

    Looking for the right resources to help you satisfy the needs of your clients? On the lookout for the best tools to help you increase your revenue? Searching for the right software to help you improve your business? Well, then you’ve come to the right place....

  • JavaScript Polling

    Polling with JavaScript is one of those ugly but important functions within advanced front-end user experience and testing practices.  Sometimes there isn't the event you can hook into to signify that a given task is complete, so you need to get your hands dirty and simply poll for...