Create nested html list using JSON array object - javascript

I have a Json object with parent node. The parent node can also be an individual node in the main array object.
[
{ "id": 1, "title": "A-Menu", "parent": null },
{ "id": 2, "title": "B-Menu", "parent": {
"id": 1, "title": "A-Menu", "parent": null }
},
{ "id": 3, "title": "C-Menu", "parent": {
"id": 2, "title": "B-Menu", "parent": {
"id": 1, "title": "A-Menu", "parent": null
}
}
},
{ "id": 6, "title": "Z-Menu", "parent": {
"id": 5, "title": "Y-Menu", "parent": {
"id": 4, "title": "X-Menu", "parent": null }
}
},
{ "id": 5, "title": "Y-Menu", "parent": {
"id": 4, "title": "X-Menu", "parent": null }
},
{ "id": 4, "title": "X-Menu", "parent": null }
]
I want to create a nested tree list like below based on the above Json:
<ul>
<li>
<a>A-Menu</a>
<ul>
<li>
<a>B-Menu</a>
<ul>
<li>
<a>C-Menu</a>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a>X-Menu</a>
<ul>
<li>
<a>Y-Menu</a>
<ul>
<li>
<a>Z-Menu</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Could you please suggest, how is it possible?
I tried like below using jquery:
var jsonObj = [{"id":1,"title":"A-Menu","parent":null},{"id":2,"title":"B-Menu","parent":{"id":1,"title":"A-Menu","parent":null}},{"id":3,"title":"C-Menu","parent":{"id":2,"title":"B-Menu","parent":{"id":1,"title":"A-Menu","parent":null}}},{"id":6,"title":"Z-Menu","parent":{"id":5,"title":"Y-Menu","parent":{"id":4,"title":"X-Menu","parent":null}}},{"id":5,"title":"Y-Menu","parent":{"id":4,"title":"X-Menu","parent":null}},{"id":4,"title":"X-Menu","parent":null}];
//<ul id="allMenus"></ul>
var html = $('#allMenus');
$.each(jsonObj, function(i) {
if(jsonObj[i].parent==null) {
$(html).append('<li id="menu'+result[i].id+'">'+result[i].title+'</li>');
} else {
}
});
I don't know how recursively create the list from unordered json object.
can anybody help?

function createNestedList(data) {
var html = "<ul>";
for (var i = 0; i < data.length; i++) {
if (data[i].parent === null) {
html += "<li>" + data[i].title + createNestedListHelper(data[i].id, data) + "</li>";
}
}
html += "</ul>";
return html;
}
function createNestedListHelper(id, data) {
var html = "<ul>";
for (var i = 0; i < data.length; i++) {
if (data[i].parent && data[i].parent.id === id) {
html += "<li>" + data[i].title + createNestedListHelper(data[i].id, data) + "</li>";
}
}
html += "</ul>";
return html;
}
var jsonObj = [ { "id": 1, "title": "A-Menu", "parent": null }, { "id": 2, "title": "B-Menu", "parent": { "id": 1, "title": "A-Menu", "parent": null } }, { "id": 3, "title": "C-Menu", "parent": { "id": 2, "title": "B-Menu", "parent": { "id": 1, "title": "A-Menu", "parent": null } } }, { "id": 6, "title": "Z-Menu", "parent": { "id": 5, "title": "Y-Menu", "parent": { "id": 4, "title": "X-Menu", "parent": null } } }, { "id": 5, "title": "Y-Menu", "parent": { "id": 4, "title": "X-Menu", "parent": null } }, { "id": 4, "title": "X-Menu", "parent": null }];
var html = createNestedList(jsonObj);
$("#allMenus").html(html);

Related

Get all parents ids from id list in nested object in javascript

