Reputation: 13
How do I create a nested menu (with "sub-sub-sub...-n") items from my JSON, based on the "id" and the "pid"?
Code details:
id - item ID
lvl - level of the item
pid - parent ID of the item
pos - position of the item
nm - name of the item
JSON:
[{"id":1,"lvl":0,"pid":0,"pos":0,"nm":"HomeTree"},
{"id":5,"lvl":1,"pid":1,"pos":0,"nm":"Books"},
{"id":2,"lvl":1,"pid":1,"pos":1,"nm":"Jobs"},
{"id":16,"lvl":1,"pid":1,"pos":2,"nm":"Music"},
{"id":17,"lvl":2,"pid":16,"pos":0,"nm":"Relax Sets"},
{"id":12,"lvl":1,"pid":1,"pos":3,"nm":"Cars"},
{"id":13,"lvl":2,"pid":12,"pos":0,"nm":"BMW"},
{"id":14,"lvl":1,"pid":1,"pos":4,"nm":"Web"},
{"id":15,"lvl":2,"pid":14,"pos":0,"nm":"PHP Analytics"},
{"id":18,"lvl":1,"pid":1,"pos":5,"nm":"Hardware"},
{"id":19,"lvl":2,"pid":18,"pos":0,"nm":"EVGA SR2 Upgrades"},
{"id":31,"lvl":2,"pid":18,"pos":1,"nm":"Keyboards"},
{"id":20,"lvl":1,"pid":1,"pos":6,"nm":"Movies"},
{"id":21,"lvl":1,"pid":1,"pos":7,"nm":"Games"},
{"id":22,"lvl":1,"pid":1,"pos":8,"nm":"Robots"},
{"id":25,"lvl":1,"pid":1,"pos":9,"nm":"Magazines"},
{"id":26,"lvl":2,"pid":25,"pos":0,"nm":"IT Security"},
{"id":27,"lvl":1,"pid":1,"pos":10,"nm":"Management"},
{"id":28,"lvl":2,"pid":27,"pos":0,"nm":"Holacracy"},
{"id":29,"lvl":3,"pid":28,"pos":0,"nm":"Testtt"}]
What I need:
HomeTree
Books
Jobs
Music
Relax Sets
Cars
BMW
Web
PHP Analytics
Hardware
EVGA SR2 Upgrades
Keyboards
Movies
Games
Robots
Magazines
IT Security
Management
Holacracy
Testtt
My current code:
$.ajax({
url: './jstree_head.php?operation=full_tree',
data: "",
dataType: 'json',
success: function(data)
{
var output="<br />";
for (var i in data)
{
var rid = data[i].id;
var rpid = data[i].pid;
var rlvl = data[i].lvl;
var rnm = data[i].nm;
var nest = ' ';
if(rpid > 1) {
nm = nest+rnm+'<br>';
}
else {nm = rnm+'<br>';}
output+='' + nm + '';
}
$('#content').html(output);
}
});
Right now I can't account for deep sub-sub levels, what is the right way to do that?
--- UPDATE ---
What I tried is:
var nest = ' ';
if(rpid > 1) {
nm = nest+rnm+'<br>';
}
else {nm = rnm+'<br>';}
output+='' + nm + '';
But this does only one level of parent items.
Upvotes: 0
Views: 2642
Reputation: 826
Since your output is not formatted, I am first creating a hierarchy of parent-child which is then being used to print the output. Instead of directly storing the values in string, I am using JSON as it's much easier to dynamically add child there.
var data = [{"id":1,"lvl":0,"pid":0,"pos":0,"nm":"HomeTree"},
{"id":5,"lvl":1,"pid":1,"pos":0,"nm":"Books"},
{"id":2,"lvl":1,"pid":1,"pos":1,"nm":"Jobs"},
{"id":16,"lvl":1,"pid":1,"pos":2,"nm":"Music"},
{"id":17,"lvl":2,"pid":16,"pos":0,"nm":"Relax Sets"},
{"id":12,"lvl":1,"pid":1,"pos":3,"nm":"Cars"},
{"id":13,"lvl":2,"pid":12,"pos":0,"nm":"BMW"},
{"id":14,"lvl":1,"pid":1,"pos":4,"nm":"Web"},
{"id":15,"lvl":2,"pid":14,"pos":0,"nm":"PHP Analytics"},
{"id":18,"lvl":1,"pid":1,"pos":5,"nm":"Hardware"},
{"id":19,"lvl":2,"pid":18,"pos":0,"nm":"EVGA SR2 Upgrades"},
{"id":31,"lvl":2,"pid":18,"pos":1,"nm":"Keyboards"},
{"id":20,"lvl":1,"pid":1,"pos":6,"nm":"Movies"},
{"id":21,"lvl":1,"pid":1,"pos":7,"nm":"Games"},
{"id":22,"lvl":1,"pid":1,"pos":8,"nm":"Robots"},
{"id":25,"lvl":1,"pid":1,"pos":9,"nm":"Magazines"},
{"id":26,"lvl":2,"pid":25,"pos":0,"nm":"IT Security"},
{"id":27,"lvl":1,"pid":1,"pos":10,"nm":"Management"},
{"id":28,"lvl":2,"pid":27,"pos":0,"nm":"Holacracy"},
{"id":29,"lvl":3,"pid":28,"pos":0,"nm":"Testtt"}];
var output="<br />";
var res = [];
function createRelationship(){
for (var i in data)
{
if(data[i].pid == 0 && data[i].id == 1){
res.push({
id: data[i].id,
nm: data[i].nm
});
}
else{
var parent = findParent(data[i].pid, res);
if(parent){
if(!parent.items){
parent.items = [];
}
parent.items.push({
id: data[i].id,
nm: data[i].nm
});
}
}
}
}
function findParent(pid, _res){
if(_res){
if(_res.id == pid){
return _res;
}
var len = _res.length ? _res.length : _res.items ? _res.items.length : 0;
for(var i =0; i< len; i++){
if(_res[i] && _res[i].id == pid){
return _res[i];
}
else{
var child = _res[i] ? _res[i] : _res;
if(child){
for(var j=0;j<child.items.length;j++){
var res = findParent(pid, child.items[j]);
if(res){
return res;
}
}
}
}
}
}
return null;
}
function printOutPut(obj, spaceCount){
var space = '';
for(var i = 0; i< spaceCount; i++){
space+= ' ';
}
output += space + obj.nm;
output += "<br />";
if(obj.items){
for(i = 0; i < obj.items.length; i++){
printOutPut(obj.items[i], (spaceCount + 4));
}
}
}
createRelationship();
for(var z =0; z<res.length;z++){
printOutPut(res[z], 1);
}
document.write(output);
Upvotes: 1
Reputation: 91555
Since your data is a flat array, as opposed to nested JSON objects, you can't use a recursive function.
Instead, you can loop over all the elements, keeping track of a list parents as the lvl
attribute changes. As the lvl
increases, add the previous element to your list of parents and use this latest parent for all following items. As the lvl
decreases, remove a latest parent from the list and use the one before it in the list instead for all following items.
Upvotes: 0