we want to convert Below JSON to Parent-Child Relation for a tree view structure, based on parent Link and Display Order.
if parent link is empty it is parent
if parent link exist it should add as a child
items should sort based on display order
[{
"ParentLink":{ },
"Id":1,
"Title":"Home ITSD test new",
"Url":{
"Description":"#",
"Url":"https://technologies.sharepoint.com/"
},
"DisplayOrder":1,
"IsActive":true,
"ID":1},{
"ParentLink":{
},
"Id":2,
"Title":"Link6",
"Url":{
"Description":"#",
"Url":"https://technologies.sharepoint.com/"
},
"DisplayOrder":2,
"IsActive":true,
"ID":2},{"ParentLink":{
"Title":"Link6"
},
"Id":3,
"Title":"link7",
"Url":{
"Description":"#",
"Url":"https://technologies.sharepoint.com/"
},
"DisplayOrder":21,
"IsActive":true,
"ID":3},{
"ParentLink":{
"Title":"Link6"
},"Id":4,
"Title":"link8",
"Url":{
"Description":"#",
"Url":"https://technologies.sharepoint.com/"
},
"DisplayOrder":22,
"IsActive":true,
"ID":4},{
"ParentLink":{
"Title":"link8"
},
"Id":5,
"Title":"link9",
"Url":{
"Description":"#",
"Url":"https://technologies.sharepoint.com/"
},
"DisplayOrder":221,
"IsActive":true,
"ID":5}]
is there any other libraries already available or any easy way to do so
While Title and ParentLink.Title do not have matching values, you could take both values as lower case letters and use both to generate a tree by iterating the given array and use an object for assigning nodes and children.
For the wanted order, I suggest to sort the data in advance and take the nodes as the actual order for generating the tree. This is easier than to sort later only parts.
Just wondering, why has the data two id properties?
var data = [{ ParentLink: {}, Id: 1, Title: "Home ITSD test new", Url: { Description: "#", Url: "https://technologies.sharepoint.com/" }, DisplayOrder: 1, IsActive: true, ID: 1 }, { ParentLink: {}, Id: 2, Title: "Link6", Url: { Description: "#", Url: "https://technologies.sharepoint.com/" }, DisplayOrder: 2, IsActive: true, ID: 2 }, { ParentLink: { Title: "Link6" }, Id: 3, Title: "link7", Url: { Description: "#", Url: "https://technologies.sharepoint.com/" }, DisplayOrder: 21, IsActive: true, ID: 3 }, { ParentLink: { Title: "Link6" }, Id: 4, Title: "link8", Url: { Description: "#", Url: "https://technologies.sharepoint.com/" }, DisplayOrder: 22, IsActive: true, ID: 4 }, { ParentLink: { Title: "link8" }, Id: 5, Title: "link9", Url: { Description: "#", Url: "https://technologies.sharepoint.com/" }, DisplayOrder: 221, IsActive: true, ID: 5 }],
tree = function (data, root) {
var r = [], o = {};
data.forEach(function (a) {
var id = a.Title.toLowerCase(),
parent = a.ParentLink && a.ParentLink.Title && a.ParentLink.Title.toLowerCase();
a.children = o[id] && o[id].children;
o[id] = a;
if (parent === root) {
r.push(a);
} else {
o[parent] = o[parent] || {};
o[parent].children = o[parent].children || [];
o[parent].children.push(a);
}
});
return r;
}(data, undefined);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I have the following array
[{ id: 1,
type: 'video',
image: null,
url: 'https://www.youtube.com/1'
},
{ id: 2,
type: 'video',
image: null,
url: 'https://www.youtube.com/2'
},
{ id: 3,
type: 'image',
image: 'https://example-1.url.webp'
},
{ id: 4,
type: 'image',
image: 'https://example-2.url.jpg',
},
{ id: 5,
type: 'video',
image: 'https://www.youtube.com/2',
}
]
I am already filtering all the items who are not webp format and the image is null
const galleryFilter = gallery.filter(
(item) => item?.image?.indexOf("webp") === -1 || item?.image === null
);
As you can see there are 2 items (id 2 and id 5 ) with the same url, how can i also filter the item duplicated with the same url in the galleryFilter method ?
you can append another filter function to filter by image url, (I have added another object into your data set id: 6)
var gallery = [{ id: 1,
type: 'video',
image: null,
url: 'https://www.youtube.com/1'
},
{ id: 2,
type: 'video',
image: null,
url: 'https://www.youtube.com/2'
},
{ id: 3,
type: 'image',
image: 'https://example-1.url.webp'
},
{ id: 4,
type: 'image',
image: 'https://example-2.url.jpg',
},
{ id: 5,
type: 'video',
image: 'https://www.youtube.com/2',
},
{ id: 6,
type: 'video',
image: 'https://www.youtube.com/2',
}
];
var galleryFilter = gallery.filter( (item) => item?.image?.indexOf("webp") === -1 || item?.image !== null ).filter((item, i, arr) => i == arr.findIndex(e => e.image == item.image));
console.log(galleryFilter);
Use filter and keep track of images with Set
const gallery = [
{ id: 1, type: "video", image: null, url: "https://www.youtube.com/1" },
{ id: 2, type: "video", image: null, url: "https://www.youtube.com/2" },
{ id: 3, type: "image", image: "https://example-1.url.webp" },
{ id: 4, type: "image", image: "https://example-2.url.jpg" },
{ id: 5, type: "video", image: "https://www.youtube.com/2" },
];
const set = new Set();
const galleryFilter = gallery.filter((item) => {
if (
(item?.image?.includes("webp") || item?.image === null) &&
!set.has(item?.image)
) {
set.add(item.image);
return true;
}
});
console.log(galleryFilter)
I'm migrating from python to javascript. So now, I'm working on a react project where I need to convert some unix-like path to json. Actually, there aren't folders, they're list of categories joined by "/".
Here is what I have:
Category Model holds the categories and the slug play as categories list joined by "/"
const categorySchema = mongoose.Schema({
name: { type: String, required: true },
slug: { type: String, unique: true }, // Repr the route
image: { type: String },
topLevel: { type: String },
description: { type: String },
}, { timestamps: true });
One representation of a category is like this:
{
name: "embedded",
slug: "/electronics/embedded",
image: "/some/image.png",
topLevel: "electronics",
description: "This is a brief description."
}
Now what I want is when I have a list of object like this
[
{
id: 1,
name: "embedded",
slug: "/electronics/embedded",
image: "/some/image.png",
topLevel: "electronics",
description: "This is a brief description."
},
{
id: 2,
name:"electonics",
slug:"/electronics",
topLevel: "electronics",
image: "/some/image.png",
description: "..."
},
{
id: 3,
name: "house",
slug: "/house",
topLevel: "house",
image: "/some/image.png",
description: "...",
}
]
to end up having from the slug which are the unix-like paths as:
[
{
id: 2,
node: "electronics",
children: [{
id: 1,
node: "embedded",
children: [],
}],
},
{
id: 3,
node: "house",
children: []
},
]
This is what I'm really struggling trying to have. If someone can help, you are more than welcome.
Based on yesterday's comment on whether I've tried something yet or not, I have basically come up with something but still not perfect because I didn't walk deep the whole tree.
Based on the input data and the type of output I want to have, this is my first trial:
function listToTree(list) {
var node,
i,
roots = [];
for (i = 0; i < list.length; i += 1) {
node = list[i];
var slugList = node.slug.split("/").filter((x) => x !== "");
var children = [];
if (slugList.length > 1) {
var parent = slugList.shift();
var parentNode = {
node: parent,
id: node.id,
children: [],
};
roots.push(parentNode);
for (var j = 0; j < slugList.length; j++) {
var child = {
id: node.id,
node: slugList[j],
children: [],
};
children.push(child);
}
roots[i].children = [...children];
} else {
roots.push({
node: node.topLevel,
id: node.id,
children: [],
});
}
}
return roots;
}
The output:
const roots = listToTree(exampleData);
console.log(roots[0]);
{
node: 'electronics',
id: 1,
children: [ { id: 1, node: 'embedded', children: [] } ]
}
So, I still need some help and to be honest this answer here, not yet perfect, was inspired by the answered made by Halcyon in here
data=[
{
id: 1,
name: "Model",
type: "directory",
path: "/path/to/folder",
children: [
{
id: 2,
name: "model.yaml",
type: "file",
path: "../../storage/model.yaml",
},
],
},
{
id: 3,
name: "Inventory",
type: "directory",
path: "/path/to/folder",
children: [
{
id: 4,
name: "inventory.yaml",
type: "file",
path: "../../storage/inventory.yaml",
},
],
},
{
id: 5,
name: "UI",
type: "directory",
path: "/path/to/folder",
children: [
{
id: 6,
name: "elements",
type: "directory",
path: "../../storage",
},
{
id: 7,
name: "viewmodel",
type: "directory",
path: "../../storage",
},
{
id: 8,
name: "i18n",
type: "directory",
path: "../../storage",
},
{
id: 9,
name: "index.template.html",
type: "file",
path: "../../storage/index.template.html",
},
],
},
{
id: 10,
name: "DeviceConnector",
type: "directory",
children: [],
},
];
function getParent(data, id) {
for (let i = 0; i < data.length; i++) {
if (data[i].id === id) {
return data;
} else if (data[i].children && data[i].children.length) {
return data[i].children;
} else if (data[i].children && data[i].children.length) {
getParent(data[i].children, id);
}
}
}
I would to make a recursive search for the object's parent array using for loop. My problem is that the loop is stopping when finding the first children occurence. Looking for a way to fix the function and make the work of it possible on any nested level.
What I'm trying to do is by calling, for example getParent(data,4), to get a parent array with one element of id = 4.
You could store the result of a recursive call and if the value is truthy, you could exit the loop with the found array.
function getParent(data, wanted) {
for (const { id, children } of data) {
if (id === wanted) return data;
const temp = children && getParent(children, wanted);
if (temp) return temp;
}
}
I'm receiving a JSON from a Laravel API in this way:
[
{
"id":48,
"parentid":0,
"title":"Item 1",
"child_content":[
{
"id":49,
"parentid":48,
"title":"Itema 1.1",
},
{
"id":52,
"parentid":48,
"title":"Item 1.2",
}
]
},
{
"id":58,
"parentid":0,
"title":"Item 2",
"child_content":[
{
"id":59,
"parentid":58,
"title":"Itema 2.1",
},
{
"id":60,
"parentid":58,
"title":"Item 2.2",
}
]
}
]
and what I need is change the JSON into this:
{
"data":
[
{
"data":
{
"id":68,
"parentid":0,
"title":"Item 1"
},
"children":
[
{
"data":
{
"id":69,
"parentid":68,
"title":"Item 1.1"
},
},
{
"data":
{
"id":69,
"parentid":68,
"title":"Item 1.2"
}
}
]
}
]
}
I've been dealing with this... but I'm not able to find the way to do this properly...
How can I do this in PHP or Javascript / TypeScript (Angular 2).
Thank you in advance.
This should achieve your goal. Basically I'm just grabbing child_content, renaming it to children and copying the 3 other attributes. The children.map iteration is putting the existing data inside an object with a key of data:
const input = [{"id":48,"parentid":0,"title":"Item 1","child_content":[{"id":49,"parentid":48,"title":"Itema 1.1"},{"id":52,"parentid":48,"title":"Item 1.2"}]},{"id":58,"parentid":0,"title":"Item 2","child_content":[{"id":59,"parentid":58,"title":"Itema 2.1"},{"id":60,"parentid":58,"title":"Item 2.2"}]}]
const output = {
data: input.map((data) => {
const {
child_content: children,
id,
parentId,
title,
} = data;
return {
id,
parentId,
title,
children: children.map(data => ({data})),
};
})
}
console.log(output);
You can use JavaScript Array.prototype.map():
var json = [{"id": 48,"parentid": 0,"title": "Item 1","child_content": [{"id": 49,"parentid": 48,"title": "Itema 1.1",}, {"id": 52,"parentid": 48,"title": "Item 1.2",}]}, {"id": 58,"parentid": 0,"title": "Item 2","child_content": [{"id": 59,"parentid": 58,"title": "Itema 2.1",}, {"id": 60,"parentid": 58,"title": "Item 2.2",}]}],
result = {
data: json.map(function (item) {
return {
data: {
id: item.id,
parentid: item.parentid,
title: item.title
},
children: item.child_content.map(function (childItem) {
return {
data: {
id: childItem.id,
parentid: childItem.parentid,
title: childItem.title
}
}
})
};
})
};
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Assuming that the differences in the two datasets are due to copy/paste from different datasets, you can use the array map method to transform the data for you.
map works by iterating through each item of an array, and allows you to return a new item in the shape which you'd like.
var input = [{"id":48,"parentid":0,"title":"Item 1","child_content":[{"id":49,"parentid":48,"title":"Itema 1.1"},{"id":52,"parentid":48,"title":"Item 1.2"}]},{"id":58,"parentid":0,"title":"Item 2","child_content":[{"id":59,"parentid":58,"title":"Itema 2.1"},{"id":60,"parentid":58,"title":"Item 2.2"}]}];
var output = {
data: input.map(function(parent) {
// return a new object which contains the properties which you need
return {
data: {
id: parent.id,
parentid: parent.parentid,
title: parent.title
},
// children is an array, so we can use map again to transform them
children: parent.child_content.map(function(child) {
return {
data: {
id: child.id,
parentid: parent.id,
title: child.title
}
};
})
}
})
}
console.log(output);
You could convert the structure without mutating the original object with iterating and recursive calls of the convert function.
It works for any depth.
function convert(o) {
var temp = { data: {} };
Object.keys(o).forEach(function (k) {
if (k === 'child_content') {
temp.children = o[k].map(convert);
} else {
temp.data[k] = o[k];
}
});
return temp;
}
var data = [{ id: 48, parentid: 0, title: "Item 1", child_content: [{ id: 49, parentid: 48, title: "Itema 1.1" }, { id: 52, parentid: 48, title: "Item 1.2" }] }, { id: 58, parentid: 0, title: "Item 2", child_content: [{ id: 59, parentid: 58, title: "Itema 2.1" }, { id: 60, parentid: 58, title: "Item 2.2" }] }],
result = { data: data.map(convert) };
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ok, what I finally did is maybe not too much elegant... but it works, probably I should create a recursive function to manage different nested levels. I took the #RobM solution and replicated the children functionality at the second level like this:
convert(input)
{
const output =
{
data: input.map((data) =>
{
const { children: children } = data;
delete data.children;
return {
data,
children: children.map(data =>
{
const { children: children } = data;
delete data.children;
return {
data,
children: children.map(data => ({data})),
};
}),
};
})
}
return output.data;
}
Below are two JSON arrays. I want to get delta data (compare the two datasets and return elements that don't appear in both sets).
var data1 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" }
];
var data2 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" },
{ id: 3, name: "HR" },
{ id: 4, name: "finance" }
];
expected output:
var Result = [
{ id: 3, name: "HR" },
{ id: 4, name: "finance" }
];
I have tried this but didn't have any luck:
$.grep(data2, function (el) {
if ($.inArray(el, data1) == -1)
diff.push([el, IDl]);
});
You are close, the problem is you need to do a deep compare of your objects. inArray will only do a shallow compare. The following code will do a deep compare by checking equality of id and name. Also, it allows jQuery.grep to build the resulting array so you do not need to do this manually.
var data1 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" }
];
var data2 = [
{ id: 1, name: "Normal" },
{ id: 2, name: "Admin" },
{ id: 3, name: "HR" },
{ id: 4, name: "finance" }
];
function compare(data1, data2) {
return $.grep(data2, function(el) {
return !data1.some(function(elToCompare) {
return elToCompare.id === el.id && elToCompare.name === el.name;
});
});
}
$("#output").text(JSON.stringify(compare(data1, data2)));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div id="output"></div>