Convert a list of objects to a json tree structure - javascript

I have a list which needs to be converted to a json format.
This..
var sourceList = [
{ title: "item-1", indent: "0" },
{ title: "item-2", indent: "0" },
{ title: "item-3", indent: "0", folder: true },
{ title: "item-4", indent: "1" },
{ title: "item-5", indent: "1", folder: true },
{ title: "item-6", indent: "2" },
{ title: "item-7", indent: "2" },
{ title: "item-8", indent: "0" }
];
to this..
var targetJson = [
{ title: "item-1" },
{ title: "item-2" },
{ title: "item-3", folder: true, children: [
{ title: "item-4" },
{ title: "item-5", folder: true, children: [
{ title: "item-6" },
{ title: "item-7" }
]},
]},
{ title: "item-8" }
];
so that the result can be used to init a tree structure like below.
item-1
item-2
item-3
.. item-4
.. item-5
.... item-6
.... item-7
item-8
The 'indent' property of each source object determines its position relative to the previous object.
Like if an object has indent greater than previous one, then it will be taken as child of previous and if it has indent same as previous then it is taken as sibling of the previous.
So children property and folder property will occur for nodes which has sub-items.
One of the challenges would be 'item-8' which is at level-0 than the previous one at level-2.
Need a solution, preferably in javascript.

I kept a mapping between indentation and the element to add children to:
// test data
var sourceList = [
{ title: "item-1", indent: "0" },
{ title: "item-2", indent: "0" },
{ title: "item-3", indent: "0", folder: true },
{ title: "item-4", indent: "1" },
{ title: "item-5", indent: "1", folder: true },
{ title: "item-6", indent: "2" },
{ title: "item-7", indent: "2" },
{ title: "item-8", indent: "0" }
];
// init
var targetJson = [];
var roots = { 0 : targetJson};
// actual code:
sourceList.forEach(function(item){
if (!roots[item.indent].splice) {
roots[item.indent] = roots[item.indent].children = [];
}
roots[item.indent].push(item);
if (item.folder) {
roots[+item.indent+1] = item;
}
});
// output
console.log(targetJson);
PS: i kept the indent property in the object so you can check the results. Feel free to remove it after the item is added. It is inconsequential.

Related

json filter nested array with javascript

I want to pull with javascript: {"subNav0", "subNav1", "subNav2", "subNav3", "subNav4", "subNav5"}.
my json:
var data = {
"menus":{
"GrandparentNav0":{
"name":"TopNav",
"items":[
{
"name":"ParentNav0",
"iconClass":"",
"items":[
{
"name":"ParentNav1",
"iconClass":"",
"items":[
{
"name":"subNav0",
"iconClass":""
},
{
"name":"subNav1",
"iconClass":""
},
{
"name":"subNav2",
"iconClass":""
},
{
"name":"subNav3",
"iconClass":""
},
{
"name":"subNav4",
"iconClass":""
},
{
"name":"subNav5",
"iconClass":""
}
]
},
]
}
]
}
},
};
i know basic filter of an array:
data .forEach(function(o) {
o.variable = o.variable.filter(s => s.value == value);
});
I dont know how to get through menus, GrandparentNav0 to pull the subNav(s)
By "pull the subNav(s)" do you mean like accessing it through something like bracket notation?
let subNavs = data['menus']['GrandparentNav0']['items'][0]['items']
console.log(subNavs)
/* would return
[
{
"name": "subNav0",
"iconClass": ""
},
{
"name": "subNav1",
"iconClass": ""
},
{
"name": "subNav2",
"iconClass": ""
},
{
"name": "subNav3",
"iconClass": ""
},
{
"name": "subNav4",
"iconClass": ""
},
{
"name": "subNav5",
"iconClass": ""
}
]
*/
Here is a solution using object-scan. This might be overkill for your requirements, however as you run into other use cases it's a Swiss army knife that makes these types of data interactions very clean
// const objectScan = require('object-scan');
const data = { menus: { GrandparentNav0: { name: 'TopNav', items: [ { name: 'ParentNav0', iconClass: '', items: [ { name: 'ParentNav1', iconClass: '', items: [ { name: 'subNav0', iconClass: '' }, { name: 'subNav1', iconClass: '' }, { name: 'subNav2', iconClass: '' }, { name: 'subNav3', iconClass: '' }, { name: 'subNav4', iconClass: '' }, { name: 'subNav5', iconClass: '' } ] } ] } ] } } };
const result = objectScan(['menus.GrandparentNav0.items[0].items[0].items[*].name'], { reverse: false, rtn: 'value' })(data);
console.log(result);
// => [ 'subNav0', 'subNav1', 'subNav2', 'subNav3', 'subNav4', 'subNav5' ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#14.0.0"></script>
Disclaimer: I'm the author of object-scan

