I'm requesting data from a remote server with json return in format :
[
{"id":"1", "parent": "#", "text" : "Parent1"},
{"id":"2", "parent": 1, "text" : "Child1"}
{"id":"3", "parent": 2, "text" : "Child12"}
{"id":"4", "parent": 1, "text" : "Child2"}
{"id":"5", "parent": 1, "text" : "Child3"}
{"id":"6", "parent": 4, "text" : "Child21"}
]
I would like to check if the selected node is a parent. I use this code:
$('#treeview').on("select_node.jstree", function (e, data) {
var isParent = data.instance.is_parent();
alert(isParent)
});
It always returns false even when I click on PARENT.
What am I missing here ?
UPDATE
This is how I get solved the issue. But I still wonder why the methods is_parent() and is_leaf() are not working
var isParent = (data.node.children.length > 0);
To get parent
use
var isParent = (data.node.children.length > 0);
alert(isParent );
$('#treeview').jstree({
'core': {
'data': [{
"id": "1",
"parent": "#",
"text": "Parent1"
}, {
"id": "2",
"parent": 1,
"text": "Child1"
},
{
"id": "21",
"parent": 2,
"text": "Child1"
},
{
"id": "3",
"parent": 2,
"text": "Child12"
}, {
"id": "4",
"parent": 1,
"text": "Child2"
}, {
"id": "5",
"parent": 1,
"text": "Child3"
},
{
"id": "6",
"parent": 4,
"text": "Child21"
},
{
"id": "7",
"parent": '#',
"text": "Parent 2"
},
{
"id": "8",
"parent": 7,
"text": "Child"
}
]
}
});
$('#treeview').on("select_node.jstree", function(e, data) {
// var isParent = data.instance.is_parent(data);
// If you need to check if a node is a root node you can use:
var isParent = (data.node.children.length > 0);
console.log(data.node);
alert(isParent)
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<div id="treeview"></div>
Related
I'm still new to recursive functions but I'm having trouble returning the object once found to a variable (currently searching based on ID). I've included a dataset below and what I have so far. The recursive function finds the correct matching item, but when it returns it, it just returns undefined to the variable. I have tried the solution here and also get the same problem I have where it just returns undefined instead of the object. Any help/pointers would be great!
const data = {
"navItems": [
{
"type": "directory",
"id" : 1,
"name": "Nav Title 1",
"children": [
{
"downloadUrl": "",
"content": "",
"id" : 2,
"type": "file",
"name": "File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"type": "file",
"id" : 3,
"name": "File 2.pdf"
},
{
"type": "directory",
"name": "Sub Title 1",
"id" : 4,
"children": [
{
"downloadUrl": "",
"content": "",
"type": "file",
"id" : 5,
"name": "Sub File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"type": "file",
"id" : 6,
"name": "Sub File 2.docx"
}
]
},
{
"type": "directory",
"name": "Sub Title 2",
"id" : 7,
"children": [
{
"type": "directory",
"id" : 8,
"name": "Sub Sub Title 1",
"children": [
{
"downloadUrl": "",
"id" : 9,
"content": "",
"type": "file",
"name": "Sub Sub File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"type": "file",
"id" : 10,
"name": "Sub Sub File 2.pdf"
}
]
},
{
"type": "directory",
"name": "Sub Sub Title 2",
"id" : 11,
"children": [
{
"downloadUrl": "",
"content": "",
"id" : 12,
"type": "file",
"name": "Sub Sub File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"id" : 13,
"type": "file",
"name": "Sub Sub File 2.pdf"
}
]
}
]
}
]
}
]
}
/* console.log(navigationConfig);*/
const searchNavItems = (navItem) => {
if (navItem.id == 10) {
console.log(navItem);
return navItem;
} else {
if (navItem.hasOwnProperty("children") && navItem.children.length > 0 && navItem.type == "directory") {
navItem.children.map(child => searchNavItems(child))
} else {
return false;
}
}
};
let dataItem = data.navItems.forEach((item => {
let nav = searchNavItems(item);
console.log(nav);
}))
console.log(dataItem)
in your fn there are couple of problems
when you are maping over children you are not returning the array of children
forEach does not return anything () => void, so you will need to create a new variable to hold that value
let dataItem;
data.navItems.forEach((item) => {
console.log(searchNavItems(item));
dataItem = searchNavItems(item);
});
hope this helps
Presented below is one possible way to achieve the desired objective.
Code Snippet
const mySearch = (needle, hayStack) => (
hayStack.some(({ id }) => id === needle)
? (
{children, ...rest} = hayStack.find(({ id }) => id === needle),
[{...rest}]
)
: hayStack.flatMap(
({ children = [] }) => mySearch(needle, children)
)
);
/* explanation of the above method
// method to search for element/s with given "id"
// finding "needle" (ie "id") in hayStack (ie, "array" of objects)
const mySearch = (needle, hayStack) => (
// check if needle exists in current array
hayStack.some(({ id }) => id === needle)
? ( // find the matching array elt, destructure to access
// "children" and "rest" props.
// send the props other than "children"
{children, ...rest} = hayStack.find(({ id }) => id === needle),
[{...rest}]
) // if needle is not present in current array
// try searching in the inner/nested "children" array
: hayStack.flatMap( // use ".flatMap()" to avoid nested return
// recursive call to "mySearch" with "children" as the hayStack
({ children = [] }) => mySearch(needle, children)
)
);
*/
const data = {
"navItems": [{
"type": "directory",
"id": 1,
"name": "Nav Title 1",
"children": [{
"downloadUrl": "",
"content": "",
"id": 2,
"type": "file",
"name": "File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"type": "file",
"id": 3,
"name": "File 2.pdf"
},
{
"type": "directory",
"name": "Sub Title 1",
"id": 4,
"children": [{
"downloadUrl": "",
"content": "",
"type": "file",
"id": 5,
"name": "Sub File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"type": "file",
"id": 6,
"name": "Sub File 2.docx"
}
]
},
{
"type": "directory",
"name": "Sub Title 2",
"id": 7,
"children": [{
"type": "directory",
"id": 8,
"name": "Sub Sub Title 1",
"children": [{
"downloadUrl": "",
"id": 9,
"content": "",
"type": "file",
"name": "Sub Sub File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"type": "file",
"id": 10,
"name": "Sub Sub File 2.pdf"
}
]
},
{
"type": "directory",
"name": "Sub Sub Title 2",
"id": 11,
"children": [{
"downloadUrl": "",
"content": "",
"id": 12,
"type": "file",
"name": "Sub Sub File 1.pdf"
},
{
"downloadUrl": "",
"content": "",
"id": 13,
"type": "file",
"name": "Sub Sub File 2.pdf"
}
]
}
]
}
]
}]
};
console.log(
'data for id: 10\n',
mySearch(10, data.navItems)?.[0]
);
console.log(
'data for id: 13\n',
mySearch(13, data.navItems)?.[0]
);
console.log(
'data for id: 9\n',
mySearch(9, data.navItems)?.[0]
);
console.log(
'data for id: 3\n',
mySearch(3, data.navItems)?.[0]
);
.as-console-wrapper { max-height: 100% !important; top: 0 }
Explanation
Inline comments added to the snippet above.
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
I have structure like below:
{
0: [{
"id": "1",
"parentId": "root",
"path": "root"
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [
"id": "4",
"parentId": "2",
"path": "2/4"
]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}]
}]
}
I have key "path" and now it's "parentId/id", but I would like to have path from root to this element, so it should looks "root/parentId/id/parentId/it..." etc. For example path: "root/1/2/4".
How can I dynamically put a value inside key "path" to get full path to root element?
Your data structure does not respect the childhood of each element, but considering this is not a part of the question, here is a simple recursive solution:
const data = [{
"id": "1",
"parentId": "root",
"path": "root",
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [{
"id": "4",
"parentId": "2",
"path": "2/4"
}
]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}
]
},
{
"id": "4",
"parentId": "2",
"path": "2/4"
}
];
function assignPath(tree, index, array, currentPath) {
tree.path = currentPath || 'root';
tree.children && tree.children.forEach(child => {
assignPath(child, null, null, `${tree.path}/${child.id}`);
});
}
data.forEach(assignPath);
console.log(data);
You will need to identify the root node and start with its path.
Then add each consecutive child id to the path end.
let obj = {
0: [{
"id": "1",
"parentId": "root",
"path": "root",
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [{
"id": "4",
"parentId": "2",
"path": "2/4"
}]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}]
}]
};
console.log(getRoute(obj[0][0], true)); // Identify root
function getRoute(node, isRoot) {
return node != null
? (isRoot
? (node.path + '/')
: ''
) + node.id + (node.children
? '/' + getRoute(node.children[0], false)
: '')
: '';
}
Recursive solution:
updatePath(array, 'root');
function updatePath(array, path) {
array.forEach((element, i) => {
element.path = path + '/' + (i + 1);
if(element.hasOwnProperty('children')) {
updatePath(element.children, element.path);
}
});
}
How would I be able to nest json object if the parent and its children was given as a property.
The data looks like:
"1": {
"id": 1,
"name": "foo",
"parent": null,
"root": 1,
"children": [2, 4, 6],
"posts":[
{ "id": "1", "name": "item1" },
{ "id": "2", "name": "item2" },
{ "id": "3", "name": "item3" }
]
},
"2": {
"id": 2,
"name": "bar",
"parent": 1,
"root": 1,
"children": null,
"posts":[
{ "id": "4", "name": "item4" }
]
},
"3": {
"id": 3,
"name": "bazz",
"parent": null,
"root": 3,
"children": [5, 7],
"posts":[
{ "id": "5", "name": "item5" },
{ "id": "6", "name": "item6" }
]
},
....
A simple groupby using lodash won't do it.
var group = _.groupBy(data, 'parent');
Here is a fiddle:
http://jsfiddle.net/tzugzo8a/1/
The context of question is a nested categories with subcategories, and categories can have categories and posts in them.
Basically I don't want to have a different property for children and posts, since they are all children of a parent.
Desired output
"1": {
"id": 1,
"name": "foo",
"parent": null,
"root": 1,
"isCategory": true,
"children": [
{
"id": 2,
"name": "bar",
"parent": 1,
"root": 1,
"isCategory": true,
"children": null
},
{ "id": "1", "name": "item1", isCategory: false },
{ "id": "2", "name": "item2", isCategory: false },
{ "id": "3", "name": "item3", isCategory: false }
]
...
}
This is my take on the question (fiddle):
var data = getData();
var group = getTree(data);
console.log(group);
function getTree(flat) {
return _.reduce(flat, function (treeObj, item, prop, flatTree) {
var children = _.map(item.children, function (childId) {
return _.set(flatTree[childId], 'isCategory', true);
}).concat(_.map(item.items, function(item) {
return _.set(item, 'isCategory', false);
}));
item.children = !!children.length ? children : null;
delete item.items;
item.parent === null && (treeObj[prop] = item);
return treeObj;
}, {});
}
Take a look on the updated fiddle:
var data = getData();
_.keys(data).forEach(function(id){
var element = data[id];
if (element.children === null){
element.children = [];
}
element.isCategory = true;
element.items.forEach(function(item){
item.isCategory = false;
})
});
_.keys(data).forEach(function(id){
var element = data[id];
element.children = element.children.map(function(childId){
return data[childId];
}).concat(element.items);
});
_.keys(data).forEach(function(id){
delete data[id].items;
});
console.log(JSON.stringify(_.findWhere(_.values(data), {'parent': null})));
I'm planning on using materialized paths in MongoDB to represent a tree and need to convert the materialized paths back into a JSON tree.
ex.
// Materialized path
var input = [
{"id": "0", "path": "javascript" },
{"id": "1", "path": "javascript/database" },
{"id": "2", "path": "javascript/database/tree" },
{"id": "3", "path": "javascript/mvc" },
{"id": "4", "path": "javascript/mvc/knockout.js"},
{"id": "5", "path": "javascript/mvc/backbone.js"},
{"id": "6", "path": "c++" },
{"id": "7", "path": "c++/c0xx"},
{"id": "8", "path": "c++/c0xx/lambda expressions"},
{"id": "9", "path": "c++/c0xx/vc10" }
];
The result would be:
[
{
"id": "0",
"name": "javascript",
"children": [
{
"id": "1",
"name": "database",
"children": [
{
"id": "2",
"name": "tree",
"children": []
}
]
},
{
"id": "3",
"name": "mvc",
"children": [
{
"id": "4",
"name": "knockout.js",
"children": []
},
{
"id": "5",
"name": "backbone.js",
"children": []
}
]
}
]
},
{
"id": "6",
"name": "c++",
"children": [
{
"id": "7",
"name": "c0xx",
"children": [
{
"id": "8",
"name": "lambda expressions",
"children": []
},
{
"id": "9",
"name": "vc10",
"children": []
}
]
}
]
}
]
I found Convert delimited string into hierarchical JSON with JQuery which works fine.
And I also found Build tree from materialized path which is written in Ruby and uses recursion. I'm interested and curious to see this implemented in Javascript and wonder whether there are any folks that are fluent in both Ruby and Javascript who would like to rewrite it. I did try a Ruby to JS converter, but the result was incomprehensible.
Thanks,
Neville
var Comment = new Schema({
date : {
type : Date,
default : Date.now
},
event: ObjectId,
body : String,
pathComment : String,
user: Array
})
Comment.virtual('level').get(function() {
return this.pathComment.split(',').length;
});
Comment.find({event: event.id}).sort({pathComment:1}).exec(function(err, comment){
var collectComment = function(comment){
return {
body: comment.body,
event: comment.event,
pathComment: comment.pathComment,
id: comment._id,
level: comment.level,
user: comment.user[0],
date: comment.date,
comments: []
};
}
var tplComment = [];
var createChildComment = function(comment, currentNode, level){
if(level==1){
comment.push(collectComment(currentNode));
}else{
createChildComment(comment[comment.length-1]['comments'], currentNode,level-1);
}
return;
}
for(var k in comment){
createChildComment(tplComment, comment[k],comment[k].level);
}
});