Toggle property of nested array of object - JS - javascript

I have an array of objects with 3 levels. I want to target the innermost child with property 'code'. If code is present, then update the child as well as the parent object with selected: true. If the property already is true, then sending in the same value should set the child to selected: false (toggle)
This is what I have going so far. If selected is true for a child, sending in another code should set selected: true for the corresponding child and selected: false for the child which had true for selected property.
Also, if selected is true for a child, defaultCollapsed property should be false for the child as well as parent and grandparent. Ifs elected is false for a child, defaultCollapsed property should be true for the child as well as parent and grandparent
const data = [{
"label": "Grand Parent 1",
"index": 0,
"code": "GRAND_PARENT_1",
"defaultCollapsed": true,
"items": [{
"id": 1,
"items": [{
"id": 100,
"label": "Child 1",
"url": "#CHILD_1",
"code": "CHILD_1",
},
{
"id": 200,
"label": "Child 2",
"url": "#CHILD_2",
"code": "CHILD_2"
},
{
"id": 300,
"label": "Child 3",
"url": "#CHILD_3",
"code": "CHILD_3"
},
{
"id": 400,
"label": "Child 4",
"url": "#CHILD_4",
"code": "CHILD_4"
}
],
"defaultCollapsed": true,
"label": "Parent 1",
"selected": true,
},
{
"id": 2,
"items": [],
"defaultCollapsed": true,
"label": "Parent 2"
},
{
"id": 3,
"items": [],
"defaultCollapsed": true,
"label": "Parent 3"
},
{
"id": 4,
"items": [],
"defaultCollapsed": true,
"label": "Parent 4"
}
]
},
{
"label": "Grand Parent 2",
"index": 1,
"code": "GRAND_PARENT_2",
"defaultCollapsed": true,
"items": []
},
{
"label": "Grand Parent 3",
"index": 2,
"code": "GRAND_PARENT_3",
"defaultCollapsed": true,
"items": []
}
]
function select(items, key, value) {
if (!Array.isArray(items)) {
return false;
}
for (const item of items) {
if (item.code === value || select(item.items, key, value)) {
item.selected = !item.selected;
item.defaultCollapsed = false;
return true;
}
}
return false;
}
function reset(items) {
if (!Array.isArray(items)) {
return;
}
for (const item of items) {
if (item.selected) {
reset(item.items);
item.selected = false;
break;
}
}
}
function resetAndSelect(data, key, value) {
reset(data);
select(data, key, value);
}
resetAndSelect(data, 'code', 'CHILD_1')
console.log('CHILD_1',data)
resetAndSelect(data, 'code', 'CHILD_2')
console.log('CHILD_2',data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
If code is CHILD_1:
[{
"label": "Grand Parent 1",
"index": 0,
"code": "GRAND_PARENT_1",
"defaultCollapsed": true,
"selected": true,
"items": [{
"id": 1,
"items": [{
"id": 100,
"label": "Child 1",
"url": "#CHILD_1",
"code": "CHILD_1",
"selected": true,
},
{
"id": 200,
"label": "Child 2",
"url": "#CHILD_2",
"code": "CHILD_2"
},
{
"id": 300,
"label": "Child 3",
"url": "#CHILD_3",
"code": "CHILD_3"
},
{
"id": 400,
"label": "Child 4",
"url": "#CHILD_4",
"code": "CHILD_4"
}
],
"defaultCollapsed": false,
"label": "Parent 1",
"selected": true,
},
{
"id": 2,
"items": [],
"defaultCollapsed": true,
"label": "Parent 2"
},
{
"id": 3,
"items": [],
"defaultCollapsed": true,
"label": "Parent 3"
},
{
"id": 4,
"items": [],
"defaultCollapsed": true,
"label": "Parent 4"
}
]
},
{
"label": "Grand Parent 2",
"index": 1,
"code": "GRAND_PARENT_2",
"defaultCollapsed": true,
"items": []
},
{
"label": "Grand Parent 3",
"index": 2,
"code": "GRAND_PARENT_3",
"defaultCollapsed": true,
"items": []
}
]
If the above output is the actual data, and the code is CHILD_1 again, I need to toggle the selected property of the child as well the corresponding parents.
[{
"label": "Grand Parent 1",
"index": 0,
"code": "GRAND_PARENT_1",
"defaultCollapsed": true,
"selected": false,
"items": [{
"id": 1,
"items": [{
"id": 100,
"label": "Child 1",
"url": "#CHILD_1",
"code": "CHILD_1",
"selected": false,
},
{
"id": 200,
"label": "Child 2",
"url": "#CHILD_2",
"code": "CHILD_2"
},
{
"id": 300,
"label": "Child 3",
"url": "#CHILD_3",
"code": "CHILD_3"
},
{
"id": 400,
"label": "Child 4",
"url": "#CHILD_4",
"code": "CHILD_4"
}
],
"defaultCollapsed": false,
"label": "Parent 1",
"selected": false,
},
{
"id": 2,
"items": [],
"defaultCollapsed": true,
"label": "Parent 2"
},
{
"id": 3,
"items": [],
"defaultCollapsed": true,
"label": "Parent 3"
},
{
"id": 4,
"items": [],
"defaultCollapsed": true,
"label": "Parent 4"
}
]
},
{
"label": "Grand Parent 2",
"index": 1,
"code": "GRAND_PARENT_2",
"defaultCollapsed": true,
"items": []
},
{
"label": "Grand Parent 3",
"index": 2,
"code": "GRAND_PARENT_3",
"defaultCollapsed": true,
"items": []
}
]

You can do this by creating recursive function using forEach loop and passing array of parents down with recursion so that you can update its selected property.
const data = [{"label":"Grand Parent 1","index":0,"code":"GRAND_PARENT_1","defaultCollapsed":true,"items":[{"id":1,"items":[{"id":100,"label":"Child 1","url":"#CHILD_1","code":"CHILD_1"},{"id":200,"label":"Child 2","url":"#CHILD_2","code":"CHILD_2"},{"id":300,"label":"Child 3","url":"#CHILD_3","code":"CHILD_3"},{"id":400,"label":"Child 4","url":"#CHILD_4","code":"CHILD_4"}],"defaultCollapsed":true,"label":"Parent 1","selected":true},{"id":2,"items":[],"defaultCollapsed":true,"label":"Parent 2"},{"id":3,"items":[],"defaultCollapsed":true,"label":"Parent 3"},{"id":4,"items":[],"defaultCollapsed":true,"label":"Parent 4"}]},{"label":"Grand Parent 2","index":1,"code":"GRAND_PARENT_2","defaultCollapsed":true,"items":[]},{"label":"Grand Parent 3","index":2,"code":"GRAND_PARENT_3","defaultCollapsed":true,"items":[]}]
function update(data, key, value, parents = []) {
data.forEach(e => {
if (e[key] === value) {
if (parents.length) {
e.selected = !e.selected;
parents.forEach(p => {
p.defaultCollapsed = !e.selected
p.selected = e.selected
})
data.forEach(s => {
if (s != e && s.selected) s.selected = false;
});
}
}
if (e.items && e.items.length) {
update(e.items, key, value, [...parents, e])
}
})
}
update(data, 'code', 'CHILD_4')
update(data, 'code', 'CHILD_4')
update(data, 'code', 'CHILD_2')
update(data, 'code', 'CHILD_1')
console.log(data)

You could toggle the target node and leave the rest as true, for the path to the item.
function update(array, value) {
var found = false;
array.forEach(o => {
var sub = update(o.items || [], value),
check = o.code === value;
if (check) {
o.selected = !o.selected
found = o.selected;
} else {
o.selected = sub;
if (sub) found = o.selected;
}
o.defaultCollapsed = !o.selected;
});
return found;
}
var data = [{ label: "Grand Parent 1", index: 0, code: "GRAND_PARENT_1", defaultCollapsed: true, items: [{ id: 1, items: [{ id: 100, label: "Child 1", url: "#CHILD_1", code: "CHILD_1" }, { id: 200, label: "Child 2", url: "#CHILD_2", code: "CHILD_2" }, { id: 300, label: "Child 3", url: "#CHILD_3", code: "CHILD_3" }, { id: 400, label: "Child 4", url: "#CHILD_4", code: "CHILD_4" }], defaultCollapsed: false, label: "Parent 1" }, { id: 2, items: [], defaultCollapsed: true, label: "Parent 2" }, { id: 3, items: [], defaultCollapsed: true, label: "Parent 3" }, { id: 4, items: [], defaultCollapsed: true, label: "Parent 4" }] }, { label: "Grand Parent 2", index: 1, code: "GRAND_PARENT_2", defaultCollapsed: true, items: [] }, { label: "Grand Parent 3", index: 2, code: "GRAND_PARENT_3", defaultCollapsed: true, items: [] }];
update(data, 'CHILD_1');
console.log(data);
update(data, 'CHILD_1');
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Get all its parent nodes path for each child nodes

Hi I have below code running, but I would like to add one more property called path which should consist all its parent node path
Expected output I need something as I have shown for cardTtile, so I need same for each node.
[
{
"id": "cardShop",
"key": "cardShop",
"title": "cardShop",
"selectable": false,
"path":cardShop"
"children": [
{
"id": "cardData",
"key": "cardData",
"title": "cardData",
"parentId": "cardShop",
"path":cardShop.cardData"
"selectable": false,
"children": [
{
"id": "cardTitle",
"key": "cardTitle",
"title": "cardTitle",
"parentId": "cardData",
"path":cardShop.cardData.cardTitle"
"isLeaf": true
},
{
"id": "cardType",
"key": "cardType",
"title": "cardType",
"parentId": "cardData",
"isLeaf": true
},
{
"id": "dtmProductName",
"key": "dtmProductName",
"title": "dtmProductName",
"parentId": "cardData",
"isLeaf": true
},
{
"id": "viewAllCards",
"key": "viewAllCards",
"title": "viewAllCards",
"parentId": "cardData",
"selectable": false,
"children": [
{
"id": "url",
"key": "url",
"title": "url",
"parentId": "viewAllCards",
"isLeaf": true
},
{
"id": "text",
"key": "text",
"title": "text",
"parentId": "viewAllCards",
"isLeaf": true
}
]
}
]
},
{
"id": "eligibilityChecker",
"key": "eligibilityChecker",
"title": "eligibilityChecker",
"parentId": "cardShop",
"selectable": false,
"children": [
{
"id": "header",
"key": "header",
"title": "header",
"parentId": "eligibilityChecker",
"isLeaf": true
},
{
"id": "subHeader",
"key": "subHeader",
"title": "subHeader",
"parentId": "eligibilityChecker",
"isLeaf": true
},
{
"id": "bulletPoints",
"key": "bulletPoints",
"title": "bulletPoints",
"parentId": "eligibilityChecker",
"isLeaf": true
}
]
}
]
}
]
I have below running code example here. I tried to persist parentKey recursively but its not giving me expected output.
const transform = data => {
const loop = (data, parent) => Object.entries(data).map(([key, value]) => {
let additional = parent? {
parentId: parent
}:{}
if(typeof value === 'object' && !Array.isArray(value)){
additional = {
...additional,
selectable: false,
children: loop(value, key)
}
}else{
additional.isLeaf = true
}
return {
id: key,
key,
title: key,
...additional
}
})
return loop(data)
}
let jsonObj = {
"data": {
"cardShop": {
"cardData": {
"cardTitle": "The Platinum Card<sup>®</sup>",
"cardType": "credit-cards",
"dtmProductName": "PlatinumCard",
"viewAllCards": {
"url": "credit-cards/all-cards",
"text": "All Cards"
}
},
"eligibilityChecker": {
"header": "Check your eligibility",
"subHeader": "The Platinum Card®",
"bulletPoints": [
"Only takes a couple of minutes to complete",
"Will not impact your credit rating",
"Allows you to apply with confidence"
]
}
}
}
}
console.log(transform(jsonObj.data))
]
You suggestion would be appreciated
Thanks
You could take another variable for path and add the actual key to it.
const transform = data => {
const loop = (data, parentId, previousPath = '') => Object
.entries(data)
.map(([key, value]) => {
const
additional = parentId ? { parentId } : {},
path = previousPath + (previousPath && '.') + key;
Object.assign(
additional,
value && typeof value === 'object' && !Array.isArray(value)
? { selectable: false, children: loop(value, key, path) }
: { isLeaf: true }
);
return { id: key, key, title: key, path, ...additional };
});
return loop(data);
}
const data = { cardShop: { cardData: { cardTitle: "The Platinum Card<sup>®</sup>", cardType: "credit-cards", dtmProductName: "PlatinumCard", viewAllCards: { url: "credit-cards/all-cards", text: "All Cards" } }, eligibilityChecker: { header: "Check your eligibility", subHeader: "The Platinum Card®", bulletPoints: ["Only takes a couple of minutes to complete", "Will not impact your credit rating", "Allows you to apply with confidence"] } } };
console.log(transform(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

How To Get The Parent value from Json for this select2

var preload_data = [{
"id": 2049,
"text": "style",
"children": [{
"id": "6906957ed912c883",
"text": "Country"
}, {
"id": "d239d844608fdbcf",
"text": "Christmas"
}]
}, {
"id": 0,
"text": "unassigned",
"children": [{
"id": "52d8e1e8d419bb61",
"text": "Punk"
}, {
"id": "88b9826121aeb89b",
"text": "Upbeat"
}, {
"id": "8485e6dd8e33fc50",
"text": "test arda"
}, {
"id": "da9fa55495a4a463",
"text": "test1"
}, {
"id": "feb1177719f4b5a4",
"text": "test arda 3"
}, {
"id": "64a2ae4ec2c0a1ef",
"text": "Feel Good"
}, {
"id": "2512f7946f660dc5",
"text": "Happy"
}, {
"id": "b1e7203207bd068f",
"text": "Love"
}, {
"id": "fb3a42b8abbf975a",
"text": "Reminiscent"
}, {
"id": "56d60aed1278c5a0",
"text": "Indie"
}, {
"id": "5733de46970ac503",
"text": "Rock"
}, {
"id": "801c33b478d1d5be",
"text": "Singer Songwriter"
}, {
"id": "ee4c6f5c12782bb9",
"text": "World"
}, {
"id": "4605140218eb9e52",
"text": "Reality"
}, {
"id": "92934140c305706e",
"text": "Pop"
}, {
"id": "f40f55db44dc0846",
"text": "Acoustic"
}, {
"id": "07b3c4640e84bfeb",
"text": "Folk"
}]
}]
and I want the output for dropdown list
Style:Christmas for example
this is the select2 code
$("#hidStyles").select2({
containerCssClass: 'styleContainer',
data: preload_data,
width: '100%',
allowClear: true,
multiple: true,
dropdownCssClass: 'select2-hidden',
placeholder: 'Please enter the name of style here to assign it to this album',
formatSelection: format1,
escapeMarkup : function(m) { return m;},
formatSearching: null
//formatSelection : format
});
and this is How I format the Json :
function format1(item) {
opt = $("#hidStyles").find(':selected');
sel = opt.text;
//og = opt.closest(".select2-results-dept-0").attr(".select2-result-label");
ogx = opt.text.data.text;
return ogx + ':' + item.text;
}
how can I get the value so that it's like style : christmas
https://jsfiddle.net/jna7ft1c/3/
I am sorry the jsfiddle I am not familiar with for making the front end, but mostly the code is like written there

How to find all specific keys in multiple level NESTED JSON in one loop, and for every of them change value

how to get the index number for every object inside the array.
I have JSON with multiple nested arrays of objects, and I need to set to the POSITION key index number.
I get this JSON dynamically, and I need to loop thru the JSON and on every POSITION key need to set indexOF() number to get object position inside array.
My problem is, how to find all keys with name POSITION and set indexOf() number for a value?
I know, and I try to get it in loop for every nested array, but is there any BETTER way? Faster way?
Here is example with nested for loops
Thnx
Here is JSON
{
"id": 175,
"name": "dag",
"title": "dfgd",
"page": [{
"id": 551,
"name": "page1",
"title": "Page 1",
"position": 0, ---> here I need set index number for obj in this page array
"questions": [{
"id": 70,
"name": "text1",
"text": "Questitexton 1",
"position": 0, ---> here I need set index number for obj in this questions array
"data": [{
"id": 56,
"name": "data",
"position": 0, ---> here I need set index number for obj in this data array
"text": "Control 3"
}]
}, {
"id": 69,
"name": "data3",
"text": "data 3",
"position": 1, ---> here I need set index number for obj in this array
"data": [{
"id": 55,
"name": "data2",
"position": 0, ---> here I need set index number for obj in this data array
"text": "Control 3"
}]
}]
}, {
"id": 552,
"name": "page2",
"title": "Page 2",
"position": 1, ---> here I need set index number for obj in this page array
"questions": [{
"id": 73,
"name": "text1",
"text": "Questitexton 1",
"position": 0, ---> here I need set index number for obj in this questions array
"data": [{
"id": 75,
"name": "data",
"position": 0, ---> here I need set index number for obj in this data array
"text": "Control 3"
}]
}, {
"id": 45,
"name": "data3",
"text": "data 3",
"position": 1, ---> here I need set index number for obj in this questions array
"data": [{
"id": 798,
"name": "data2",
"position": 0, ---> here I need set index number for obj in this data array
"text": "Control 3"
}]
}]
}]
}
My current attempt
const animals = [{
id: 175,
name: "dag",
title: "dfgd",
page: [{
id: 551,
name: "page1",
title: "Page 1",
position: null,
questions: [{
id: 70,
name: "text1",
text: "Questitexton 1",
position: null,
data: [{
id: 56,
name: "data",
position: null,
text: "Control 3"
}]
},
{
id: 69,
name: "data3",
text: "data 3",
position: null,
data: [{
id: 55,
name: "data2",
position: null,
text: "Control 3"
}]
}
]
},
{
id: 552,
name: "page2",
title: "Page 2",
position: null,
questions: [{
id: 73,
name: "text2",
text: "Questitexton 1",
position: null,
data: [{
id: 75,
name: "data",
position: null,
text: "Control 3"
}]
},
{
id: 45,
name: "data5",
text: "data 3",
position: null,
data: [{
id: 798,
name: "data2",
position: null,
text: "Control 3"
}]
}
]
}
]
}];
for (let data of animals) {
for (let data1 of data.page) {
data1.position = data.page.indexOf(data1);
for (let data2 of data1.questions) {
data2.position = data1.questions.indexOf(data2);
for (let data3 of data2.data) {
data3.position = data2.data.indexOf(data3);
}
}
}
}
console.log(animals);
You could clone the object and add the index if position is found.
const addIndex = (o, i) => Object.fromEntries(Object.entries(o).map(([k, v]) => [
k,
k === 'position'
? i
: Array.isArray(v)
? v.map(addIndex)
: v
]));
var animals = [{ id: 175, name: "dag", title: "dfgd", page: [{ id: 551, name: "page1", title: "Page 1", position: null, questions: [{ id: 70, name: "text1", text: "Questitexton 1", position: null, data: [{ id: 56, name: "data", position: null, text: "Control 3" }] }, { id: 69, name: "data3", text: "data 3", position: null, data: [{ id: 55, name: "data2", position: null, text: "Control 3" }] }] }, { id: 552, name: "page2", title: "Page 2", position: null, questions: [{ id: 73, name: "text2", text: "Questitexton 1", position: null, data: [{ id: 75, name: "data", position: null, text: "Control 3" }] }, { id: 45, name: "data5", text: "data 3", position: null, data: [{ id: 798, name: "data2", position: null, text: "Control 3" }] }] }] }],
result = animals.map(addIndex);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can't really do it in a one-liner but if you create a re-usable function to set a position on an array, then you can do it quite quickly.
My code creates a copy of your original array, but that shouldn't be such a problem per say, I am sure you could work around it if you like
function getPositionedObject( objToCopy, position = 0 ) {
// take all the keys on the object
return Object.keys( objToCopy ).reduce( (agg, key) => {
// get the value once
const value = objToCopy[key];
if (Array.isArray( value ) ) {
// if it's an array, iterate all the items and re-use this function
agg[key] = value.map( getPositionedObject );
} else {
// if it's not keep the value as is
agg[key] = value;
}
return agg;
}, { position }); // start with the position that was passed as a parameter
}
With your dataset (I removed the initial positions from the code you have given, it kinda looks like the following)
const dataset = {
"id": 175,
"name": "dag",
"title": "dfgd",
"page": [{
"id": 551,
"name": "page1",
"title": "Page 1",
"questions": [{
"id": 70,
"name": "text1",
"text": "Questitexton 1",
"data": [{
"id": 56,
"name": "data",
"text": "Control 3"
}]
}, {
"id": 69,
"name": "data3",
"text": "data 3",
"data": [{
"id": 55,
"name": "data2",
"text": "Control 3"
}]
}]
}, {
"id": 552,
"name": "page2",
"title": "Page 2",
"questions": [{
"id": 73,
"name": "text1",
"text": "Questitexton 1",
"data": [{
"id": 75,
"name": "data",
"text": "Control 3"
}]
}, {
"id": 45,
"name": "data3",
"text": "data 3",
"data": [{
"id": 798,
"name": "data2",
"text": "Control 3"
}]
}]
}]
};
function getPositionedObject( objToCopy, position = 0 ) {
return Object.keys( objToCopy ).reduce( (agg, key) => {
const value = objToCopy[key];
if (Array.isArray( value ) ) {
agg[key] = value.map( getPositionedObject );
} else {
agg[key] = value;
}
return agg;
}, { position });
}
console.log( getPositionedObject( dataset ) );

flattening nested json object

[
{
"children": [
{
"children": [
{
"dateAdded": 1493033302670,
"id": "1534",
"index": 0,
"parentId": "1",
"title": "data1",
"url": "data2"
},
{
"children": [
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "data3",
"url": "data4"
}
],
"dateAdded": 1490363326576,
"dateGroupModified": 1490363326576,
"id": "1401",
"index": 1,
"parentId": "1",
"title": "daily"
},
{
"children": [
{
"dateAdded": 1481787664555,
"id": "1429",
"index": 0,
"parentId": "1407",
"title": "data56",
"url": "data"
},
{
"dateAdded": 1483365608504,
"id": "1430",
"index": 1,
"parentId": "1407",
"title": "data34",
"url": "data55"
}
]
}
]
}
]
}
]
This is a representation of Chrome bookmarks data.
If the object has url property it means that is a bookmark. If it does not have url property it is a folder.
It is a tree structure.
I would like to create flatten object with additional property named type. Like:
[
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "title",
"url": "some url",
"type": "bookmark"
},
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1402",
"title": "title2",
"url": "some url2"
"type": "folder"
}
]
Thanks in advance.
You could use an iterative and recursive approach for getting flat data.
function flatten(array) {
var result = [];
array.forEach(function iter(o) {
var temp = {},
keys = Object.keys(o);
if (keys.length > 1) {
keys.forEach(function (k) {
if (k !== 'children') {
temp[k] = o[k];
}
});
temp.type = 'url' in o ? 'bookmark' : 'folder';
result.push(temp);
}
Array.isArray(o.children) && o.children.forEach(iter);
});
return result;
}
var data = [{ children: [{ children: [{ dateAdded: 1493033302670, id: "1534", index: 0, parentId: "1", title: "data1", url: "data2" }, { children: [{ dateAdded: 1489571506844, id: "1451", index: 0, parentId: "1401", title: "data3", url: "data4" }], dateAdded: 1490363326576, dateGroupModified: 1490363326576, id: "1401", index: 1, parentId: "1", title: "daily" }, { children: [{ dateAdded: 1481787664555, id: "1429", index: 0, parentId: "1407", title: "data56", url: "data" }, { dateAdded: 1483365608504, id: "1430", index: 1, parentId: "1407", title: "data34", url: "data55" }] }] }] }];
console.log(flatten(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I've made a function that iterates through an array containing objects. If a given object has a property called children, the function calls itself. If it doesn't, then it gets pushed to a new array flattenedBookmarks.
The Solution
var flattenedBookmarks = [];
flattenBookmarks(bookmarks);
function flattenBookmarks(bookmarks) {
for (var i = 0; i < bookmarks.length; i++) {
var potentialBookmark = bookmarks[i];
if (potentialBookmark.hasOwnProperty("url")) {
potentialBookmark.type = "bookmark";
} else {
potentialBookmark.type = "folder";
}
if (potentialBookmark.hasOwnProperty("children")) {
flattenBookmarks(potentialBookmark.children);
if (potentialBookmark.hasOwnProperty("dateGroupModified")) {
flattenedBookmarks.push(potentialBookmark);
}
} else {
flattenedBookmarks.push(potentialBookmark);
}
}
}
You should probably be returning the flattened array from the function instead of storing it in a new global array flattenedBookmarks, but at least this will get you started.
https://jsfiddle.net/s9ur35re/
The example shows how to do it
data = [
{
"children": [
{
"children": [
{
"dateAdded": 1493033302670,
"id": "1534",
"index": 0,
"parentId": "1",
"title": "data1",
"url": "data2"
},
{
"children": [
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "data3",
"url": "data4"
}
],
"dateAdded": 1490363326576,
"dateGroupModified": 1490363326576,
"id": "1401",
"index": 1,
"parentId": "1",
"title": "daily"
},
{
"children": [
{
"dateAdded": 1481787664555,
"id": "1429",
"index": 0,
"parentId": "1407",
"title": "data56",
"url": "data"
},
{
"dateAdded": 1483365608504,
"id": "1430",
"index": 1,
"parentId": "1407",
"title": "data34",
"url": "data55"
}
]
}
]
}
]
}
];
data2 = [];
function search(data) {
for (n in data) {
if (typeof data[n] == 'object') {
if (data[n].id != undefined) {
if (data[n].url != undefined) {
data[n].type="folder";
} else {
data[n].type="bookmark";
}
data2.push(data[n]);
}
search(data[n]);
}
}
}
search(data);
console.log(data2);

Traverse to child nodes and find property(upto n levels)

We have a JSON file:
var response = {
"Status": "Met",
"Text": "Text1",
"Id": "AAA",
"ContentItems": [
{
"Selected": true,
"Text": "Text2",
"Id": "BBB"
},
{
"Status": "Met",
"Text": "Text3",
"Id": "CCC",
"ContentItems": [
{
"Selected": true,
"Text": "Text5",
"Id": "DDD"
},
{
"Status": "Met",
"Text": "Text6",
"Id": "EEE",
"ContentItems": [
{
"Selected": true,
"Text": "Text7",
"Id": "FFF"
},
{
"Selected": true,
"Text": "Text8",
"Id": "GGG"
},
{
"Status": "Met",
"Text": "Text9",
"Id": "III",
"ContentItems": [
{
"Status": "Met",
"Text": "Text11",
"Id": "JJJ",
"ContentItems": [
{
"Text": "Text12",
"Id": "77"
},
{
"Status": "Met",
"Text": "Text13",
"Id": "10",
"ContentItems": [
{
"Text": "Text14",
"Id": "45"
},
{
"Selected": true,
"Text": "Text15",
"Id": "87"
},
{
"Selected": true,
"Text": "Text16",
"Id": "80"
}
]
}
]
},
{
"Status": "Met",
"Text": "Text17",
"Id": "KKK",
"ContentItems": [
{
"Text": "Text18",
"Id": "12"
},
{
"Status": "NotMet",
"Text": "Text19",
"Id": "14",
"ContentItems": [
{
"Text": "Text20",
"Id": "55"
},
{
"Selected": true,
"Text": "Text21",
"Id": "98"
}
]
}
]
}
]
}
]
}
]
}
]
};
From the JSON file we need the following:
1.Return true if all "Status" is "Met".
2.Return false if any "Status" is "NotMet".
Since Child nodes can be any level deep; I used recursion function to traverse to each node and from there i'm looping over the child nodes and recursively calling the function.
I tried this code but its not working as expected.
function isStatusMet(response) {
if (response.Status == 'NotMet') {
return false;
} else {
if (response.ContentItems) {
if(Array.isArray(response.ContentItems)) {
for(var i = 0; i < response.ContentItems.length;i++) {
if (response.ContentItems[i].ContentItems) {
return isStatusMet(response.ContentItems[i]);
} else {
if (response.ContentItems[i].Status == 'NotMet') {
return false;
} else {
continue;
}
}
}
return true;
}
}
}
}
var isStatusMet = function isStatusMet( data ) {
// If the status is NotMet, we finish immediately
if (data.Status === 'NotMet') return false;
// Since only nodes with ContentItems have a status, we check if the node has children and recursively check if every child has no Status of NotMet
else if (data.hasOwnProperty('ContentItems')) return data.ContentItems.every(isStatusMet);
// We're dealing with a child without Status or Childnodes, so we just return true.
// Since the status in not met and the parent node of this node expects in its 'every' loop that we only return false for nodes that have Status NotMet, this makes the recusion work.
else return true;
};
var met = isStatusMet(response);
console.log(met);
The statement return isStatusMet(response.ContentItems[i]); will do a premature exit on any status. It should only return false if the recursive call answers false, or else the loop needs to continue.
Change it to this:
if (response.ContentItems[i].ContentItems) {
if (!isStatusMet(response.ContentItems[i])) return false;
}
You could use Array#every and use it recursive if ContentItems is an array.
var data = { Status: "Met", Text: "Text1", Id: "AAA", ContentItems: [{ Selected: true, Text: "Text2", Id: "BBB" }, { Status: "Met", Text: "Text3", Id: "CCC", ContentItems: [{ Selected: true, Text: "Text5", Id: "DDD" }, { Status: "Met", Text: "Text6", Id: "EEE", ContentItems: [{ Selected: true, Text: "Text7", Id: "FFF" }, { Selected: true, Text: "Text8", Id: "GGG" }, { Status: "Met", Text: "Text9", Id: "III", ContentItems: [{ Status: "Met", Text: "Text11", Id: "JJJ", ContentItems: [{ Text: "Text12", Id: 77 }, { Status: "Met", Text: "Text13", Id: 10, ContentItems: [{ Text: "Text14", Id: 45 }, { Selected: true, Text: "Text15", Id: 87 }, { Selected: true, Text: "Text16", Id: 80 }] }] }, { Status: "Met", Text: "Text17", Id: "KKK", ContentItems: [{ Text: "Text18", Id: 12 }, { Status: "NotMet", Text: "Text19", Id: 14, ContentItems: [{ Text: "Text20", Id: 55 }, { Selected: true, Text: "Text21", Id: 98 }] }] }] }] }] }] },
result = [data].every(function iter(a) {
return a.Status !== 'NotMet' && (!Array.isArray(a.ContentItems) || a.ContentItems.every(iter));
});
console.log(result);

Categories

Resources