javascript tree with path for each node - javascript

i'm trying to make a tree with the path for each node :
Plunkr of actual demo (see console only): https://plnkr.co/edit/peCIZcSzChF3b2WnaOxk?p=preview
the original datas :
(this is a list of tags, the "parent" is the parent ID )
var originals=[
{"id":1,"name":"Grammaire","parent":null},
{"id":2,"name":"Orthographe","parent":null},
{"id":8,"name":"Orthographe lexicale","parent":2},
{"id":9,"name":"Orthographe grammaticale","parent":2},
{"id":10,"name":"Adjectif couleur","parent":9},
{"id":11,"name":"Nombre","parent":8},
{"id":12,"name":"Annalyse grammaticale","parent":1},
{"id":19,"name":"Concordance des temps","parent":1},
{"id":20,"name":"annalyse 2","parent":12}
];
So it should make a tree like this :
1-Grammaire
12-Annalyse grammaticale
20-Annalyse 2
19-Concordance des temps
2-Orthographe
8-Orthographe lexicale
9-Orthographe grammaticale
10-Adjectif couleur
11-Nombre
I get a code who make it :
function convert(array){
var map = {};
for(var i = 0; i < array.length; i++){
var obj = array[i];
obj["children"] = [];
map[obj.id] = obj;
var parent = obj.parent || '-';
if(!map[parent]){
map[parent] = {
children: []
};
}
map[parent].children.push(obj);
}
return map['-'].children;
}
And the result :
[
{"id":1,"name":"Grammaire","parent":null,
"children":[
{"id":12,"name":"Annalyse grammaticale","parent":1,
"children":[{"id":20,"name":"annalyse 2","parent":12,"children":[]}]
},
{"id":19,"name":"Concordance des temps","parent":1,"children":[]}
]},
{"id":2,"name":"Orthographe","parent":null,
"children":[
{"id":8,"name":"Orthographe lexicale","parent":2,
"children":[
{"id":11,"name":"Nombre","parent":8,"children":[]}]
},
{"id":9,"name":"Orthographe grammaticale","parent":2,
"children":[{"id":10,"name":"Adjectif couleur","parent":9,"children":[]}]
}
]
}
]
PROBLEM !
for example for the node with id = 20
{"id":20,"name":"annalyse 2","parent":12,"children":[]}
I need to get for this node the parent node id and name like this :
{"id":20,"name":"annalyse 2","parent":12,"children":[]
"parentNodes"= [{"id":1,"name":"Grammaire"},{"id":12,"name":"Annalyse grammaticale"},{"id":20,"name":"annalyse 2"}]
}
I don't want cyclic solution because i already make it and make my code bug because i need to clone this object.
Any help is welcomed, i know i have to make a recursive function who add the "path" but i fail until now
thanks

maybe need some fix but work !
function setPath(array){
function initPath(node,liste){
liste.push({"id":node.id,"name":node.name});
node["path"] = tools_clone(liste) ;
for(var n in node.children){
initPath(node.children[n],tools_clone(liste));
}
}
for(var i = 0; i < array.length; i++) {
var p = [];
initPath(array[i],p);
}
}
var r = convert(originals);
setPath(r);

Related

Javascript module pattern with array

I have an exercise which i don´t really understand, so I hope for some help for this.
I should hardcode a simple array and the exercise tells me this:
Often, when we create our web applications, we have the need for test data. Implement a reusable nodejs module, using JavaScripts module pattern, which can provide random test data as sketched below:
var data = dataGenerator.getData(100,"fname, lname, street, city, zip");
This should return a JavaScript array (not JSON) with 100 test data on the form:
[{fname: "Bo", lname:"Hansen", street: "Lyngbyvej 26", city: "Lyngby", zip: "2800"},..]
If you call it like this:
var data = dataGenerator.getData(25,fname, lname);
it should return 25 test data as sketched below:
[{fname: "Bo", lname:"Hansen"},..]
I have some code here, but this dosen´t work yet:
var dataGenerator = (function () {
var data = [
{
fname : "Bo",
lname : "Bosen",
...
},
{
fname : "jashkjh",
lname : "jhsdkfj",
...
},
...
];
return {getData : function (count, fields) {
var result = [];
var i = 0;
var field;
var j;
fields = fields.split(/\s*,\s*/);
while (i < count && i < data.length) {
result.push({});
// Det objekt vi arbejder på lige nu er i result[i]
for (j = 0; j < fields.length; j++) {
result[i][fields[j]] = data[i][fields[j]];
}
i++;
}
return result;
}};
})();
module.exports = dataGenerator;
I do not know the data body, but could try:
var data=[{fname:"Bo",lname:"Bosen",street:"Lyngbyvej 26",city:"Lyngby",zip:"2800"},{fname:"jashkjh",lname:"jhsdkfj",street:"Fmsn 9",city:"Pra",zip:"1600"},{fname:"eeee",lname:"aaaa",street:"Eda 5",city:"Pre",zip:"3500"}];
var dataGenerator = {
getData: function(count, fieldsStr){
var result = [], fields = fieldsStr.split(/\s*,\s*/), i = 0;
while(i < count && data[i]){
var item = {};
fields.forEach(function(key){
item[key] = data[i][key]
});
result.push(item);
i++
}
return result
}
}
var results = dataGenerator.getData(2,"fname, zip");
document.write(JSON.stringify(results))

