What is the best way to effectively handle the proxying of objects across multiple levels?

As illustrated in a Stack Overflow thread, utilizing Proxy objects is an effective method for monitoring changes in an object.

But what if you need to monitor changes in subobjects? In such cases, you will also have to proxy those subobjects.

I am currently working with code that automates this process - ensuring that any attempted property setting triggers the wrapping of the value in a proxy. This functionality allows us to take action whenever any value changes.

function createProxiedObject(objToProxy) {
  return new Proxy(objToProxy, {
    set: function (target, key, value) {
    //proxy nested objects
    if (value !== null && typeof value === 'object') {
      value = createProxiedObject(value);
    }
    target[key.toString()] = value;

    handleProxiedObjectChange();
  });

While this approach works effectively, there is one scenario where it can cause issues:

function ensureObjectHasProperty(object, key, default) {
  if (object[key] !== null) {
    // some validation occurs here
    return object[key];
  } else {
    return default;
  }
}

...

proxiedObject = somethingThatCreatesAProxiedObject(someValue);
proxiedObject[someProperty] = ensureObjectHasProperty(proxiedObject, someProperty, defaultValue)

In this situation, the value under someProperty (which is already proxied) may inadvertently get reassigned to the proxied object, resulting in double-wrapping. Consequently, the handleProxiedObjectChange method may be triggered multiple times with each change in the object.

To prevent this issue, one solution could be to avoid assigning anything to the proxied object unless it's truly new. However, given that the problem has already occurred, there is a risk of it happening again in the future. How can I modify the set function to prevent rewrapping objects that are already proxied? Alternatively, is there a more efficient way to monitor an object so that handleProxiedObjectChange is invoked whenever the object or any of its subobjects undergo a change?

Answer №1

After following the advice of @ExperiencedExplorer, I implemented a solution using a WeakSet to prevent wrapping a proxy within another proxy:

const proxiedItems = new WeakSet();

...

function createProxiedItem(itemToProxy) {
  // Make sure items are deeply proxied recursively
  for (let x in itemToProxy) {
    subItem = itemToProxy[x];
    if (subItem !== null && typeof subItem === 'object' && !proxiedItems.has(subItem)) {
      itemToProxy[x] = createProxiedItem(subItem);
    }
  }

  let proxiedItem = new Proxy(itemToProxy, {
    set: function (target, key, value) {
      // Adding a check - only call handleProxiedItemChange if there's actually a change
      if (_.isEqual(target[key.toString()], value)) {
        return true;
      }

      // Proxy nested items
      if (value !== null && typeof value === 'object' && !proxiedItems.has(value)) {
        value = createProxiedItem(value);
      }
      target[key.toString()] = value;

      handleProxiedItemChange();
  });
  proxiedItems.add(proxiedItem);
  return proxiedItem;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The touch events are not detected on Pixi.js when buttons are placed on a stage that has been both scaled and

Currently, I am developing a game using pixi js. In order to ensure that the game appears consistent on all screens, I have implemented the following scaling logic: this.scale = Math.max(this.viewWidth, this.viewHeight) / (2048 * this.ratio); Additionall ...

When the page is refreshed, the route fails to load the data

My Vue.JS website is quite simple, utilizing VueX and Vue-Router. I have defined two routes: '#/' and '#/account/' These routes are filled with components from .vue files, loaded dynamically upon page load using http-vue-loader (to avo ...

Trying to enter the function, but it exits without executing

I'm facing an issue with my function that involves making multiple calls to an observer. I need the function to wait until all the calls are complete before returning. I attempted putting the return statement inside the subscribe method, but it result ...

Is there a way to first run my validate function and then proceed with sending my AJAX request upon clicking a button?

Hey there! I've got a dynamic table generated from a database. You can check out the table. I have all the necessary code in place, but what I really need is to ensure proper timing of execution for specific actions: 1) Verify if all mandatory fields ...

React.js router - struggles to clean up unsightly query parameters in the URL

I've been trying to eliminate the query string by following this solution: var { Router, Route, IndexRoute, IndexLink, Link } = ReactRouter; var createHashHistory = History.createHashHistory; var history = createHashHistory({queryKey: false} ...

While executing a jssor code in SP 2007, IE experiences freezing issues

I've integrated a jssor slider with vertical navigation (without jQuery) into a Sharepoint 2007 page using CEWP. All the image links have been replaced with images stored in the SP image library, and the jssor.slider.min.js file has been uploaded to t ...

Conceal the current component prior to displaying the component associated with Navlink in React Router

Currently, I am in the process of developing a single-page web application using React routing. My goal is to hide the current component before rendering the next component when a NavLink is clicked, similar to how <a href="someLink"> works in HTML. ...

Guide on navigating through various HTML pages with distinct parameters using Node.js (Express server)

Seeking assistance with a Node.js server that receives an ID as a query parameter. Each time a client connects with different parameters, I aim to serve them a unique HTML page containing a simple UI with 2 dynamic arrays. Everything seems to be working co ...

Move the dist folder to the libs directory using webpack

I am interested in achieving the following task: After successfully using gulp for copying libraries, I added the below code to my tasks: gulp.task('copy:libs', function() { return gulp .src(npmdist(), { base: paths.base.node.dir }) . ...

Incorporate a fresh label for a function utilizing AngularJS

I want to insert a new HTML tag with an event attached to it. Here is an example of what I am trying to achieve: <html ng-app="module"> <head> <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script&g ...

Navigate to the following div, navigate back to the previous div

I am attempting to implement a div navigation system with next/previous buttons. Despite searching extensively on Google, I have not found the exact solution I am looking for. First and foremost, I want to maintain the integrity of my html structure. < ...

Press the button to duplicate the cell column separated by commas

In my HTML table, there is a specific column filled with container numbers that I want to copy to the clipboard when a button is clicked. The column has the class ".container" Here is the code I have been working on. HTML: <button onclick="copyToC ...

How to Establish an Angular Global Variable

What is the process for establishing a global variable in Angular? I have established a variable within a service, entered a value in the login component, and attempted to access this variable from another component. However, I noticed that the value res ...

Displaying items as objects in search results in Kendo Angular's auto complete feature

Seeking assistance with implementing Kendo Angular's auto complete widget using server filtering. Following the service call, the popup displays [object Object] and the count of these matches the results retrieved from the server. Could someone kindly ...

Avoid API calls by using connect-history-api-fallback

I have implemented the connect-history-api-fallback along with the page.js router. page('/', index); page('/about', about); page(); function index() { console.log("viewing index"); } function about() { console.log("viewing ...

Transforming encoded information into a text format and then reversing the process

I am facing an issue with storing encrypted data in a string format. I have tried using the TextEncoder method but it seems to be creating strings with different bytes compared to the original ArrayBuffer. Here is the line causing the problem: const str ...

Leveraging $http and $q in an Angular configuration with a service/provider

My goal is to load specific configurations for each controller in the app.config section. Each controller requires a distinct set of data, but these sets are not mutually exclusive. I am struggling to find a solution to this issue. .config(['$routePr ...

Can Angular i18n facilitate language switching?

My objective is to switch the language from English (United States) to Indonesia using a button. View Source Code The issue is that the tutorial does not cover how to implement the language change feature. Why opt for Angular i18n over a custom helper? ...

Error: Attempted to submit an invalid or unexpected input token

I want to display my ship registration number from the database in an AJAX response. I am using a method to send my field and then show the ship registration number in another function. Here is the code snippet that I have debugged: show_name(2d1c9a71586 ...

Having difficulty accessing the value of a table td element in HTML using a jQuery selector

When creating a table, I utilize ng-repeat to generate table rows. Whenever the dropdown changes, a function is triggered which applies certain conditions. Based on these conditions, an object is added to an array that is bound to a scope variable. Here i ...