0

I have a scenario where I want to change properties of object in an array. That array is wrapped inside another object.


const defaultData = {
  title: "Title",
  subtitle: "Subtitle",
  books: [
    {
      bookId: "1",
      imageSrc:
        "any.png",
      name: "Issue",
      userOwnsData: true,
      panelsCollected: 0,
      totalPanels: 123,
      link: "https://google.com",
    },
  ],
  bgColor: "black",
};

When I spread it like this:

{...defaultData, ...defaultData.books[0], panelsCollected:123} //previously it was 0

then it adds another extra object to parent object but not update it inside first index of books array

How can I just change that panelsCollected property without disturbing whole structure as we are using typescript.

Edit:

We can change it directly accessing the property too as we know index but that comes with a side effect of manipulating original dataset also which we should avoid and only copy needs to be updated.

Thanks

6
  • Why do you need to spread that object out to update one value? Why not just defaultData.books[0].panelsCollected = 123? Commented Nov 25, 2022 at 16:38
  • @Andy Yes it will change only one property but what about other data we need. How can i get same structure with just one property being changed. Commented Nov 25, 2022 at 16:45
  • What other data? You should probably expand your question code to be representative of the problem you're actually facing. Commented Nov 25, 2022 at 16:55
  • @Andy I have an object named defaultData and i want to return same structure of it but just one property needs to be updated which was panelsCollected. I tried my best to clear everything in question. Commented Nov 25, 2022 at 17:12
  • 1
    If you know the index of the object in books you can just update that property value as I suggested. You don't necessarily need to create a brand new object by spreading the old one out. Commented Nov 25, 2022 at 17:16

2 Answers 2

1

When spreading an object with nested properties with the intention of updating specific properties, think of it in two steps:

  1. Spread the original object to copy it (...)
  2. Redefine the new property values after the spread object

In your example we are doing the following:

  • Duplicating defaultData and assigning an updated books property (to be defined in the next step)
  • Duplicating the first book (defaultData.books[0]) and assigning an updated panelsCollected property to it. Then overwriting the existing books property with this updated array item

The result is as follows:

const defaultData = {
  title: "Title",
  subtitle: "Subtitle",
  books: [
    {
      bookId: "1",
      imageSrc:
        "any.png",
      name: "Issue",
      userOwnsData: true,
      panelsCollected: 0,
      totalPanels: 123,
      link: "https://google.com",
    },
  ],
  bgColor: "black",
};

const newBook = {
  ...defaultData,
  books: [
    {
      ...defaultData.books[0],
      panelsCollected: 123
    }
  ]
}

console.log(newBook)
/*
{
  title: "Title",
  subtitle: "Subtitle",
  books: [
    {
      bookId: "1",
      imageSrc:
        "any.png",
      name: "Issue",
      userOwnsData: true,
      panelsCollected: 123,
      totalPanels: 123,
      link: "https://google.com",
    },
  ],
  bgColor: "black",
};
*/

If for example the books property was 1000 items long, you would instead use have to find the specific book in your array using an array method (e.g. find / findIndex) and update it, e.g.

const bookToUpdateIndex = defaultData.books.findIndex(book => book.bookId === '1')

const updatedBooks = [...defaultData.books]
updatedBooks[bookToUpdateIndex] = {
  ...updatedBooks[bookToUpdateIndex],
  panelsCollected: 123
}

const newBook = {
  ...defaultData,
  books: updatedBooks
}
Sign up to request clarification or add additional context in comments.

2 Comments

findIndex(book => bookId === '1') should be findIndex(book => book.bookId === '1')
And also this answer also mutates the original object. @SulemanAhmad which isn't what you wanted.
0

Instead of using find and the spread syntax an alternative approach (but not necessarily the most performant) might be to copy the object by stringifying it, and then reparsing that string. And then you can just update the object at the index you need.

const defaultData={title:"Title",subtitle:"Subtitle",books:[{bookId:"1",imageSrc:"any.png",name:"Issue",userOwnsData:!0,panelsCollected:0,totalPanels:123,link:"https://google.com"}],bgColor:"black"};

const copy = JSON.parse(JSON.stringify(defaultData));
copy.books[0].panelsCollected = 123;

console.log(defaultData);
console.log(copy);

3 Comments

const newBook = { ...defaultData, books: [ { ...defaultData.books[0], panelsCollected: 123 } ] }
I was looking for this part which does not mutate original object.
But it only works if you have one book. @SulemanAhmad. I was indicating the second part of that answer which would mutate the original object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.