Home > Software engineering >  Javascript spread on array index to 'push' new item to nested array
Javascript spread on array index to 'push' new item to nested array

Time:01-20

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)

CodePudding user response:

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; }

CodePudding user response:

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);

CodePudding user response:

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.

CodePudding user response:

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)

CodePudding user response:

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"]}));

console.log( data );

  • Related