So I have an array of objects which have all nested children property. It is in front-end a treeview, which should expand the nodes until selected ones, for each id in a list. To be able to do this, I have to get all the parents ids for each selected id from the list.
For example, my list of checkedKeys ids:
[16787217, 16787245, 16787266, 16787270, 16787272, 16787265, 16787264]
All the checked items represents the ids from the list object:
My object list looks like this:
[
{
"id": 11,
"name": "Forecast source",
"value": null,
"children": []
},
{
"id": 2,
"name": "Item Type",
"value": null,
"children": []
},
{
"id": 16787217,
"name": "Item#Cust",
"value": null,
"children": [
{
"id": 16787230,
"name": "Customer",
"value": null,
"children": [
{
"id": 16787291,
"name": "Commercial Network",
"value": null,
"children": []
},
{
"id": 16787296,
"name": "Distribution Site",
"value": null,
"children": []
},
{
"id": 16787265,
"name": "Site",
"value": null,
"children": []
}
]
},
{
"id": 16787254,
"name": "Item",
"value": null,
"children": [
{
"id": 16787294,
"name": "ABC (Regular)",
"value": null,
"children": []
},
{
"id": 16787273,
"name": "ABC (U)",
"value": null,
"children": []
},
{
"id": 16787278,
"name": "ABC (€)",
"value": null,
"children": []
},
{
"id": 16787290,
"name": "Class",
"value": null,
"children": []
},
{
"id": 16787260,
"name": "Family",
"value": null,
"children": [
{
"id": 16787264,
"name": "Product line",
"value": null,
"children": []
}
]
},
{
"id": 16787263,
"name": "Flavour",
"value": null,
"children": []
},
{
"id": 16787262,
"name": "Format",
"value": null,
"children": []
},
{
"id": 16787261,
"name": "Group 1",
"value": null,
"children": []
},
{
"id": 16787292,
"name": "ProdGroup",
"value": null,
"children": []
},
{
"id": 16787293,
"name": "Recipe",
"value": null,
"children": []
},
{
"id": 16787288,
"name": "Sale status",
"value": null,
"children": []
}
]
},
{
"id": 16787245,
"name": "Item#Site",
"value": null,
"children": [
{
"id": 16787266,
"name": "Family#Warehouse",
"value": null,
"children": []
}
]
}
]
},
{
"id": 3,
"name": "Lead Time",
"value": null,
"children": []
},
{
"id": 5,
"name": "Levels",
"value": null,
"children": []
},
{
"id": 16787268,
"name": "N1",
"value": null,
"children": [
{
"id": 16787269,
"name": "N2",
"value": null,
"children": [
{
"id": 16787270,
"name": "N3",
"value": null,
"children": [
{
"id": 16787271,
"name": "N4",
"value": null,
"children": [
{
"id": 16787272,
"name": "N5",
"value": null,
"children": [
{
"id": 33564497,
"name": "N6",
"value": null,
"children": [
{
"id": 33564498,
"name": "N7",
"value": null,
"children": [
{
"id": 33564499,
"name": "N8",
"value": null,
"children": [
{
"id": 33564500,
"name": "N9",
"value": null,
"children": []
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
},
{
"id": 16787286,
"name": "Op set",
"value": null,
"children": []
}
]
So my problem is that I can't figure out how to get all parents nodes ids recursively until the root level and push them into the expandedKeys array.
I tried to implement a function like this:
this.list.forEach(el => {
this.setExpandedNodes(el);
});
setExpandedNodes(node: PropertyNode) {
if (node.children) {
node.children.forEach(chld => {
this.checkedKeys.forEach(key => {
if (chld.id === key) {
this.expandedKeys.push(node.id);
} else if (chld.children) {
chld.children.forEach(grChld => {
this.setExpandedNodes(grChld);
});
}
});
});
}
}
But I can't figure out how to get all parent ids starting from each selected id until the root level. Anyone have an idea?
Thanks to this answer I managed to do it.
getPath(model, id) {
let path,
item = model.id ;
if (!model || typeof model !== 'object') {
return;
}
if (model.id === id) {
return [item];
}
(model.children || []).some(child => (path = this.getPath(child, id)));
return path && [item, ...path];
}
setExpandedKeys() {
if (this.checkedKeys && this.checkedKeys.length > 0) {
this.checkedKeys.forEach(k => {
this.list.forEach(
mt => {
const result = this.getPath(mt, k);
if (result) {
this.expandedKeys.push(...result);
}
}
);
});
}
}
this.setExpandedKeys();
I have now all the parents ids until the root.
A function that returns an array of parent objects may look like this:
Using tree-model-js:
const getParentsById = (id, data) => {
var TreeModel = require('tree-model')
const tree = new TreeModel()
let path
for (let item of data) {
const root = tree.parse(item)
root.walk(function (node) {
// Halt the traversal by returning false
if (node.model.id === id) {
path = node.getPath()
return false;
}
});
}
path.pop()
return path.map(item => item.model)
}
Without using tree-model-js:
const getParentsById = (id, data) => {
const isFoundChild = (id, data, parents) => {
if (data.find(item => item.id == id)) {
return true;
}
else {
for (let item of data) {
if (item.children.length)
if (isFoundChild(id, item.children)) {
parents.push(item);
return true;
}
}
return false;
}
}
const parents = [];
if (data.find(item => item.id == id))
return [];
else {
for (let item of data) {
if (item.children.length)
if (isFoundChild(id, item.children, parents)) {
parents.push(item);
return parents;
}
}
}
}
Next, it is enough to apply map() to the result:
let parentsId = getParentsById(16787296, data).map(item => item.id)

Need to modify BE response to expected response at FE

BE Response:- which I am getting from Backend Service
{
"data": {
"type": "AnyType",
"resources": [
{
"id": 1,
"treeId": "1",
"name": "name1",
"description": "description1",
"children": [
{
"id": 3,
"treeId": "1-3",
"name": "subName1",
"description": "subDescription1",
"children": [
{
"id": 6,
"treeId": "1-3-6",
"name": "subSubName1",
"description": "subSubDesc1",
"children": []
}
]
}
]
},
{
"id": 2,
"treeId": "2",
"name": "name2",
"description": "description2",
"children": [
{
"id": 7,
"treeId": "2-7",
"name": "subName2",
"description": "subDescription2",
"children": []
}
]
}
]
}
}
But I need to modify this response to as below on FE
Expected Response:- means I need to join name and description field text to one(in name field ) as below:-
{
"data": {
"type": "AnyType",
"resources": [
{
"id": 1,
"treeId": "1",
"name": "name1-description1",
"description": "description1",
"children": [
{
"id": 3,
"treeId": "1-3",
"name": "subName1-subDescription1",
"description": "subDescription1",
"children": [
{
"id": 6,
"treeId": "1-3-6",
"name": "subSubName1-subSubDesc1",
"description": "subSubDesc1",
"children": []
}
]
}
]
},
{
"id": 2,
"treeId": "2",
"name": "name2-description2",
"description": "description2",
"children": [
{
"id": 7,
"treeId": "2-7",
"name": "subName2-subDescription2",
"description": "subDescription2",
"children": []
}
]
}
]
}
}
there could be n number of children of each object and children can have an array of objects.
What I have done:- I am able to change the very first name but not children name
let resDataArry = [];
let descData: DynamicResource;
response.forEach((x, index) => {
const descName = x.name + ' ' + x.description;
descData = { ...tree.resources[index], name: descName };
resDataArry.push(descData);
});
return resDataArry;
Please help.
You can use nested Array#forEach to access children array and then concatenate the name and description together.
let data = {
"data": {
"type": "AnyType",
"resources": [
{
"id": 1,
"treeId": "1",
"name": "name1",
"description": "description1",
"children": [
{
"id": 3,
"treeId": "1-3",
"name": "subName1",
"description": "subDescription1",
"children": [
{
"id": 6,
"treeId": "1-3-6",
"name": "subSubName1",
"description": "subSubDesc1",
"children": []
}
]
}
]
},
{
"id": 2,
"treeId": "2",
"name": "name2",
"description": "description2",
"children": [
{
"id": 7,
"treeId": "2-7",
"name": "subName2",
"description": "subDescription2",
"children": []
}
]
}
]
}
}
data.data.resources.forEach(function(item){
item.name = item.name + ' ' + item.description;
item.children.forEach(function(child){
child.name = child.name + ' ' + child.description;
});
});
console.log(data);

Find empty arrays in nested array and remove them in Javascript

I have a nested and hierarchical array of objects, which looks like this
[{
"id": 0,
"name": "E00-E90 Stoffwechselstörungen",
"parentId": null,
"children": [{
"id": 1,
"name": "E70-E90 Stoffwechselstörungen",
"parentId": 0,
"children": [{
"id": 2,
"name": "E70.- Störungen des Stoffwechsels aromatischer Aminosäuren",
"parentId": 1,
"children": []
}, {
"id": 3,
"name": "E71.- Störungen des Stoffwechsels verzweigter Aminosäuren und des Fettsäurestoffwechsels",
"parentId": 1,
"children": []
}, {
"id": 4,
"name": "E72.- Sonstige Störungen des Aminosäurestoffwechsels",
"parentId": 1,
"children": []
},
...
Now I want to remove the empty array "children": [] from the last children.
I've tried it with reduce but it doesn't work without any error.
var lastElementLength = list.length - 1
const findItemNested = (arr, itemId, nestingKey) => (
arr.reduce((a, item) => {
if (a) return a;
if (item.id === itemId) return item;
if (item[nestingKey]) return findItemNested(item[nestingKey], itemId, nestingKey)
}, null)
);
const resEmptyChildren = findItemNested(roots, lastElementLength, "children");
console.log('resEmptyChildren', resEmptyChildren)
You could use recursion for that.
var tInput = [{
"id": 0,
"name": "E00-E90 Stoffwechselstörungen",
"parentId": null,
"children": [{
"id": 1,
"name": "E70-E90 Stoffwechselstörungen",
"parentId": 0,
"children": [{
"id": 2,
"name": "E70.- Störungen des Stoffwechsels aromatischer Aminosäuren",
"parentId": 1,
"children": []
}, {
"id": 3,
"name": "E71.- Störungen des Stoffwechsels verzweigter Aminosäuren und des Fettsäurestoffwechsels",
"parentId": 1,
"children": []
}, {
"id": 4,
"name": "E72.- Sonstige Störungen des Aminosäurestoffwechsels",
"parentId": 1,
"children": []
}]
}]
}];
(function removeEmptyChildrenProperties(input){
console.log('Checking id:', input.id);
if(input.hasOwnProperty('children')){
if(input.children && input.children.length){
input.children.forEach(removeEmptyChildrenProperties)
}
else{
console.log('Remove children on id:', input.id);
delete input.children
}
};
return input
}).apply(null, tInput);
console.log(JSON.stringify(tInput));

how to convert json parent objects and childs into html dom

I get an API where i have an objects and items in objects.
I have first level, second level and third level arrays, i only need firts and second levels.
How i can display an items for first level objects in html dom?
i only need items with ids = 457 > 458 - 459 - 460 - 461 - 464 - 581, 472 > ....;
its a tree categories
and how i can match code of first level object with child(second level objects)
here is my code
$(document).ready(function() {
var data = [
{
"id": 457,
"name": "name457",
"code": "url457",
"icon": "",
"productsCount": 1,
"items": [
{
"id": 458,
"name": "name458",
"code": "url458",
"icon": null,
"productsCount": 1,
"items": [
{
"id": 741,
"name": "name741",
"code": "url741",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 743,
"name": "name743",
"code": "url743",
"icon": null,
"productsCount": 1,
"image": null
}
],
"image": null
},
{
"id": 459,
"name": "name459",
"code": "url459",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 460,
"name": "name460",
"code": "url460",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 461,
"name": "name461",
"code": "url461",
"icon": null,
"productsCount": 1,
"items": [
{
"id": 599,
"name": "name599",
"code": "url599",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 742,
"name": "name742",
"code": "url742",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 744,
"name": "name744",
"code": "url744",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 882,
"name": "name882",
"code": "url882",
"icon": null,
"productsCount": 1,
"image": null
}
],
"image": null
},
{
"id": 464,
"name": "name464",
"code": "url464",
"icon": null,
"productsCount": 1,
"items": [
{
"id": 883,
"name": "name883",
"code": "url883",
"icon": null,
"productsCount": 1,
"image": null
},
{
"id": 884,
"name": "name884",
"code": "url884",
"icon": null,
"productsCount": 1,
"image": null
}
],
"image": null
},
{
"id": 581,
"name": "name581",
"code": "url581",
"icon": null,
"productsCount": 1,
"image": null
}
],
"image": null
},
{
"id": 472,
"name": "name472",
"code": "url472",
"icon": "milk",
"productsCount": 1,
"items": []
}
]
var keys = Object.keys(data[0]);
var HTML = '';
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < keys.length; j++) {
item = data[i];
items = keys[j];
HTML +=
'<div class="css-firstLVL-cat"><a class="" target="_blank" href="https://firstLVL-cat/' +
item.code + '">' + item.name +
'</a ><div class="css-secondLVL-cat"><a class="" target="_blank" href="https://firstLVL-cat/secondLVL-cat' +
item.items.code + '">' + item.items.name + '</a ></div></div > ';
}
}
$('#gable').append(HTML);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Convert JSON Data to HTML</title>
</head>
<body>
<main class="css-1">
<div class="css-2">
<div>
<div>
<div class="css-3">
<div id="gable" class="css-items">
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</body>
</html>

Remove element from JSON Object

I have a json array which looks something like this:
{
"id": 1,
"children": [
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
},
{
"id": 2,
"children": {
"id": 3,
"children": {
"id": 4,
"children": ""
}
}
}]
}
I would like to have a function which removes the elements which has the "children" empty. How can I do it? I am not asking for the answer, only suggestions
To iterate through the keys of an object, use a for .. in loop:
for (var key in json_obj) {
if (json_obj.hasOwnProperty(key)) {
// do something with `key'
}
}
To test all elements for empty children, you can use a recursive approach: iterate through all elements and recursively test their children too.
Removing a property of an object can be done by using the delete keyword:
var someObj = {
"one": 123,
"two": 345
};
var key = "one";
delete someObj[key];
console.log(someObj); // prints { "two": 345 }
Documentation:
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/delete
JSfiddle
function deleteEmpty(obj){
for(var k in obj)
if(k == "children"){
if(obj[k]){
deleteEmpty(obj[k]);
}else{
delete obj.children;
}
}
}
for(var i=0; i< a.children.length; i++){
deleteEmpty(a.children[i])
}

Categories