'Updating values of multidimensional object in JS

I have been reading different post about this, but in the end the result its the same, I cannot update the values of the object working with. I am sending the key/value pair as if they were completely independent. I hope I can explain clearly: So the object I get from BE looks like this:

    {
        id: 3,
        name: 'something',
        display: true,
        type: 'customer',
        preferences: {
            food: 'meat',
            allergies: {
                key: 'value',
            },
        
        }

    }

So what did I do so far? Since this is a bigger object, with other nested ones (I keep it simple here, there is no need to paste everything) I had to filter some of them in order to keep the code organised. That is why I have started doing like this:

  1. render everything that does not have an object as a value
                        {Object.entries(parendtObj)
                            .filter(([key, value]) => {
                                return typeof value !== 'object'
                            })
                            .map(([key, value], index) => {
                                return (
                                            <Fragment key={index}>
                                                <RHField
                                                    type="text"
                                                    label={key}
                                                    name={key}
                                                    onChange={e =>
                                                        setValue({
                                                            ...parendtObj,
                                                            [key]: e.target.value,
                                                        })
                                                    }
                                                />
                                            </Fragment>
                                );
                            })}

OK, everything good until here. So what I did after this? tried to do the same but instead of taking only the parentOjb, I would go one step further:

                        {Object.entries(parendtObj.preferences)
                            .filter(([key, value]) => {
                                return typeof value !== 'object'
                            })
                            .map(([key, value], index) => {
                                return (
                                            <Fragment key={index}>
                                                <RHField
                                                    type="text"
                                                    label={key}
                                                    name={key}
                                                    onChange={e =>
                                                        setValue({
                                                            ...parendtObj,
                                                            preferences: {
                                                            [key]: e.target.value,
                                                           },
                                                        })
                                                    }
                                                />
                                            </Fragment>
                                );
                            })}

But what happens in this case is that I cannot update the values of the keys inside "preferences", instead they are sent as new key/value pairs.

I guess many will point out here

                                     onChange={e =>
                                                        setValue({
                                                            ...parendtObj,
                                                            preferences: {
                                                            [key]: e.target.value,
                                                           },
                                                        })
                                                    }

Well, I lost track of how many different ways I have tried there, the issue is still the same, they dont get updated like in the first snippet I pasted. What is it I am doing wrong? Is there any easier way to update the values of an object like this? Would you recommend to flatten the object? or maybe filter the object and use the prototype.flat against the array?



Solution 1:[1]

It's hard to tell what exactly you are looking for and what end result supposed to be, but it sounds like you could achieve what you need via recursive function:

const data = {
    id: 3,
    name: 'something',
    display: true,
    type: 'customer',
    preferences: {
        food: 'meat',
        allergies: {
            key: 'value',
        },

    }

}

function updateObject(obj, level = 0 /* how many levels of nested objects */, target = {})
{
  let index = -1;
  for(let key in obj)
  {
    index++;
    if (obj[key] && typeof obj[key] == "object")
    {
      target[key] = updateObject(obj[key], ++level);
      continue;
    }
    if (!level) /* root of the main object */
    {
      target[key] = `<Fragment key={index}>
                      <RHField
                          type="text"
                          label="{key}"
                          name="{key}"
                          onChange={e =>
                              setValue({...obj,
                                  [key]: e.target.value,
                              })
                          }
                      />
                  </Fragment>`
    }
    else /* nested objects */
    {
      target[key] = obj[key];
    }
  }
  return target;
}
console.log(updateObject(data));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 vanowm