Accessing parent properties on arrays (grandparent)
Nice lib! I just have a quick question of something i was not able to do. Imagine you have at some point a node like this:
{
id: "1",
name: "Peter",
books: [
{name: "Funny book"} ,
{name: "Sad book"}
]
}
When the current value is the node {name:"funny Book"} accessing the parent gets the parent array and not the parent node. Is there a way to access the "id" property from the children?
📝It is possible to do it with the original object using getNodeByPath() but id is not there from the begining, I create it while I traverse the tree so i need a reference to the parent node that has been already extended
📝Also no way to get it from the array, because when the value is the array itself, key and parent are null
Hi! Thanks for the feedback. I agree that being able to traverse up the tree is a nice feature. I intend to add it but can't give any timeframe atm.
In the meantime I believe your use case should be achievable like this (stackblitz):
const { traverse, getNodeByPath } = require('object-traversal');
const root = {
// Commenting out id from the original example, since you say we are adding it dynamically
// id: '1',
name: 'Peter',
books: [{ name: 'Funny book' }, { name: 'Sad book' }],
};
const isBookRegex = /books\.\d+$/;
console.log('root before: ', root);
traverse(root, ({ parent, key, value, meta }) => {
// for example sake, we are adding id to any object which contains the 'books' property
if (key === 'books') {
parent.id = 1;
}
// if we are accessing a book, add the ownerId into it
const isBook = isBookRegex.test(meta.nodePath);
if (isBook) {
const grandParentPath = meta.nodePath.split('.').slice(0, -2).join('.');
const grandParent = getNodeByPath(root, grandParentPath);
value.ownerId = grandParent.id; // value is book
}
});
console.log('root after: ', root);
This outputs:
root before: {
name: 'Peter',
books: [ { name: 'Funny book' }, { name: 'Sad book' } ]
}
root after: {
name: 'Peter',
books: [
{ name: 'Funny book', ownerId: 1 },
{ name: 'Sad book', ownerId: 1 }
],
id: 1
}
Also note that in your example when value is the array itself, parent and key are not null. Instead the parent is the root object and the key is 'books' (as demonstrated in the stackblitz).
Hope it helps!
Thanks for the answer!
When I've tried the getNodeByPath() it was getting the object before it was updated, but I guess it is because i'm using immer like this:
return produce(root, (draft) => traverse(draft, myFunction));
I think I was unable to pass draft as a second parameter to MyFunction() but I guess I can just put the function directly there.
Will check it in more detail 👀, thanks!
Btw before being able to go to grandparent etc I would add access to parent when Array.isArray(value) . Right now on those levels where we are an array, there is no direct access to parent, they are null
A really simple use case, imagine building a deepSort(root, fn) that will use object-traversal to traverse and sort every array it finds using a fn.
Btw before being able to go to grandparent etc I would add access to parent when
Array.isArray(value). Right now on those levels where we are an array, there is no direct access to parent, they arenull
There's nothing stopping you from accessing parent when value is an array. You can see this by running node array-parent.js in the stackblitz I provided. It is likely immer is what is messing with your implementation.
The only time parent is null, is when value is the root itself.
If I'm missing something, please provide a stackblitz example. Good luck!
Thanks for the examples. So weird, i'm not able to reproduce it... but i'm using your lib a lot :) If i end up again facing the issue I will build a stackblitz to show you the issue. Thanks!
Keeping this open as a reminder for the upward traversal feature.