- Observer extends
EventEmitter
- EventEmitter
- EventHandler
Observer extends EventEmitter
Observer that provides sync events when data is changed. For data-centric application this allows to build more flat architecture where different logical parts can subscribe to observer and do not need to interact between each other, by that decoupling logic, improving modularity. Data can be any complexity JSON, and provides specific path or simple query for partial paths using wildcard notation for subscribing to changes.
Extends: EventEmitter
Name | Type | Description |
---|---|---|
data | object | array |
Data that observer is modifying. This data should not be modified by application logic. |
new Observer([data]) (constructor)
.set([path], data)
.unset([path])
.patch([path], data)
.insert(path, data, [index])
.move(path, from, to)
.remove(path, [index])
.get([path]) ⇒ *
.clear()
.on(name, callback, [scope], [once]) ⇒ EventHandler
.once(name, callback, [scope]) ⇒ EventHandler
.emit(name, [...args])
.off([name], [callback], [scope])
[path:]set (path, value, old) (event)
[path:]unset (path, old) (event)
[path:]insert (path, value, index) (event)
[path:]move (path, value, from, to) (event)
[path:]remove (path, value, index) (event)
Param | Type | Description |
---|---|---|
[data] | object | array |
Object or an Array for initial data. Defaults to { }; |
Example
let planet = new Observer({ age: 4.543, population: 7.594 });
// get data
element.textContent = planet.get('population');
// know when data changes
planet.on('population:set', function (path, value) {
element.textContent = value;
});
// set data
planet.set('population', 7.595); // triggers "population:set" event
Example
// more complex example for data
let planets = new Observer({
earth: {
age: 4.543,
population: 7.594
},
mars: {
age: 4.603,
population: 0
}
});
// know when any planet population changes
// using a wildcard notation to match multiple paths
planets.on('*.population:set', function (path, population) {
const planet = path[0];
elements[planet].textContent = population;
});
// set data
planets.set('earth.population', 7.595); // triggers "*.population:set" event
Example
// list of tasks
let todos = new Observer([{
text: 'buy a milk',
complete: true
}, {
text: 'walk a dog'
}]);
// subscribe for a new tasks
todos.on('insert', (path, value, index) => {
if (path.length) return;
console.log(`new task "${value.text}" been added at position ${index}`);
});
// subscribe for a task completion state changes
todos.on('*.complete:set', (path, value) => {
console.log(`task "${todos.get(path[0] + '.text')}" has been marked "${(!value ? 'not ' : '') + 'complete'}"`);
});
// add another task
todos.insert('', { text: 'fix a fence' });
// complete a task
todos.set('1.complete', true);
Set data by a specific path. If in process of setting existing object values will be unset, it will emit unset
events with related paths. New and modified values will trigger set
events with related paths. If set is against an array and index is higher then length of an array, it will insert null's until set value and trigger insert
events.
Param | Type | Description |
---|---|---|
[path] | string | number |
Path in data to be set to. If path is not provided, it will set the root of observer. |
data | * |
Data to be set. |
Example
obj.set('position.x', 42);
obj.set('position', { x: 4, y: 2 });
Unset data by a specific path. It will emit unset
events with related paths. If path is not provided, it will reset root of data to empty object. If unset of an array item, it will additionally trigger move
and remove
events if necessary.
Param | Type | Description |
---|---|---|
[path] | string | number |
Path in data to be unset. If path is not provided, it will set root of observer to empty object. |
Example
obj.unset('position.z');
Patch data by a specific path. In process of setting, it will not unset values that are not provided in patch data. But still can trigger unset events if object is changed to something else, so it will emit unset
events with related paths. New and modified values will trigger set
events with related paths.
Param | Type | Description |
---|---|---|
[path] | string | number |
Path in data to be patched. If path is not provided, it will patch the root of observer. |
data | * |
Data for patching. |
Example
let obj = new Observer({ position: { x: 4, y: 2 } });
obj.patch('position', { z: 7 });
// will become { position: { x: 4, y: 2, z: 7 } }
Insert data by a specific path. Inserting new data will emit set
event, if any items were moved in array, they will emit move
event first.
Param | Type | Description |
---|---|---|
path | string | number |
Path in data to be inserted to. If path is empty string or null, it will insert in the root of observer if it is an array. |
data | * |
Data to be set. |
[index] | number |
Index within array to insert to. By default -1 (the end of an array). 0 - will insert in the beginning. Negative values will count from the end of an array. |
Example
const primes = new Observer([ 2, 5, 7 ]);
primes.insert('', 11);
primes.insert('', 3, 1); // we forgot prime number 3 which should be second in a list
Example
const planets = new Observer({
saturn: {
satellites: [ ]
}
});
obj.insert('saturn.satellites', 'rhea');
obj.insert('saturn.satellites', 'iapetus');
obj.insert('saturn.satellites', 'titan', 0); // insert in the beginning
Move item by a specific path. Moving item will emit move
event for affected items in arrays first, and then moved item it self. Indices support negative values, counting will be from the end then.
Param | Type | Description |
---|---|---|
path | string | number |
Path in data to be inserted to. If path is empty string or null, it will insert in the root of observer if it is an array. |
from | number |
Index from which item to be moved. |
to | number |
Index to which item to be moved. |
Example
satellites.move('', 1, 3); // from 1 to 3
satellites.move('', -1, 0); // from the end to the beginning
satellites.move('', 3, -1); // from 3 to the end
Remove item by a specific path. Removing item will emit unset
event for an affected item in arrays first, then move
event for affected items, and then remove
for it self. Indices support negative values, counting will be from the end then.
Param | Type | Description |
---|---|---|
path | string | number |
Path in data to be inserted to. If path is empty string or null, it will insert in the root of observer if it is an array. |
[index] | number |
Index from which item to be removed. By default removes from the end of an array. |
Example
planets.remove('', 8); // remove 9th item (sad Pluto)
Get data by a specific path. Returns raw data based on path. If path is not provided will return root data of observer. This data should not be modified by application logic, and is subject to change by obseerver functions.
Returns: *
- Data based on provided path.
Param | Type | Description |
---|---|---|
[path] | string | number |
Path of data to be returned. |
Example
let x = obj.get('position.x');
Example
const planets = new Observer([ 'mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune' ])
let planet = planets.get(2); // earth
Resets observer, its data to empty object and removes all subscribed events.
.on(name, callback, [scope], [once]) ⇒ EventHandler
Attach an event handler.
Overrides: on
Returns: EventHandler
- Object that can be used to manage the event.
Param | Type | Description |
---|---|---|
name | string |
Name of the event to bind the callback to. |
callback | function |
Function that is called when event is emitted. |
[scope] | object |
Object to use as 'this' when the event is emitted, defaults to current this. |
[once] | boolean |
Boolean to indicate if this event should emit only once. Defaults to false. |
Example
obj.on('event', function (a, b) {
console.log(a + b);
});
obj.emit('event', 4, 2);
.once(name, callback, [scope]) ⇒ EventHandler
Attach an event handler which will emit only once.
Returns: EventHandler
- Object that can be used to manage the event.
Param | Type | Description |
---|---|---|
name | string |
Name of the event to bind the callback to. |
callback | function |
Function that is called when event is emitted. |
[scope] | object |
Object to use as 'this' when the event is emitted, defaults to current this. |
Example
obj.once('event', function (a) {
console.log(a);
});
obj.emit('event', 4);
obj.emit('event', 2); // will not trigger
Emit the event by name and optional list of arguments.
Param | Type | Description |
---|---|---|
name | string |
Name of the event to bind the callback to. |
[...args] | * |
Arguments to be passed to event callbacks. |
Example
obj.emit('event', 'hello', 42);
Remove event handlers based on provided arguments.
Param | Type | Description |
---|---|---|
[name] | string |
Name of the events to remove. If not specified all events will be removed. |
[callback] | function |
Function that is used as callback. If not defined, then all events of specified name will be removed. |
[scope] | object |
Object that is used as a scope for event handlers. If not defined, then all events with matching name and callback function will be removed. |
Example
obj.off(); // removes all events
obj.off('event'); // removes all events named `event`.
obj.off(/input:\w+/); // removes all events with name matching regular expression
obj.off('event', fn); // removes events named `event` with `fn`
obj.off('event', fn, obj); // removes events named `event` with `fn` callback and `obj` as a scope.
Fired when value have been set/changed on a path. Path can be a specific or using a wildcard notation for broader matches. Also path can be omitted completely to match event for any changes.
Param | Type | Description |
---|---|---|
path | Array.<(string|number)> |
Path to the value changed as a mutable array of strings or numbers. Do not modify this array. |
value | * |
New value. |
old | * |
Old value. |
Example
// specific path
obj.on('earth.population:set', function (path, value, old) {
element.textContent = value;
});
Example
// using wildcard with partial path, which will match any changes
// where second level property name is `population`
obj.on('*.population:set', function (path, value, old) {
const planet = path[0];
elements[planet].textContent = value;
});
Example
const obj = new Observer({ position: { x: 0, y: 0, z: 0 } });
// using wildcard to match any axis change of a position object
obj.on('position.*:set', function (path, value, old) {
const axis = path[1];
setAxis(axis, value);
});
Example
obj.on('set', function (path, value, old) {
// any change of data will trigger this event
});
Fired when value have been unset on a path. Same rules apply as for set
event when defining path.
Param | Type | Description |
---|---|---|
path | Array.<(string|number)> |
Path to the value changed as a mutable array of strings or numbers. Do not modify this array. |
old | * |
Old value. |
Example
obj.on('earth.population:unset', function (path, old) {
console.log(`'earth.population' has been unset`);
});
Example
obj.on('*:unset', function (path) {
console.log(`planet '${path[0]}' has been unset`);
});
Example
obj.on('unset', function (path) {
console.log(`'${path.join('.')}' has been unset`);
});
Fired when value have been inserted on a path. Path can be a specific or using a wildcard notation for broader matches. Also path can be omitted completely to match event for any inserts.
Param | Type | Description |
---|---|---|
path | Array.<(string|number)> |
Path to the value changed as a mutable array of strings or numbers. Do not modify this array. |
value | * |
New value. |
index | number |
Index at which value was inserted. |
Example
// specific path
obj.on('saturn.satellites:insert', function (path, value, index) {
console.log(`satelite "${value}" has been added to saturn at position ${index}`);
});
Example
// using wildcard with partial path, which will match any changes
// where second level property name is `satellites`
obj.on('*.satellites:insert', function (path, value, index) {
console.log(`satellite "${value}" of planet "${path[0]}", has been inserted at ${index}`);
});
Example
obj.on('insert', function (path, value, index) {
// any insert of data will trigger this event
});
Fired when value have been moved in an array. Path can be a specific or using a wildcard notation for broader matches. Also path can be omitted completely to match event for any changes.
Param | Type | Description |
---|---|---|
path | Array.<(string|number)> |
Path to the value changed as a mutable array of strings or numbers. Do not modify this array. |
value | * |
Value item moved. |
from | number |
Index from which value was moved. |
to | number |
Index to which value was moved. |
Example
// specific path
obj.on('saturn.satellites:move', function (path, value, from, to) {
});
Example
// using wildcard with partial path, which will match any changes
// where second level property name is `satellites`
obj.on('*.satellites:move', function (path, value, from, to) {
console.log(`satellite "${value}" of planet "${path[0]}", has been moved from ${from} to ${to}`);
});
Example
obj.on('move', function (path, value, from, to) {
// any move of data will trigger this event
});
Fired when value have been removed from an array. Path can be a specific or using a wildcard notation for broader matches. Also path can be omitted completely to match event for any changes.
Param | Type | Description |
---|---|---|
path | Array.<(string|number)> |
Path to the value changed as a mutable array of strings or numbers. Do not modify this array. |
value | * |
Old value. |
index | number |
Index from which value was removed. |
Example
// specific path
obj.on('planets:remove', function (path, value, index) {
// oh Pluto!
});
Example
// using wildcard with partial path, which will match any changes
// where second level property name is `satellites`
obj.on('*.satellites:remove', function (path, value, index) {
console.log(`satellite "${value}" of planet "${path[0]}", has been removed from ${index} position`);
});
Example
obj.on('remove', function (path, value, index) {
// any remove of data will trigger this event
});
Provides ability to subscribe and emit events in sync manner. Each subscribtion (on, once) returns EventHandler that simplifies callbacks management.
See: https://github.com/Maksims/mr-EventEmitter/blob/main/API.md#EventEmitter
Constructed by EventEmitter and provides easy ability to manage event.
See: https://github.com/Maksims/mr-EventEmitter/blob/main/API.md#EventHandler