Watch for Object Changes with JavaScript

By  on  

Watching for changes to an object's property has always been a much sought after task; many shims have been used over the years to listen to object changes.  These days we have better methods for listening to object changes:  the Proxy API.  Sindre Sorhus has created on-change, a tiny JavaScript tool that allows you to listen for changes on JavaScript objects and arrays!

on-change JavaScript

Since the on-change code is so tiny, here it is in its full glory:

'use strict';

module.exports = (object, onChange) => {
	const handler = {
		get(target, property, receiver) {
			try {
				return new Proxy(target[property], handler);
			} catch (err) {
				return Reflect.get(target, property, receiver);
			}
		},
		defineProperty(target, property, descriptor) {
			onChange();
			return Reflect.defineProperty(target, property, descriptor);
		},
		deleteProperty(target, property) {
			onChange();
			return Reflect.deleteProperty(target, property);
		}
	};

	return new Proxy(object, handler);
};

The onChange function returns a proxy which you'll use to make any object changes.

Using on-change

Pass onChange the object you'd like to spy on and a change handler function:

let j = {
    a: 1
};

// Upon change, save to server
let changeable = onChange(j, () => save(j));

Then use that Proxy to change properties and get notified of changes:


// Make a change that would trigger changes
changeable.a = 2;

// save() is triggered!

// j.a === 2

Note that the original object's values also change -- that's the beauty of Proxy!  Also note that on-change doesn't tell you which property changed; the use case, as Sindre describes, is saving an object (to server, etc.) when any part of an object changes.  You could also use ti for a small library with a render function, re-rendering the content whenever a property changed!

This on-change library is really nice if you don't need to know which property changed, just that something changed.

Recent Features

  • By
    CSS Filters

    CSS filter support recently landed within WebKit nightlies. CSS filters provide a method for modifying the rendering of a basic DOM element, image, or video. CSS filters allow for blurring, warping, and modifying the color intensity of elements. Let's have...

  • By
    Create Namespaced Classes with MooTools

    MooTools has always gotten a bit of grief for not inherently using and standardizing namespaced-based JavaScript classes like the Dojo Toolkit does.  Many developers create their classes as globals which is generally frowned up.  I mostly disagree with that stance, but each to their own.  In any event...

Incredible Demos

  • By
    Spoiler Prevention with CSS Filters

    No one likes a spoiler.  Whether it be an image from an upcoming film or the result of a football match you DVR'd, sometimes you just don't want to know.  As a possible provider of spoiler content, some sites may choose to warn users ahead...

  • By
    MooTools Window Object Dumping

    Ever want to see all of the information stored within the window property of your browser? Here's your chance. The XHTML We need a wrapper DIV that we'll consider a console. The CSS I like making this look like a command-line console. The MooTools JavaScript Depending on what you have loaded...

Discussion

  1. If someone wonders what this Reflect object it. I stumbled across on-change a few days ago and wrote about it. :)

    https://www.stefanjudis.com/today-i-learned/the-global-reflect-object-its-use-cases-and-things-to-watch-out-for/

  2. Dave

    Just a note that watching an object really bogs down all accesses to the object. It’s great for debugging but don’t build a lot of functionality around it in your production code.

  3. Raj

    It is worth mentioning that arrays are not handled by this function and push/pop/delete to an array needs to be handled by overwriting those methods.

  4. Jean-Guy Boulay

    Thanks for this David, I’m relatively novice to programming (used mostly in webobjects within Storyline) so forgive me if my question seems idiotic. I checked out Proxy Api and it’s browser compatibility excludes IE. Is there an alternative to onChange for IE?

  5. javi

    Nice solution,

    But to create a proxy for change notification purposes is not the same that observe changes on an object. In your solution, you create a different object – the proxy – to operate with and force the developer to abandon the use of the original object. The best explanation is an example:

       let j     = { x : 1 }
       let proxy = onChange (j, ...)
    
       proxy.x = 2 // works!
       j.x = 2     // does not work! 
    

    Why this detail is, sometimes, important. Because, sometimes, you are not the owner of the object j and the owner does not want to change the j reference for your proxy. Imagine a situation where you are a framework developer and want to observe changes in some code of your user by maintaining transparency from her perspective.

    If you want another example I can detail the corner case that brought me here. In my case, my j object is a DOM element and I cannot replace it with a proxy.

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