8

I am trying to detect changes in an array of objects using JavaScript proxies.

Problem: Any time there is a change in array like deletion or insertion, i want to get that deleted or inserted item.

Current Code

target = [{ id: 1, a: 'a' }, { id: 2, a: 'b' }];
proxy = new Proxy(target, {
    get: function (target, property: string, receiver) {
        if (property === 'pop') {
            console.log('deleted object', target[target.length - 1]);
        }
        console.log('get', property);
        // property is index in this case
        return target[property];
    },
    set: function (target, property, value, receiver) {
        console.log('set', property, 'to', value);
        target[property] = value;
        // you have to return true to accept the changes
        return true;
    }
});

Current Thoughts: I did a little workaround to get the deleted item from array but it only works for pop() method because it deletes the last item from array. But i need a way to get the changes even it is made using splice method or push or pop.

Thanks.

[Update] Solution I Found:

https://github.com/ElliotNB/observable-slim I used this library to detect changes in array, i am able to detect changes on nested properties inside array too. This is exactly what i was looking for.

The reason i am using this library is because it's using proxies.

8
  • If you want to capture splice, then you'll have to write a handler for splice just like you did for pop - look at the arguments to see what will be deleted and then and store the data before it's deleted. Rinse and repeat for every method you want to handle. Commented Feb 28, 2019 at 11:05
  • I tried but i didn't get the splice arguments inside this proxy handler. Commented Feb 28, 2019 at 11:05
  • npmjs.com/package/underscore-observe There was this library to observe changes in the array but this is using Array.observe() which is now Obsolete. and proxies are alternative for Array.observe so there should be a way to detect these changes using proxies. Commented Feb 28, 2019 at 11:11
  • @JoharZaman is Proxy important to you ? or any other way will be fine also ? Commented Feb 28, 2019 at 11:12
  • 1
    You shouldn't be tracking method calls at all, you only should be tracking indexed elements. Commented Feb 28, 2019 at 11:15

2 Answers 2

0

I recommend not to expose actual traget on getter. You can create a wrapper function to support the cutosom modifier. Check out the below example.

const target = [
  { id: 1, a: "a" },
  { id: 2, a: "b" },
];
const proxy = new Proxy(target, {
  get: function (target, property, receiver) {
    switch (property) {
      case "push":
      case "pop":
      case "slice":
      case "splice":
        return (...arg) => target[property](...arg);
    }
    throw Error("Not supported yet");
  },
});

proxy.push({ id: 3, a: "c" })
console.log(proxy.pop())
console.log(proxy.slice(1,2))
console.log(proxy.pop())

Sign up to request clarification or add additional context in comments.

1 Comment

This is pretty much no longer an array. Neither proxy.length nor proxy[0] work.
0

Refer the below code for reference :

function observeArrayChanges(array, callback) {
  // Create a proxy for the array
  const arrayProxy = new Proxy(array, {
    // The set handler is called whenever there's an insertion or deletion
    set(target, property, value) {
      const oldValue = target[property];

      // Perform the actual insertion or deletion
      const result = Reflect.set(target, property, value);

      // Check if it's an insertion or deletion
      if (oldValue !== value) {
        // Call the callback with information about the change
        callback({
          type: oldValue === undefined ? 'insert' : 'delete',
          item: oldValue === undefined ? value : oldValue,
        });
      }

      // Return the result of the set operation
      return result;
    },
  });

  return arrayProxy;
}

// Example usage:

const myArray = observeArrayChanges(
  [{ id: 1, a: 'a' }, { id: 2, a: 'b' }],
  (change) => {
    console.log(`Change type: ${change.type}`);
    console.log(`Changed item: `, change.item);
  }
);

// Insert an item
myArray.push({ id: 3, a: 'c' });

// Delete an item
//delete myArray[0];
console.log(myArray.pop())
console.log(myArray.slice(1,2))
console.log(myArray.pop())
console.log(myArray.length)
console.log(JSON.stringify(myArray))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.