2

Consider the following data:

let data = [
    { foo: true, bar: [ 1, 2, 3 ] },
    { foo: true, bar: [ 8, 9,   ] }
];

I'm trying to push something to the nested bar array on index 1 using the spread syntax (...).

So the final array should become:

[
    { foo: true, bar: [ 1, 2, 3 ] },
    { foo: true, bar: [ 8, 9, 'new-item'  ] }
]

Normally, we'll just use push: data[1].bar.push(0), but I need a spread solution


I've tried to use this approach:
How to push new elements to a nested array of objects in JavaScript using spread syntax

data = [ ...data, {[1]: { ...data[1], bar: [ ...data[1].bar, 'new-item' ] } }] 

But this will append another object with a single key 1, it does not alter data[1].


Then, I've tried to use Object.assign() but again ended up with a new index:
Replace array entry with spread syntax in one line of code?

data = [ ...data, Object.assign({}, data[1], { bar }})

tl;dr, How do I append something to an array, part of an object, that's inside an array of objects, using the spread syntax?

Please link me to a duplicate, or provide a way to do this


Playground:

let data = [
    { foo: true, bar: [ 1, 2, 3 ] },
    { foo: true, bar: [ 8, 9 ] }
];

// 'Regular' push method
// data[1].bar.push(0);

// Using spread reassign
// data = [ ...data, {[1]: { ...data[1], bar: [ ...data[1].bar, 'new-item' ] } }] 

// Using Object.assign
data = [ ...data, Object.assign({}, data[1], {bar: [ 'new-item' ] } ) ];

console.log(data)

4
  • Im not posting an answer, but that seems to work : data = [ data[0], { ...data[1], bar: [ ...data[1].bar, 'new-item' ] } ] Commented Jan 19, 2023 at 16:19
  • This works fine @Foobar, but how would you re-write this if data has 100 items and you need to change index 42? Commented Jan 19, 2023 at 16:26
  • @0stone0 @Foobar's answer is close to my answer: simply replace the static ....data[1] with a ...data.slice(0, desired_index_to_edit) (& follow with a ...data.slice(desired_index_to_edit+1)) Commented Jan 19, 2023 at 16:27
  • May you work only on one item, and dont spread everthing: data[1] = { ...data[1], bar: [ ...data[1].bar, 'new-item' ] } So 1 can now easy be 42. Commented Jan 19, 2023 at 16:29

5 Answers 5

2

You could take an outer Object.assign with an array as target and an object with the index as key.

let
    data = [
        { foo: true, bar: [1, 2, 3] },
        { foo: true, bar: [8, 9] }
    ];

data = Object.assign(
    [...data],                            // target array
    { 1: {                                // array index as key
        ...data[1],
        bar: [...data[1].bar, 'new-item']
    } }
);

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

2 Comments

I wonder. why [...data] and not just data?
@Foobar, you could do that, but i would avoid to mutate the data.
1

You can use Object.assign on the array itself.

let data = [
    { foo: true, bar: [ 1, 2, 3 ] },
    { foo: true, bar: [ 8, 9,   ] }
];
data = Object.assign([...data], {1: { ...data[1], bar: [...data[1].bar, 'new-item']}});
console.log(data);

1 Comment

Thanks, +1. I'm sorry that Nina was 42 seconds faster. Will accept her answer if there are no shorter alternatives.
0

I don't think this is more readable than many other options open to you but this satisfies the requirement of "using object spread".

let data = [
  { foo: true, bar: [ 1, 2, 3 ] },
  { foo: true, bar: [ 8, 9,   ] },
  { foo: false, bar: [ ] }
];

let idx = 1;
let newData = [ 
  ...data.slice(0, idx), 
  { 
    ...data[idx], 
    bar: [ ...data[idx].bar, 'new-item' ]
  },
  ...data.slice(idx+1)
];

console.log(newData);

This will first take your data and cut the array up to the item you wish to replace (index 1). A new object follows, then the rest of the array (if any) follows.

2 Comments

Thanks, this is decent, but dont really like the 2 slice. The object assign seems like a more clean way of doing this.
Unless my benchmark is wrong, slicing twice like this is faster than the Object.assign(), though.
0

First, treat the array like an object with numbered keys, and use the spread operator and override the necessary index. Then, use Object.values() to treat it like an array.

let data = [
  { foo: true, bar: [ 1, 2, 3 ] },
  { foo: true, bar: [ 8, 9, ] }
]

data = Object.values({ ...data, 1: { ...data[1], bar: [ ...data[1].bar, 'new-item' ] } })

console.log(data)

In this particular case, if the index you need to alter is near the beginning of the array, you can also use an IIFE to allow for a destructuring approach, like this:

let data = [
  { foo: true, bar: [ 1, 2, 3 ] },
  { foo: true, bar: [ 8, 9, ] }
]

data = (([first, {bar, ...rest}]) => [first, {...rest, bar:[...bar, 'new-item']}])(data)

console.log(data)

Comments

0

You can just assign the first element index to the modified element that uses Array#map and the spread operator as follows:

const data = [
    { foo: true, bar: [ 1, 2, 3 ] },
    { foo: true, bar: [ 8, 9,   ] }
];

data[1] = [data[1]].map(({foo,bar}) => ({foo,bar:[...bar,"some new value"]}))[0];

console.log( data );

Comments

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.