Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to subscribe to object changes?

Tags:

javascript

I wonder how to subscribe to the changes of a JavaScript object e.g. like Redux does. I read through a lot of JS documentations but I couldn't find a non-deprecated way to handle this problem (Object.protype.watch() as well as Object.observe() are deprecated). Moreover I read a few Stackoverflow questions regarding this topic but they are all at least 5 years old. To visualize my problem I'll show an example.

This could be an object I want to watch for:

const store = {
    anArray = [
    'Hi',
    'my',
    'name',
    'is'
  ]
}

.. and this a function which changes the store object:

function addAName() {
    store.anArray.push('Bob')
}

My goal in this example is to trigger the following function every time the store object changes

function storeChanged() {
    console.log('The store object has changed!')
}

Thank you in advance!

like image 330
Eyk Rehbein Avatar asked Apr 25 '18 11:04

Eyk Rehbein


People also ask

How can we prevent object modification?

To prevent modification of JavaScript objects, one of the techniques is to use Object. freeze() . Freezing an object does not allow new properties to be added to an object and prevents from removing or altering the existing properties.

What is watch in JavaScript?

The watch() method watches for a property to be assigned a value and runs a function when that occurs.

How do I watch for changes to an object in JavaScript?

Watch for Object Changes with JavaScript. 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.

How does the subscribe () method work in JavaScript?

The value that gets passed in to the subscribe () callback, form, is simply a JavaScript object. As the form values change, this same object structure will be passed into the subscription with the updated form values.

Is there a better way to subscribe to change events?

There might be a better way than subscribing to a change event (which usually can be an expensive operation as it could be called many times) Subject/BehaviorSubject allows you to both publish as well as listen to changes.

What happens when form values change in a subscription?

As the form values change, this same object structure will be passed into the subscription with the updated form values. We get the sessionStorage object from the browser, and we associate the form values object to a key in the storage, in this case 'form'.


3 Answers

Have you tried using Proxy from ECMA6? I think this is what you are looking for You only have to define a function as the set of the validator of the Proxy like this:

let validator = {
    set: function(target, key, value) {
        console.log(`The property ${key} has been updated with ${value}`);
        return true;
    }
};
let store = new Proxy({}, validator);
store.a = 'hello';
// console => The property a has been updated with hello
like image 64
Alejandro Riera Avatar answered Oct 21 '22 22:10

Alejandro Riera


You can use Object.defineproperty() to create reactive getters/setters. It has good browser support and looks handy.

function Store() {

  let array = [];

  Object.defineProperty(this, 'array', {
    get: function() {
      console.log('Get:', array);
      return array;
    },
    set: function(value) {
      array = value;
      console.log('Set:', array)
    }
  });


}

var store = new Store();
store.array; //Get: []
store.array = [11]; //Set: [11]
store.array.push(5) //Set: [11, 5]
store.array = store.array.concat(1, 2, 3) //Set: [11, 5, 1, 2, 3]
like image 3
soeik Avatar answered Oct 21 '22 22:10

soeik


To solve this problem without any indirections (in using object) you can use proxy.

By wrapping all objects with observalbe you can edit your store frealy and _base keeps track of which property has changed.

const observalbe = (target, callback, _base = []) => {
  for (const key in target) {
    if (typeof target[key] === 'object')
      target[key] = observalbe(target[key], callback, [..._base, key])
  }
  return new Proxy(target, {
    set(target, key, value) {
      if (typeof value === 'object') value = observalbe(value, callback, [..._base, key])
      callback([..._base, key], target[key] = value)
      return value
    }
  })
}

const a = observalbe({
  a: [1, 2, 3],
  b: { c: { d: 1 } }
}, (key, val) => {
  console.log(key, val);
})

a.a.push(1)

a.b.c.d = 1
a.b = {}
a.b.c = 1
like image 4
Maciej Kozieja Avatar answered Oct 21 '22 21:10

Maciej Kozieja