0

I'm trying to work with data that resembles this kind of object:

const sampleData = {
  coyotes: '',
  armadillos: false,
  wombats: [''],
  geckos: 0,
  dogs: {
    beagle: '',
    bulldog: ''
  },
  wolves: [
    {
      type: '',
      color: '',
      range: '',
      status: {
        endangered: true,
        protected: false
      }
    }
  ],
  cats: {}
}

As you can see, it's got a mix of different JavaScript types: strings, Booleans, numbers, etc.

When something in the form changes, I need to compare the old object with the changed object and check for equality, among other things. To determine if something has changed, I use this recursive function:

export const getChangedValues = (initialValues, values) => {
  return Object
    .entries(values)
    .reduce((acc, [key, value]) => {
      const hasChanged = initialValues[key] !== value
      if (hasChanged) {
        acc[key] = value
      }
      return acc
    }, {})
}

However, when I compare new objects with old using lodash isEqual, I get a false for the number values because our fields save numbers as strings (I have no control over that).

So, I use this to convert JUST the numbers in the object to strings, because I need to leave everything else alone (especially the Booleans):

export const convertValuesToStrings = (obj) => {
  return _.cloneDeepWith(obj, value => {
    return (_.isNumber(value)) ? _.toString(value) : undefined
  })
}

This works perfectly in converting numbers to strings, but I'm getting a false positive for the nested objects. After running the string converter and then checking if there has been a change, it's also returning objects, even if their underlying data hasn't changed.

I'm still learning the more complex areas of JavaScript, like recursion. Can anyone spot what I'm missing here?

Bottom line is that I need to recursively compare two objects after converting any number values (and ONLY number values) to strings. :)

patrickrso
  • 23
  • 3
  • I think you will find [this Q&A](https://stackoverflow.com/a/33233053/633183) to be helpful. if you have any follow-up questions, I'm here to help – Mulan Feb 04 '22 at 16:23

1 Answers1

-1

To keep this simple, have you tried comparing the objects using JSON.stringify()?

if(JSON.stringify(oldObject) === JSON.stringify(newObject)) {
   console.log('objects are basically equal' ) 
}

This approach is pretty simple for fully comparing a deep object. This cannot be modified too much but solves the problem using a tested built in function and let's you focus on writing the actual application.

Silvan Bregy
  • 2,544
  • 1
  • 8
  • 21
  • I did try JSON.stringify() initially, but it returned false positives when used to check equality. For example, the code below returns false because for some reason it detects a difference in the nested objects, even when there isn't one. const equal = _.isEqual(JSON.stringify(initialValues), JSON.stringify(currFormValues)) – patrickrso Feb 04 '22 at 17:23
  • Actually, I got this to do what I needed it to do by using a combination of JSON.stringify and my convertValues ToStrings utility method. For example: JSON.stringify(convertValuesToStrings(initialValues)). Using this maintains consistent value types for both comparison objects, though it still feel a bit heavy and messy. – patrickrso Feb 04 '22 at 19:21