Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
object-observer
Advanced tools
object-observer utility provides simple means to (deeply) observe specified object/array changes; implemented via native Proxy; changes delivered in a synchronous way
object-observer
Starting with 6.0.0
this package will be relocated to @gullerya/object-observer
, please follow up there.
object-observer
provides a deep observation of a changes performed on an object/array graph.
Main aspects and features:
Observable
configuration; more details hereobserver
configuration; more details hereObservable
s
Array
mutation methods supported: pop
, push
, shift
, unshift
, reverse
, sort
, fill
, splice
, copyWithin
TypedArray
mutation methods supported: reverse
, sort
, fill
, set
, copyWithin
Map
, WeakMap
, Set
, WeakSet
(set
, delete
) etc are not observed (see this issue for more details)Date
Supported: 71+ | 65+ | 79+ | 12.1 | 12.0.0+
Performance report can be found here.
Changelog is here.
For a preview/playground you are welcome to:
Use regular npm install object-observer --save-prod
to use the library from your local environment.
ES module:
import { Observable } from 'object-observer';
CJS flavor:
const { Observable } = require('object-observer');
Huge thanks to seidelmartin providing the CJS build while greatly improving the build code overall along the way!
CDN (most suggested, when possible):
import { Observable } from 'https://libs.gullerya.com/object-observer/x.y.z/object-observer.min.js';
Replace the
x.y.z
with the desired version, one of the listed in the changelog.
CDN features:
Full details about CDN usage and example are found here.
Library implements Observable
API as it is defined here.
There is also a 'DOM-like' API flavor - constructable ObjectObserver
.
This API is resonating with DOM's MutationObserver
, ResizeObserver
etc from the syntax perspective.
Under the hood it uses the same Observable
mechanics.
Read docs about this API flavor here.
object-observer
is cross-instance operable.
Observables created by different instances of the library will still be detected correctly as such and handled correctly by any of the instances.
Security policy is described here. If/when any concern raised, please follow the process.
const
order = { type: 'book', pid: 102, ammount: 5, remark: 'remove me' },
observableOrder = Observable.from(order);
Observable.observe(observableOrder, changes => {
changes.forEach(change => {
console.log(change);
});
});
observableOrder.ammount = 7;
// { type: 'update', path: ['ammount'], value: 7, oldValue: 5, object: observableOrder }
observableOrder.address = {
street: 'Str 75',
apt: 29
};
// { type: "insert", path: ['address'], value: { ... }, object: observableOrder }
observableOrder.address.apt = 30;
// { type: "update", path: ['address','apt'], value: 30, oldValue: 29, object: observableOrder.address }
delete observableOrder.remark;
// { type: "delete", path: ['remark'], oldValue: 'remove me', object: observableOrder }
Object.assign(observableOrder, { amount: 1, remark: 'less is more' }, { async: true });
// - by default the changes below would be delivered in a separate callback
// - due to async use, they are delivered as a batch in a single callback
// { type: 'update', path: ['ammount'], value: 1, oldValue: 7, object: observableOrder }
// { type: 'insert', path: ['remark'], value: 'less is more', object: observableOrder }
let a = [ 1, 2, 3, 4, 5 ],
observableA = Observable.from(a);
Observable.observe(observableA, changes => {
changes.forEach(change => {
console.log(change);
});
});
// observableA = [ 1, 2, 3, 4, 5 ]
observableA.pop();
// { type: 'delete', path: [4], value: undefined, oldValue: 5, object: observableA }
// now observableA = [ 1, 2, 3, 4 ]
// following operation will cause a single callback to the observer with an array of 2 changes in it)
observableA.push('a', 'b');
// { type: 'insert', path: [4], value: 'a', oldValue: undefined, object: observableA }
// { type: 'insert', path: [5], value: 'b', oldValue: undefined, object: observableA }
// now observableA = [1, 2, 3, 4, 'a', 'b']
observableA.shift();
// { type: 'delete', path: [0] value: undefined, oldValue: 1, object: observableA }
// now observableA = [ 2, 3, 4, 'a', 'b' ]
// following operation will cause a single callback to the observer with an array of 2 changes in it)
observableA.unshift('x', 'y');
// { type: 'insert', path: [0], value: 'x', oldValue: undefined, object: observableA }
// { type: 'insert', path: [1], value: 'y', oldValue: undefined, object: observableA }
// now observableA = [ 2, 3, 4, 'a', 'b' ]
observableA.reverse();
// { type: 'reverse', path: [], object: observableA } (see below and exampe of this event for nested array)
// now observableA = [ 'b', 'a', 4, 3, 2 ]
observableA.sort();
// { type: 'shuffle', path: [], object: observableA } (see below and exampe of this event for nested array)
// observableA = [ 2, 3, 4, 'a', 'b' ]
observableA.fill(0, 0, 1);
// { type: 'update', path: [0], value: 0, oldValue: 2, object: observableA }
// observableA = [ 0, 3, 4, 'a', 'b' ]
// the following operation will cause a single callback to the observer with an array of 2 changes in it)
observableA.splice(0, 1, 'x', 'y');
// { type: 'update', path: [0], value: 'x', oldValue: 0, object: observableA }
// { type: 'insert', path: [1], value: 'y', oldValue: undefined, object: observableA }
let customer = { orders: [ ... ] },
oCustomer = Observable.from(customer);
// sorting the orders array, pay attention to the path in the event
oCustomer.orders.sort();
// { type: 'shuffle', path: ['orders'], object: oCustomer.orders }
oCustomer.orders.reverse();
// { type: 'reverse', path: ['orders'], object: oCustomer.orders }
Arrays notes: Some of array operations are effectively moving/reindexing the whole array (shift, unshift, splice, reverse, sort). In cases of massive changes touching presumably the whole array I took a pessimistic approach with a special non-detailed events: 'reverse' for
reverse
, 'shuffle' forsort
. The rest of these methods I'm handling in an optimistic way delivering the changes that are directly related to the method invocation, while leaving out the implicit outcomes like reindexing of the rest of the Array.
object-observer
allows to filter the events delivered to each callback/listener by an optional configuration object passed to the observe
API.
In the examples below assume that
callback = changes => {...}
.
let user = {
firstName: 'Aya',
lastName: 'Guller',
address: {
city: 'of mountaineers',
street: 'of the top ridges',
block: 123,
extra: {
data: {}
}
}
},
oUser = Observable.from(user);
// path
//
// going to observe ONLY the changes of 'firstName'
Observable.observe(oUser, callback, {path: 'firstName'});
// going to observe ONLY the changes of 'address.city'
Observable.observe(oUser, callback, {path: 'address.city'});
// pathsOf
//
// going to observe the changes of 'address' own properties ('city', 'block') but not else
Observable.observe(oUser, callback, {pathsOf: 'address'});
// here we'll be notified on changes of
// address.city
// address.extra
// pathsFrom
//
// going to observe the changes from 'address' and deeper
Observable.observe(oUser, callback, {pathsFrom: 'address'});
// here we'll be notified on changes of
// address
// address.city
// address.extra
// address.extra.data
FAQs
object-observer utility provides simple means to (deeply) observe specified object/array changes; implemented via native Proxy; changes delivered in a synchronous way
We found that object-observer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.