How to add objects to an array during creation using a loop in Javascript?

I am trying to write some meta information for a website (using vue-meta) and I need to add some tags as objects within an array named meta.
The code is like this:
metaInfo() {
return {
htmlAttrs: { lang: "en"
},
title: this.Post.Title,
meta: [
{
name: "description", content: this.Post.Title
},
{
name: "date", content: this.Post.DateCreated
},
{
name: "author", content: this.Post.Author
},
// Now I need multiple objects of: {name: "tag", content: "Tags.TagName"} like this but doesn't work:
function() {
this.Tags.forEach(function (TagName, index) {
{ property: "tag", content: "TagName" }
})
}
],
}
}
How can I create my array so that I end up with this for example:
meta: [
{
name: "description", content: "Javascript question"
},
{
name: "date", content: "20200421"
},
{
name: "author", content: "volumeone"
},
{ property: "tag", content: "Javascript" }
,
{ property: "tag", content: "Programming" }
,
{ property: "tag", content: "Newbie" }
]
you can do such sort of thing.
var meta = [{
name: "description", content: this.Post.Title
},
{
name: "date", content: this.Post.DateCreated
},
{
name: "author", content: this.Post.Author
}]
this.Tags.forEach(function (TagName, index) {
meta.push({ property: "tag", content: "TagName" })
})
metaInfo() {
return {
htmlAttrs: { lang: "en"
},
title: this.Post.Title,
// or you can just write "meta" instead of "meta: meta" its an shorthand // code
meta: meta
}
}
Unless I'm missing something, you can just use push and pass the object.
var meta = [];
meta.push({"property" : "tag","content" : "test"});
console.log(meta);

Display fetch data in accordion React Native

I'm using an accordion list from native base, and all i'm displaying rightnow is:
const dataArray = [
{ title: "Desc", content: "n" },
{ title: "education1", content: "n" },
{ title: "education2", content: "n" },
{ title: "Price", content: 'n' },
{ title: "place", content: "n" },
{ title: "paiement", content: "n" }
];
...
<Content padder>
<Accordion dataArray={dataArray} expanded={0} />
</Content>
so i fetched some data from a database and i want to diplay the content of every array inside the corresponding accordion pad, here is the format of the data:
Array [
Object {
"code": false,
"id": 10,
"name": "medecin_mediclic",
"presentation": false,
"profession": "Medecin",
"specialite": "Généraliste",
},
Object {
"education": Array [],
},
Object {
"education": Array [],
},
Object {
"price": Array [],
},
Object {
"place": Array [],
},
Object {
"paiement": Array [],
},
]
for example, in my accordion list first pad is "Desc" should contain:
"medecin_mediclic",
false,
"Medecin",
"Généraliste",
and so on.if the array is null then nothing comes out
anyone have any idea how to do it?

Meteor cross collection arrays

