Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern to check if a JavaScript object has changed

I get from the server a list of objects

[{name:'test01', age:10},{name:'test02', age:20},{name:'test03', age:30}]

I load them into html controls for the user to edit. Then there is a button to bulk save the entire list back to the database.

Instead of sending the whole list I only want to send the subset of objects that were changed.

It can be any number of items in the array. I want to do something similar to frameworks like Angular that mark an object property like "pristine" when no change has been done to it. Then use that flag to only post to the server the items that are not "pristine", the ones that were modified.

like image 929
Ro. Avatar asked Jul 09 '16 01:07

Ro.


People also ask

How do you know if an object has changed position?

changes position requires a point of reference. An object changes position if it moves relative to a reference point. To visualize this, picture yourself competing in a 100-m dash.

How do you check if an element is in an object JavaScript?

JavaScript provides you with three common ways to check if a property exists in an object: Use the hasOwnProperty() method. Use the in operator. Compare property with undefined .


2 Answers

Here is a function down below that will return an array of changed objects when supplied with an old array of objects and a new array of objects:

getChanges = function(oldArray, newArray) {
  var changes, i, item, j, len;
  if (JSON.stringify(oldArray) === JSON.stringify(newArray)) {
    return false;
  }
  changes = [];
  for (i = j = 0, len = newArray.length; j < len; i = ++j) {
    item = newArray[i];
    if (JSON.stringify(item) !== JSON.stringify(oldArray[i])) {
      changes.push(item);
    }
  }
  return changes;
};

For Example:

var older = [{name:'test01', age:10},{name:'test02', age:20},{name:'test03', age:30}]
var newer = [{name:'test01', age:10},{name:'test02', age:20},{name:'test03', age:20}]
getChanges(older, newer)

(Notice test03's age is now 20) Will return

[{name:'test03', age:20}]

You would simply have to export the full list of edited values client side, compare it with the old list, and then send the list of changes off to the server.

Hope this helps!

like image 55
nshoo Avatar answered Oct 02 '22 13:10

nshoo


Here are a few ideas.

  1. Use a framework. You spoke of Angular.

  2. Use Proxies, though Internet Explorer has no support for it.

  3. Instead of using classic properties, maybe use Object.defineProperty's set/get to achieve some kind of change tracking.

  4. Use getter/setting functions to store data instead of properties: getName() and setName() for example. Though this the older way of doing what defineProperty now does.

  5. Whenever you bind your data to your form elements, set a special property that indicates if the property has changed. Something like __hasChanged. Set to true if any property on the object changes.

  6. The old school bruteforce way: keep your original list of data that came from the server, deep copy it into another list, bind your form controls to the new list, then when the user clicks submit, compare the objects in the original list to the objects in the new list, plucking out the changed ones as you go. Probably the easiest, but not necessarily the cleanest.

  7. A different take on #6: Attach a special property to each object that always returns the original version of the object:

    var myData = [{name: "Larry", age: 47}];
    var dataWithCopyOfSelf = myData.map(function(data) {  
        Object.assign({}, data, { original: data });
    });
    // now bind your form to dataWithCopyOfSelf.

Of course, this solution assumes a few things: (1) that your objects are flat and simple since Object.assign() doesn't deep copy, (2) that your original data set will never be changed, and (3) that nothing ever touches the contents of original.

There are a multitude of solutions out there.

like image 35
kevin628 Avatar answered Oct 02 '22 14:10

kevin628