listener.js

import listener from 'listener.js'

Description

Listeners are special proxy objects that can trigger (one or several) callbacks when any of its properties are set.

listener
target ⟶ proxy
nil ⟶ proxy
A factory function for new listener objects. When an object is passed as an argument, the listener will act as a proxy for that object. Otherwise a new target object is created.

Example

import MyUserComponent from '/path/to/MyUserComponent.js' // Suppose this component allows the user to enter a new name import backend from '/path/to/backendController.js' // Suppose this class abstracts some backend API const user = listener({name: "World"}) // Greet the user whenever the name changes: user.listen("name", newName => alert(`Hello, ${newName}!`)) // Save the in the back-end whenever it changes: user.listen(null, (value, old) => { if (value != old) backend.saveUserSomehow(user) })) document.body.apend(new MyUserComponent(user))

This code uses a listener proxy to represent a User so it can respond whenever the user gets updated.

Methods

The proxy object will override the following two properties of the target object:

listener.listen(<prop>, <callback>)
Registers a callback on a single property that will be called whenever the property changes.
listener.listen(null, <callback>)
Registers a callback that will be called whenever any property changes.
listener.listen(<prop>|null, <callback>, {once: true})
Registers a callback that will only be called once, then remove itself.
listener.forget(<prop>, <callback>)
Forgets a specific callback for a specific property.
listener.forget(<prop>)
Forgets all callbacks for a certain property.
listener.forget(null[, <callback>])
Forgets one or all generic callbacks. This will not delete any specific property callbacks. In other words, this is not a mechanism for clearing all callbacks of a listener.

callback
new, old, prop ⟶ nil
prop
string

Note that callbacks will run regardless of whether the new and old values are actually different. It is up to the user to compare the new value to the old one and possibly only take action when there is a meaningful difference.

Callbacks are internally stored as a map from property name to a set of callbacks. Therefore, registering the same callback on the same property more than once will have no effect; the callback will only be called once for every property change.

Note that one-time callbacks registered with {once: true} will generate a new wrapper function that removes itself before calling the actual callback. This has two implications:

This behaviour of one-time callbacks may change in the future and should not be relied on.

Additionally, the listener factory itself has the following method:

listener.raw
proxy → target
This static method can be used to retrieve the target object for a given listener proxy.

Note that callbacks will only trigger when the property is set via the proxy object. Changing the raw object directly will not trigger any callbacks as javascript provides no mechanism to detect such property changes on plain objects.