I am trying to pull an array from a different collection using collection2. I have been able to do this with objects using the following example for users:
users: {
type: String,
label: "Inspector",
optional: true,
autoform: {
firstOption: 'Choose an Inspector',
options: function() {
return Meteor.users.find({}, {
sort: {
profile: 1,
firstName: 1
}
}).map(function(c) {
return {
label: c.profile.firstName + " " + c.profile.lastName,
value: c._id
};
});
}
}
},
I would like to do the same but for an array of objects. Here is what the source data looks like:
{
"_id": "xDkso4FXHt63K7evG",
"AboveGroundSections": [{
"sectionName": "one"
}, {
"sectionName": "two"
}],
"AboveGroundItems": [{
"itemSection": "one",
"itemDescription": "dfgsdfg",
"itemCode": "dsfgsdg"
}, {
"itemSection": "two",
"itemDescription": "sdfgsdfg",
"itemCode": "sdfgsdgfsd"
}]
}
Here is what my function looks like:
agSection: {
type: String,
optional: true,
autoform: {
firstOption: 'Select A Section Type',
options: function() {
return TemplateData.find({}, {
sort: {
AboveGroundSections: 1,
sectionName: [0]
}
}).map(function(c) {
return {
label: c.AboveGroundSections.sectionName,
value: c.AboveGroundSections.sectionName
}
});
}
}
},
I know this, it's just not pulling the data for me. I am sure, I am just missing something small. I am trying to pull all objects within the AboveGroundSection array.
Your .map() is iterating over the set of documents but not over the arrays inside each document. Also I don't think your sorting is going to work the way you hope because of the inner nesting.
Try:
agSection: {
type: String,
optional: true,
autoform: {
firstOption: 'Select A Section Type',
options() {
let opt = [];
TemplateData.find().forEach(c => {
c.AboveGroundSections.forEach(s => { opt.push(s.sectionName) });
});
return opt.sort().map(o => { return { label: o, value: o } });
}
}
},
Also if your AboveGroundSections array only has a single key per element then you can simplify:
"AboveGroundSections": [
{ "sectionName": "one" },
{ "sectionName": "two" }
]
To:
"AboveGroundSections": [
"one",
"two"
]

Collapse all nodes initially Infragistics IgTree

I am using the following Infragistics component for viewing hierarchical data. http://www.igniteui.com/tree/drag-and-drop-single-tree
I have initialized the tree view like below to see all the nodes of the tree expanded initially. Can someone please suggest me if I am missing any option to display all nodes collapsed initially?
$("#tree").igTree({
checkboxMode: "off",
singleBranchExpand: true,
nodeClick: function (evt, ui) {
if (ui.node.data.Folder == "") {
var agreements = [];
var entry = [];
entry.push(ui.node.data.AgreementNbr);
entry.push(ui.node.data.ExternalDescription);
entry.push(ui.node.data.Description);
entry.push(ui.node.data.EffDate);
entry.push(ui.node.data.ExpDate);
entry.push(ui.node.data.ReleaseStatus);
agreements.push(entry);
$('#example').DataTable({
responsive: true,
columns: [
{ title: "Agreement Number" },
{ title: "External Description" },
{ title: "Description" },
{ title: "Effective Date." },
{ title: "Expiry Date" },
{ title: "Release Status" }
],
data: agreements,
destroy: true,
processing: true,
});
}
else {
var output = ui.node.data.Folder.map(function (obj) {
var a = [obj.AgreementNbr, obj.ExternalDescription, obj.Description, obj.EffDate, obj.ExpDate, obj.ReleaseStatus];
return Object.keys(a).map(function (key) {
return a[key];
});
});
console.log(output);
$('#example').DataTable({
responsive: true,
columns: [
{ title: "Agreement Number" },
{ title: "External Description"},
{ title: "Description"},
{ title: "Effective Date"},
{ title: "Expiry Date"},
{ title: "Release Status"}
],
data : output,
destroy: true
});
}
},
dataSource: files,
dataSourceType: "json",
initialExpandDepth: 0,
pathSeparator: ".",
bindings: {
textKey: "Text",
valueKey: "Value",
imageUrlKey: "ImageUrl",
childDataProperty: "Folder",
Description: "Description"
},
// Enable Drag-and-drop feature
dragAndDrop: false
});
Use the initialExpandDepth option
initialExpandDepth : -1
You have that option set to 0.
If you set the initialExpandDepth to -1, all nodes should display collapsed initially.
You can see infragistics.com for more information.

Categories