0

I'm really not sure how to word this issue but I will try my best.

I have a nested array:

const items = [
  {
    id: 1,
    name: "Test name",
    children: [
      {
        id: 5,
        name: "Test name 5",
        children: [
          {
            id: 6,
            name: "Test name 6",
            children: [],
          },
        ],
      },
    ],
  },
  {
    id: 8,
    name: "Test name 8",
    children: [
      {
        id: 9,
        name: "Test name 9",
        children: [],
      },
    ],
  },
];

and I have an array of indexes where to target and update

const keys = [0,0,0]

The array of indexes should target Test name 6

How can I update Test name 6 to something else?

p.s. items and keys are dynamic. there might be dozens of nested items or dozens of indexes in keys

0

3 Answers 3

1

You could reduce the indices and check the children property.

After getting the final object, just assign the value to the wanted property.

const
    getItem = (children, keys) => keys.reduce(
        ({ children = [] }, i) => children[i],
        { children }
    ),
    items = [{ id: 1, name: "Test name", children: [{ id: 5, name: "Test name 5", children: [{ id: 6, name: "Test name 6", children: [] }] }] }, { id: 8, name: "Test name 8", children: [{ id: 9, name: "Test name 9", children: [] }] }],
    keys = [0, 0, 0];
    
console.log(getItem(items, keys));

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

Comments

0

To update your nested array first you will first need to change it to a mutable variable, i.e. from a const to a let or var.

From there you can update the value with something like:

// Copy pasted data from your post
let items = [
  {
    id: 1,
    name: "Test name",
    children: [
      {
        id: 5,
        name: "Test name 5",
        children: [
          {
            id: 6,
            name: "Test name 6",
            children: [],
          },
        ],
      },
    ],
  },
  {
    id: 8,
    name: "Test name 8",
    children: [
      {
        id: 9,
        name: "Test name 9",
        children: [],
      },
    ],
  },
];

const keys = [0,0,0]

// <----------------- CODE BELOW ---------------->

// var to store item each time you dive deeper into the nested array
// initalize with the first item
let item = items[keys[0]].children;

// loop through each key
for(let i = 1; i < keys.length; i++){
  // if we are at the last key, set item equal to the item object
  if(i == keys.length-1){
    item = item[keys[i]];
  }
  // otherwise, set item equal to the item's children
  else{
    item = item[keys[i]].children
  }
}

// once item has been reached - all keys have been looped through - data can be minupulated
item.name = "new value"
// "Test name 6" has been updated to "new value"

emphasized text

Comments

0

In this scenario, I usually use a Map referencing the items within the nested arrays. For example:

const items = [
  {
    id: 1,
    name: "Test name",
    children: [
      {
        id: 5,
        name: "Test name 5",
        children: [
          {
            id: 6,
            name: "Test name 6",
            children: [],
          },
        ],
      },
    ],
  },
  {
    id: 8,
    name: "Test name 8",
    children: [
      {
        id: 9,
        name: "Test name 9",
        children: [],
      },
    ],
  },
];

const createItemsMap = items => {
  const m = new Map();
  
  (function _collect(items) {
    for (const item of items) {
      m.set(item.id, item);
      if (item.children) {
        _collect(item.children);
      }
    }
  })(items);
  
  return m;
}

const itemsMap = createItemsMap(items);

// modify item #6
itemsMap.get(6).name = "Modified name 6";

console.log("itemsMap.get(1) === items[0] is", itemsMap.get(1) === items[0]);
console.log(items);

With that map, modifying the items is simply a matter of doing this :

const keys = [1,5,6];

for (const key of keys)
  const item = itemsMap.get(key);

  // update item
  item.name = `Updated name ${key}`;
  item.newProp = 'New value!';
}

// ex: 
console.log(items[0]);
// {
//   id: 1,
//   name: "Updated name 1",
//   newProp: "New value!',
//   children: [
//     {
//       id: 5,
//       name: "Updated name 5",
//       newProps: "New value!",
//       children: [
//         {
//           id: 6,
//           name: "Updated name 6",
//           newProps: "New value!",
//           children: [],
//         },
//       ],
//     },
//   ],
// },

And a few more freebies :

// get all existing keys
const keys = Array.from(itemsMap.keys());

// check if an item exists
const exists3 = itemsMap.has(3);  // false
const exists5 = itemsMap.has(5);  // true

// adding new children
const newChild = { id: 3, name: "Test name 3", children: [] };
// ... add as child of 5
itemsMap.get(5).children.push(newChild); 
// ... add it to the map
itemsMap.set(newChild.id, newChild);  // that's it!

// remove an item
const removed = itemsMap.get(3);
// ... find if there is a parent...
const parent = Array.from(itemsMap.values()).find(item =>
  item.children.includes(removed)
);
if (parent) {
   // ... if there is a parent, remove the child
   parent.children = parent.children.filter(item => 
      item !== removed
   );
} else {
   // ... otherwise it is a root item, so remove it
   items = items.filter(item => item !== removed);
}
// ... remove from map
itemsMap.delete(removed.id);

Note: If items is modified directly (i.e. items are added or removed), then itemsMap needs to either be re-generated, or preferably updated. In any other case, both items and itemsMap reference to the same 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.