h_a_l_a_s
h_a_l_a_s

Reputation: 66

JavaScript modifying an object inside the array

I am having a problem trying to modify the name of a nested object using map function and to return the modified object.

I was trying the approach with double forEach loop but I am also failing with that.

const myObject = [{
    id: 1,
    childrenList: [{
        id: 1,
        name: 'foo',
      },
      {
        id: 2,
        name: 'foo',
      },
    ],
  },
  {
    id: 2,
    childrenList: [{
        id: 1,
        name: 'foo',
      },
      {
        id: 2,
        name: 'foo',
      },
    ],
  },
];

const alteredObject = myObject.map((thisChild) => {
  if (thisChild.id === 1) {
    thisChild.childrenList.map((item) => {
      if (item.id === 1) {
        return {
          ...item,
          name: 'bar',
        };
      }
      return item;
    });
  }
  return thisChild;
});

console.log(alteredObject);

//trying to get:
alteredObject = [
    {
      id: 1,
      childrenList: [
        {
          id: 1,
          name: 'bar',
        },
        {
          id: 2,
          name: 'foo',
        },
      ],
    },
    {
      id: 2,
      childrenList: [
        {
          id: 1,
          name: 'foo',
        },
        {
          id: 2,
          name: 'foo',
        },
      ],
    },
  ];

This is the first time I am trying to modify a nested object. Normally with an array of objects, I am not having any issue so I am not sure what I am doing wrong

Upvotes: 1

Views: 354

Answers (6)

PeterKA
PeterKA

Reputation: 24648

You're missing a return; you have to return the modified thisChild as {...thisChild, childrenList:modifiedChildrenList}

const myObject = [{ id: 1, childrenList: [{ id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, { id: 2, childrenList: [{ id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, ];

const alteredObject = myObject.map((thisChild) => {
  if (thisChild.id === 1) {
    return {...thisChild,childrenList:thisChild.childrenList.map((item) => {
        if (item.id === 1) {
          return {
            ...item,
            name: 'bar',
          };
        }
        return item;
      })
    }
  }
  return thisChild;
});

console.log(alteredObject);

Upvotes: 0

IISkullsII
IISkullsII

Reputation: 725

As you already know, Array.prototype.map() returns a new Array containing the modified version.
In your first map function myObject.map(), you aren't saving the second map function modified result as the childrenList content.
therefore no changes would be stored in the first map function and the result would have no changes.

const alteredObject = myObject.map((thisChild) => {
  if (thisChild.id === 1) {
    // Here you should save the result of this 
    // Array.prototype.map() Function as the new 'thisChild.childrenList'
    thisChild.childrenList = thisChild.childrenList.map((item) => {
      // ...
    });
  }
  return thisChild;
});

const myObject = [{
    id: 1,
    childrenList: [{
        id: 1,
        name: 'foo',
      },
      {
        id: 2,
        name: 'foo',
      },
    ],
  },
  {
    id: 2,
    childrenList: [{
        id: 1,
        name: 'foo',
      },
      {
        id: 2,
        name: 'foo',
      },
    ],
  },
];

const alteredObject = myObject.map((thisChild) => {
  if (thisChild.id === 1) {
    thisChild.childrenList = thisChild.childrenList.map((item) => {
      if (item.id === 1) {
        return {
          ...item,
          name: 'bar',
        };
      }
      return item;
    });
  }
  return thisChild;
});

console.log(alteredObject);

Upvotes: 1

mgm793
mgm793

Reputation: 2066

You only need to update the children with your map and it will work. Like this:

  const myObject = [
    {
      id: 1,
      childrenList: [
        {
          id: 1,
          name: "foo"
        },
        {
          id: 2,
          name: "foo"
        }
      ]
    },
    {
      id: 2,
      childrenList: [
        {
          id: 1,
          name: "foo"
        },
        {
          id: 2,
          name: "foo"
        }
      ]
    }
  ];

  const alteredObject = myObject.map((thisChild) => {
    if (thisChild.id === 1) {
      thisChild.childrenList = thisChild.childrenList.map((item) => {
        if (item.id === 1) {
          return {
            ...item,
            name: "bar"
          };
        }
        return item;
      });
    }
    return thisChild;
  });
  console.log(alteredObject);
And if you want to do it with forEach:

  const myObject = [
    {
      id: 1,
      childrenList: [
        {
          id: 1,
          name: "foo"
        },
        {
          id: 2,
          name: "foo"
        }
      ]
    },
    {
      id: 2,
      childrenList: [
        {
          id: 1,
          name: "foo"
        },
        {
          id: 2,
          name: "foo"
        }
      ]
    }
  ];

  const alteredObject = myObject.map((thisChild) => {
    if (thisChild.id === 1) {
      thisChild.childrenList.forEach((item) => {
        if (item.id === 1) {
          item.name = 'bar';
        }
        return item;
      });
    }
    return thisChild;
  });
  console.log(alteredObject);

If you can modify your object then you can do it with two forEach:

  const myObject = [
    {
      id: 1,
      childrenList: [
        {
          id: 1,
          name: "foo"
        },
        {
          id: 2,
          name: "foo"
        }
      ]
    },
    {
      id: 2,
      childrenList: [
        {
          id: 1,
          name: "foo"
        },
        {
          id: 2,
          name: "foo"
        }
      ]
    }
  ];

 myObject.forEach((thisChild) => {
    if (thisChild.id === 1) {
      thisChild.childrenList.forEach((item) => {
        if (item.id === 1) {
          item.name = 'bar';
        }
        return item;
      });
    }
  });
  console.log(myObject);

Upvotes: 1

raz-ezra
raz-ezra

Reputation: 559

The array map method creates a new array (mdn), so the parent object alteredObject still has the childrenList key pointing to the original array. To solve this, you can add assignment of the new array to the key:

thisChild.childrenList = thisChild.childrenList.map(...)

This way, the key will point to the newly created array

Upvotes: 0

Terry Lennox
Terry Lennox

Reputation: 30725

This can be done with a couple of map calls, we'll alter the name value if the firstChild id is 1 and the leaf object id is also 1:

const myObject = [ { id: 1, childrenList: [ { id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, { id: 2, childrenList: [ { id: 1, name: 'foo', }, { id: 2, name: 'foo', }, ], }, ]; 

const alteredObject = myObject.map((thisChild) => {
  return { ...thisChild, childrenList: thisChild.childrenList.map(({id, name}) => { 
      return { id, name: (thisChild.id === 1 && id === 1) ? 'bar': name };
  })}
});
  
  
console.log(alteredObject)
.as-console-wrapper { max-height: 100% !important; }

Upvotes: 0

nem0z
nem0z

Reputation: 1123

You can use this code :

const myObject = [
    {
    id: 1,
    childrenList: [
        { id: 1, name: 'foo', },
        { id: 2, name: 'foo', },
    ],
  },
  {
    id: 2,
    childrenList: [
        { id: 1, name: 'foo', },
        { id: 2, name: 'foo', },
    ],
  },
];

let result = myObject.map(
    el => el.id === 1 ? 
    {...el, childrenList: el.childrenList.map(child => child.id === 1 ? {...child, name: 'bar'} : child)} 
    : el
);

console.log(result);

Upvotes: 0

Related Questions