Reputation: 345
I've got two javascript objects, i want to change the structure of one of them and merge the other one into the first one
I've tied using loops but it doesn't seem to be the best way to do it
My first object is called 'navbar'
navbar:
[ { Id: 7,
ParentId: null,
Name: 'Home',
Slug: '/',
Priority: 1,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Custom Plus' },
{ Id: 15,
ParentId: 14,
Name: 'About Us',
Slug: 'about-us',
Priority: 1,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Custom Plus' },
{ Id: 8,
ParentId: null,
Name: 'New Cars',
Slug: 'new-cars',
Priority: 2,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Custom' },
{ Id: 14,
ParentId: null,
Name: 'More',
Slug: 'more',
Priority: 8,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Placeholder' } ]
And my second one is called newvehicles:
newvehicles:
[ { Id: 5,
VehicleType: 'Car',
MakeId: 5,
MakeName: 'Make',
MakeSlug: 'make',
ModelId: 13,
ModelName: 'All-New Car',
ModelSlug: 'all-new-car',
Prefix: null,
Suffix: null,
Priority: 1,
Redirect: null,
Image:
'http://xxxx.jpg',
Assets: null,
Markup: null },
{ Id: 6,
VehicleType: 'Car',
MakeId: 5,
MakeName: 'Car',
MakeSlug: 'Car',
ModelId: 8,
ModelName: 'Car',
ModelSlug: 'Car',
Prefix: null,
Suffix: null,
Priority: 2,
Redirect: null,
Image:
'http://xxxx.jpg',
Assets: null,
Markup: null } ]
What i want to achieve is for the object of newvehicles to be pushed into the navbar as a child of 'new-cars' and also to go through the navbar and move anything that has a ParentId of not null to be moved into that parent object as a child
I'm currently using a for loop to do some of the changes:
for (var i = 0; i < navigation.navbar.length; i++) {
var obj = navigation.navbar[i];
if (obj.Slug == 'new-cars') {
obj.child = newvehicles;
}
}
But i'm looking for the output to be something like this:
navbar:
[ { Id: 7,
ParentId: null,
Name: 'Home',
Slug: '/',
Priority: 1,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Custom Plus' },
{ Id: 8,
ParentId: null,
Name: 'New Cars',
Slug: 'new-cars',
Priority: 2,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Custom'.
child : [ { Id: 5,
VehicleType: 'Car',
MakeId: 5,
MakeName: 'Make',
MakeSlug: 'make',
ModelId: 13,
ModelName: 'All-New Car',
ModelSlug: 'all-new-car',
Prefix: null,
Suffix: null,
Priority: 1,
Redirect: null,
Image:
'http://xxxx.jpg',
Assets: null,
Markup: null },
{ Id: 6,
VehicleType: 'Car',
MakeId: 5,
MakeName: 'Car',
MakeSlug: 'Car',
ModelId: 8,
ModelName: 'Car',
ModelSlug: 'Car',
Prefix: null,
Suffix: null,
Priority: 2,
Redirect: null,
Image:
'http://xxxx.jpg',
Assets: null,
Markup: null } ] },
{ Id: 14,
ParentId: null,
Name: 'More',
Slug: 'more',
Priority: 8,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Placeholder',
child: { Id: 15,
ParentId: 14,
Name: 'About Us',
Slug: 'about-us',
Priority: 1,
MenuDisplay: true,
MenuSubDisplay: false,
MobileDisplay: false,
PageType: 'Custom Plus' } } ]
Upvotes: 1
Views: 624
Reputation: 5753
The looping logic you presented already seems to be meeting your goal regarding appending the cars logic. However, implicit in your request is that there will only be one entry with a slug of 'new-cars'. If that is true, then consider:
navbar.find(item => item.Slug == 'new-cars').child = newvehicles;
Regarding the non-null parentId, you can:
Here is the code:
for (var i = navbar.length - 1; i >= 0; i--) {
var obj = navbar[i];
let parent = navbar.find(item => item.Id == obj.ParentId);
if (parent) {
parent.child = navbar.splice(i,1);
}
}
In both cases, prefix 'navigation.' to 'navbar' and/or 'newvehicles' as necessary.
Edit: To deal with the OP's comment below requesting the ability to associate multiple children with a parent.
In order for the 'child' property to allow multiple children, we would turn it into an array. So we would first check to see if the 'child' property exists in the parent. If not, we create it and set it equal to an empty array. Then, we push the spliced child object inside the loop:
for (var i = navbar.length - 1; i >= 0; i--) {
var obj = navbar[i];
let parent = navbar.find(item => item.Id == obj.ParentId);
if (parent) {
if (!parent.child)
parent.child = [];
parent.child.push(navbar.splice(i,1)[0]);
}
}
Consider changing the name of 'child' to 'children' for your needs.
Also, be aware that all of this will only work for one level. If you need multi-level nesting of parents to children, then a simple loop will not suffice. You may want to create a different question in that case.
Upvotes: 2
Reputation: 3529
Here is a solution based on Lodash-fp
This a variant of Lodash library which allows a full functional programming style and makes this kind of tasks so much easier (don't hesitate if you wish some explanations)
const parentsPartition = _.partition(['ParentId', null], navbar);
const vehicleHierarchy = _.map(
vehicle => {
const children = _.filter(['ParentId', vehicle.Id], parentsPartition[1]);
return _.cond([
[_.isEmpty, _.constant(vehicle)],
[_.stubTrue, _.set('children', _, vehicle)]
])(children);
},
_.concat(parentsPartition[0], newvehicles)
);
And here the result (sorry, my screen isn't high enough to full print)
Upvotes: 0