Efficient function for creating JSON data from File Directory Structure?

Like the title says, I have a directory structure, I want to convert it into a JSON format compatible for jsTree usage.
So the output for a given list
INPUT:
./Simple Root Node
./Root Node 2
./Root Node 2/Child 1
./Root Node 2/Child 2
OUTPUT:
treeJSON = [
{ "id" : "ajson1", "parent" : "#", "text" : "Simple root node" },
{ "id" : "ajson2", "parent" : "#", "text" : "Root node 2" },
{ "id" : "ajson3", "parent" : "ajson2", "text" : "Child 1" },
{ "id" : "ajson4", "parent" : "ajson2", "text" : "Child 2" },
]
My Method:
Currently, I'm taking each line from the input. Say ./Root Node 2/Child 1, then I pattern match the first folder, creating an array like { "id" : "ajson2", "parent" : "#", "text" : "Root node 2" }. Then go recursively for the next removing the first folder.Hence, creating the net array as { "id" : "ajson4", "parent" : "ajson2", "text" : "Child 2" }.
I do this for each line in the input and then use my unique array function as in http://jsfiddle.net/bsw5s60j/8/ to strip all the duplicate arrays which were created. For instance, { "id" : "ajson2", "parent" : "#", "text" : "Root node 2" } would be created twice. Once while going through the 3rd line and then the 4th line.
Clearly, this code is HIGHLY inefficient.If I have around 1.3K directories, then assume each has 4 sub directories, we have 5.2K arrays which have to be checked for duplicates.
This is creating a hge problem. Is there any other efficient way I can twaek this code?
Fiddle: (Works with Chrome Only because of the file webkit attribute) http://jsfiddle.net/bsw5s60j/8/
Javascript
var input = document.getElementById('files');
var narr = [];
var fileICON = "file.png";
//when browse button is pressed
input.onchange = function (e) {
var dummyObj = [];
var files = e.target.files; // FileList
for (var i = 0, f; f = files[i]; ++i) {
var fname = './' + files[i].webkitRelativePath;
narr = $.merge(dummyObj, (cat(fname)));
}
treeJSON = narr.getUnique(); // getting the JSON tree after processing input
console.log(JSON.stringify(treeJSON));
//creating the tree using jstree
$('#tree')
.jstree({
'core': {
'check_callback': true,
'data': function (node, cb) {
cb.call(this, treeJSON);
}
}
});
var tree = $('#tree').jstree(true);
tree.refresh();
};
//get unqiue array function
Array.prototype.getUnique = function () {
var o = {}, a = [];
for (var i = 0, l = this.length; i < l; ++i) {
if (o.hasOwnProperty(JSON.stringify(this[i]))) {
continue;
}
a.push(this[i]);
o[JSON.stringify(this[i])] = 1;
}
return a;
};
// categorizing function which converts each ./Files/Root/File.jpg to a JSON
var objArr = [];
var folderArr = [];
function cat(a) {
if (!a.match(/\/(.+?)\//)) {
var dummyObj = {};
var fname = a.match(/\/(.*)/)[1];
dummyObj.id = fname;
dummyObj.text = fname;
if (folderArr === undefined || folderArr.length == 0) {
dummyObj.parent = '#';
} else {
dummyObj.parent = folderArr[(folderArr.length) - 1];
dummyObj.icon = fileICON; // add extention and icon support
}
objArr.push(dummyObj);
return objArr;
} else {
if (a.charAt(0) == '.') {
var dummyObj = {};
var dir1 = a.match(/^.*?\/(.*?)\//)[1];
dummyObj.id = dir1;
dummyObj.text = dir1;
dummyObj.parent = '#';
dummyObj.state = {
'opened': true,
'selected': true
}; // not working
folderArr.push(dir1);
objArr.push(dummyObj);
var remStr = a.replace(/^[^\/]*\/[^\/]+/, '');
cat(remStr);
return objArr;
} else {
var dummyObj = {};
var dir1 = a.match(/^.*?\/(.*?)\//)[1];
dummyObj.id = dir1;
dummyObj.text = dir1;
dummyObj.parent = folderArr[(folderArr.length) - 1];
folderArr.push(dir1);
objArr.push(dummyObj);
var remStr = a.replace(/^[^\/]*\/[^\/]+/, '');
cat(remStr);
return objArr;
}
}
}
HTML
<input type="file" id="files" name="files[]" multiple webkitdirectory />
<div id="tree"></div>
Any changes or suggestions would be greatly helpful! Thanks
Here is a simple algorithm that should do quite efficiently, using a map from filepaths to their ids:
var idcount = 0;
var treeJSON = [];
var idmap = {};
function add(dirs) {
if (!dirs.length) return "#";
var name = dirs.join("/");
if (name in idmap)
return idmap[name];
var dir = dirs.pop();
var parent = add(dirs);
var id = "ajson" + ++idcount;
treeJSON.push({id: id, parent: parent, text: dir});
return idmap[name] = id;
}
var files = e.target.files; // FileList
for (var i=0; i<files.length; ++i) {
var name = files[i].webkitRelativePath;
add(name.split("/"));
}
return treeJSON;
(updated jsfiddle demo)
This is how you might use it for dynamic updates:
// initalise JStree here
var idcount = 0;
var treeJSON = [];
var idmap = {};
function add(dirs, isfolder) {
if (!dirs.length) return "#";
var name = dirs.join("/");
if (name in idmap) {
if (isfolder && idmap[name].icon)
delete idmap[name].icon;
return idmap[name];
}
var dir = dirs.pop();
var parent = add(dirs, true);
var id = "ajson" + ++idcount;
var item = {id: id, parent: parent, text: dir}
if (parent == "#")
item.state = {opened:true, selected:true};
if (!isfolder && dir.indexOf(".") > 0)
item.icon = fileICON;
treeJSON.push(item);
return idmap[name] = id;
}
input.onchange = function(e) {
var files = e.target.files; // FileList
for (var i=0; i<files.length; ++i) {
var name = files[i].webkitRelativePath;
add(name.split("/"), false);
}
// refresh JStree
};

How to dynamically generate javascript objects within other objects. Can you use a for loop inside an object?

I hope to achieve a set of javascript objects something like this:
tabs[0]={
sections[0]={
title:"section0",
children[0]={
title:"Child0"
},
children[1]={
title:"Child1"
},
children[2]={
title:"Child2"
}
},
sections[1]={
title:"section1",
children[0]={
title:"Child0"
},
children[1]={
title:"Child1"
}
}
};
tabs[1]={
sections[0]={
title:"section0",
children[0]={
title:"Child0"
},
children[1]={
title:"Child1"
}
},
sections[1]={
title:"section1",
children[0]={
title:"Child0"
},
children[1]={
title:"Child1"
}
},
sections[2]={
title:"section2",
children[0]={
title:"Child0"
},
children[1]={
title:"Child1"
}
}
};
Here is my code but I'm getting an "Unexpected Token" error at the first for loop within the tab object. Is this not allowed? How could I read these arrays and create objects like those above dynamically? The arrays (and subsequently the objects) can and will change as the .csv files change, which is why I need to dynamically create these objects. These objects will be used in with AngularJS's ng-repeat to create the tabbed and side navigation for an app.
this.tabData = tabsService.tabData;
var tabCount = tabsService.tabData.length;
var tabs={};
var tCounter = 0;
for (tCounter; tCounter<tabCount; tCounter++){
var tabURL = "Contents/Product Groups/"+this.tabData[tCounter]+"/sectionOrder.csv";
tabs[tCounter] ={
"TabSectionData" : $.getCsvArray(tabs[tCounter].tabURL), //gets array from csv file
"sectionCount" : TabSectionData.length
for (sCounter = 0; sCounter<tabs[tCounter].sectionCount; sCounter++){
"tabChildURL" : "Contents/Product Groups/"+this.tabData[tCounter]+"/"+tabs[tCounter].TabSectionData[sCounter]+"/order.csv",
"TabChildData" : $.getCsvArray(tabChildURL) //gets array from csv file
sections[sCounter] ={
"title" = tabs[tCounter].TabSectionData.[sCounter];
cCounter = 0;
for (cCounter = 0; cCounter<TabChildData.length; cCounter++){
children[cCounter]={
"title": tabs[tCounter].TabSectionData[sCounter].TabChildData.[cCounter]
}
}
}
}
}
}
You can run a loop inside a function and instantly execute the function.
I created a Snippet to exemplify.
var obj = {
name: 'My Object',
sections: (function () {
var result = [];
for (var i = 0; i < 10; i++) {
var it = {};
result[i] = it;
it.title = 'Hello';
it.children = [];
for (var j = 0; j < i; j++) {
it.children[j] = 'children' + j;
}
}
return result;
})()
};
var json = JSON.stringify(obj, null, 4);
jQuery('pre').append(json);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre></pre>
Regarding your question, 'Can you use for loop inside an object [literal] ', perhaps to create a list of properties, you may do something like this:
Enclose your for loop inside an immediately invoked function. From that function return the result of the loop.
For example:
I want to dynamically add an array of properties using for loop.
var items = {
list : (function(){ // immediately invoked function
var arr = []; // array
for (var i = 0; i < 4; i++)
{
arr.push('item no. '+i); // add each item to array
}
return arr; // return the array as value of the list property
})()
}
RESULT:
items = {
list : [
"item no. 0",
"item no. 1",
"item no. 2",
"item no. 3"
]
}

How to traverse through JSON data dynamically and make changes ..?

I have a map like data in JSON
var map = {
level1 : {
x : {name:'level1 x' , },
y : {name:'level1 y'}
},
level2 : {
x : {name:'level2 x'},
y : {name:'level2 y'}
}
}
I need to traverse through this data , i am getting the traverse path as an string
"level1 x name" , "level2 y name";
How can i parse through the JSON data from that string path..??
What i tried is ,
var path = "level1 x name".split(" ");
var pointer = map; // assuming it will take reference of map and change will cause to map also
for (var i = 0, len = path.length; i < len; i++) {
if(pointer){
pointer = pointer[path[i]];
}else{
pointer = map[path[i]];
}
}
pointer = "level1 xx";
console.log(map);
But map data is not changing.. how to loop through with reference and change the value ..?
This is how you get your value:
var name = [map].concat("level1 x name".split(" ")).reduce(function(prev, curr) {
return prev[curr];
});
console.log(name);
// -> 'level1 x'
JavaScript passes arguments by value, not by reference.
For your convenience I changed your code for you to acceomplish what you asked for:
var path = "level1 x name".split(" ");
var pointer = map; // assuming it will take reference of map and change will cause to map also
for (var i = 0, len = path.length-1; i < len; i++) {
if(pointer){
pointer = pointer[path[i]];
}else{
pointer = map[path[i]];
}
}
pointer[path[path.length-1]] = "level1 xx";
console.log(map);
Try This.. Change the path variable as required. It is working fine. I just verified it in firebug.
var map = {
level1 : {
x : {name:'level1 x' , },
y : {name:'level1 y'}
},
level2 : {
x : {name:'level2 x'},
y : {name:'level2 y'}
}
};
var path = "level1 x name";
var pathInfor = path.split(' ');
var pathLength = pathInfor.length;
//alert(map[pathInfor[0]][pathInfor[1]][pathInfor[2]].name);
for(level in map)
{
if(level == pathInfor[0]){
var selLevel = map[level];
for(xy in selLevel)
{
if(xy == pathInfor[1])
{
var selVariable = map[level][xy];
for(innerVal in selVariable){
if(innerVal == pathInfor[2]){
alert(map[level][xy][innerVal]);
}
}
}
}
}
}
In this method you are not required to check with the values. If you want to print all the values form JSON, remove the condition.

Javascript | Objects, Arrays and functions

may be you can help me. How can I create global object and function that return object values by id?
Example:
var chat = {
data : {
friends: {}
}
}
....
/*
JSON DATA RETURNED:
{"users": [{"friend_id":"62","name":"name","username":"admin","thumb":"images/avatar/thumb_7d41870512afee28d91.jpg","status":"HI4","isonline":""},{"friend_id":"66","name":"Another name","username":"regi","thumb":"images/avatar/thumb_d3fcc14e41c3a77aa712ae54.jpg","status":"Всем привет!","isonline":"avtbsl0a6dcelkq2bd578u1qt6"},{"friend_id":"2679","name":"My name","username":"Another","thumb":"images/avatar/thumb_41effb41eb1f969230.jpg","status":"","isonline":""}]}
*/
onSuccess: function(f){
chat.data.friends = {};
for(var i=0; i< f.users.length;i++){
chat.data.friends.push(f.users[i])
}
}
How can I create a new function (It will return values by friend_id)?
get_data_by_id: function (what, friend_id) {
/*obj.what = getfrom_globalobject(chat.data.friends???)*/
}
Example of use:
var friend_name = get_data_by_id(name, 62);
var friend_username = get_data_by_id(username, 62);
var friend_avatar = get_data_by_id(thumb, 62);
Try:
get_data_by_id: function (what, friend_id) {
return chat.data.friends[friend_id][what];
}
... but use it like:
var friend_name = get_data_by_id('name', 62);
...and set up the mapping with:
for(var i=0; i< f.users.length;i++){
chat.data.friends[f.users[i].friend_id] = f.users[i];
}
You cannot .push() to an object. Objects are key => value mappings, so you need to use char.data.friends[somekey] = f.users[i];
If you really just want a list with numeric keys, make x5fastchat.data.friends an array: x5fastchat.data.friends = [];
However, since you want to be able to access the elements by friend_id, do the following:
onSuccess: function(f){
x5fastchat.data.friends = {};
for(var i=0; i< f.users.length;i++){
chat.data.friends[f.users[i].friend_id] = f.users[i]
}
}
get_data_by_id: function (what, friend_id) {
obj[what] = chat.data.friends[friend_id][what];
}
Note the obj[what] instead of your original obj.what: When writing obj.what, what is handled like a string, so it's equal to obj['what'] - but since it's a function argument you want obj[what].
Take a look at the following code. You can simply copy paste it into an HTML file and open it. click "go" and you should see the result. let me know if I did not understand you correctly. :
<script>
myObj = { "field1" : { "key1a" : "value1a" }, "field2" : "value2" }
function go()
{
findField(myObj, ["field2"])
findField(myObj, ["field1","key1a"])
}
function findField( obj, fields)
{
var myVal = obj;
for ( var i in fields )
{
myVal = myVal[fields[i]]
}
alert("your value is [" + myVal + "]");
}
</script>
<button onclick="go()">Go</button>
I would recommend using the friend objects rather than getting them by id and name.
DATA = {"users": [{"friend_id":"62","name":"name","username":"admin","thumb":"images/avatar/thumb_7d41870512afee28d91.jpg","status":"HI4","isonline":""},{"friend_id":"66","name":"Another name","username":"regi","thumb":"images/avatar/thumb_d3fcc14e41c3a77aa712ae54.jpg","status":"Всем привет!","isonline":"avtbsl0a6dcelkq2bd578u1qt6"},{"friend_id":"2679","name":"My name","username":"Another","thumb":"images/avatar/thumb_41effb41eb1f969230.jpg","status":"","isonline":""}]}
// simple data store definition
Store = {items:{}};
NewStore = function(items){
var store = Object.create(Store);
store.items = items || {};
return store
};
Store.put = function(id, item){this.items[id] = item;};
Store.get = function(id){ return this.items[id]; };
Store.remove = function(id){ delete this.items[id]; };
Store.clear = function(){ this.items = {}; };
// example
var chat = {
data : {
friends : NewStore()
}
}
// after data loaded
chat.data.friends.clear();
for( var i = 0; i < DATA.users.length; i += 1 ){
var user = DATA.users[i];
chat.data.friends.put( user.friend_id, user );
}
getFriend = function(id){ return chat.data.friends.get( id ); }
var friend = getFriend(66);
console.log(friend.name);
console.log(friend.username);
console.log(friend.thumb);

Categories