Étant donné le tableau JSON suivant:
function rtnSocket(cmd, data, cb){ socket.emit(cmd, data); socket.on(cmd, cb); } rtnSocket('get-folders', folderid, function(data){ console.log(data); });
Je dois créer une arborescence de menus avec les sous-dossiers imbriqués sous les dossiers parents.
Voici un code côté serveur:
socket.on('get-folders', function(data){ var folders = []; getSession(session.key, function(currSession){ db.rows('getFolders', currSession, [currSession.user], function(err, rows){ if (err) { socket.emit('err', 'Error is: ' + err ); } else if(rows[0]){ //~ folders.push(JSON.stringify(rows)); socket.emit('get-folders', JSON.stringify(rows)); //~ n_Folders(rows, currSession, socket, folders, 0); } }); }); });
et côté client:
[{"ID":12,"NAME":"ktc","PARENTID":0}, {"ID":11,"NAME":"root","PARENTID":0}, {"ID":1,"NAME":"rwhitney","PARENTID":0}, {"ID":21,"NAME":"shared folder","PARENTID":0}, {"ID":2,"NAME":".config","PARENTID":1}, {"ID":5,"NAME":"wallpapers","PARENTID":1}, {"ID":3,"NAME":"geany","PARENTID":2}, {"ID":4,"NAME":"colorschemes","PARENTID":3}, {"ID":13,"NAME":"efast","PARENTID":12}, {"ID":15,"NAME":"includes","PARENTID":13}, {"ID":14,"NAME":"views","PARENTID":13}, {"ID":17,"NAME":"css","PARENTID":15}, {"ID":16,"NAME":"js","PARENTID":15}]
quelqu'un peut-il s'il vous plaît m'aider à me guider dans la bonne direction?
4 Réponses :
Vous pouvez collecter tous les nœuds à partir d'une structure de données plate, utiliser ID
et PARENTID
comme clés dans une table de hachage et obtenir le tableau racine comme résultat.
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = [{ ID: 12, NAME: "ktc", PARENTID: 0 }, { ID: 11, NAME: "root", PARENTID: 0 }, { ID: 1, NAME: "rwhitney", PARENTID: 0 }, { ID: 21, NAME: "shared folder", PARENTID: 0 }, { ID: 13, NAME: "efast", PARENTID: 12 }, { ID: 2, NAME: ".config", PARENTID: 1 }, { ID: 5, NAME: "wallpapers", PARENTID: 1 }, { ID: 15, NAME: "includes", PARENTID: 13 }, { ID: 14, NAME: "views", PARENTID: 13 }, { ID: 3, NAME: "geany", PARENTID: 2 }, { ID: 17, NAME: "css", PARENTID: 15 }, { ID: 16, NAME: "js", PARENTID: 15 }, { ID: 4, NAME: "colorschemes", PARENTID: 3 }], tree = function (data, root) { var t = {}; data.forEach(o => { Object.assign(t[o.ID] = t[o.ID] || {}, o); t[o.PARENTID] = t[o.PARENTID] || {}; t[o.PARENTID].children = t[o.PARENTID].children || []; t[o.PARENTID].children.push(t[o.ID]); }); return t[root].children; }(data, 0); console.log(tree);
J'ai opté pour une seule requête qui obtient les résultats dans un objet JSON utilisable. Avant, c'était un tableau d'objets et semblait maladroit.
Qu'est-ce que ça veut dire? veuillez modifier la question, si nécessaire.
Nina, je viens de mettre à jour ma question pour refléter ce que j'utilise maintenant. Je dois maintenant convertir le JSON en une arborescence hiérarchique visuelle. Pouvez-vous donner des conseils à ce sujet?
vous pourriez poser une autre question, car pour une apparence visuelle, vous avez besoin d'un certain style et j'en aurais besoin d'un exemple.
J'ai essayé de poser une autre question, mais elle a été presque fermée immédiatement, alors je l'ai supprimée. Apparemment, je ne suis pas doué pour poser des questions. :(
Je pense que je suis sur quelque chose de toute façon! Merci
Il est préférable de placer les sous-dossiers à l'intérieur de l'objet parent en tant que tableau de sous-dossiers .. cela éliminera ParentID et facilitera la traversée
[ { "ID": 1, "NAME": "rwhitney", "PARENTID": 0, "SUB": [ { "ID": 2, "NAME": ".config", "PARENTID": 1, "SUB": [ { "ID": 3, "NAME": "geany", "PARENTID": 2, "SUB": [ { "ID": 4, "NAME": "colorschemes", "PARENTID": 3 } ] } ] }, { "ID": 5, "NAME": "wallpapers", "PARENTID": 1 } ] } ]
La question était de savoir comment faire cela. Vraisemblablement, la structure de tableau fournie est disponible quelque part, et il y a maintenant une raison de la convertir en arbre.
Au début, nous devons mettre à plat un tableau imbriqué:
let data = [ [{ ID: 12, NAME: "ktc", PARENTID: 0 }, { ID: 11, NAME: "root", PARENTID: 0 }, { ID: 1, NAME: "rwhitney", PARENTID: 0 }, { ID: 21, NAME: "shared folder", PARENTID: 0 }], [{ ID: 13, NAME: "efast", PARENTID: 12 }], [{ ID: 2, NAME: ".config", PARENTID: 1 }, { ID: 5, NAME: "wallpapers", PARENTID: 1 }], [{ ID: 15, NAME: "includes", PARENTID: 13 }, { ID: 14, NAME: "views", PARENTID: 13 }], [{ ID: 3, NAME: "geany", PARENTID: 2 }], [{ ID: 17, NAME: "css", PARENTID: 15 }, { ID: 16, NAME: "js", PARENTID: 15 }], [{ ID: 4, NAME: "colorschemes", PARENTID: 3 }]]; const flatArray = (arr) => { return arr.reduce((flat, toFlatten) => { return flat.concat(Array.isArray(toFlatten) ? flatArray(toFlatten) : toFlatten); }, []); } const makeTree = dataset => { let hashTable = Object.create(null) dataset.forEach( aData => hashTable[aData.ID] = { ...aData, childNodes : [] } ) let dataTree = [] dataset.forEach( aData => { if( aData.PARENTID ) hashTable[aData.PARENTID].childNodes.push(hashTable[aData.ID]) else dataTree.push(hashTable[aData.ID]) } ) return dataTree } const dataTree = makeTree(flatArray(data)); console.log(dataTree)
Ensuite, nous pouvons créer un arbre:
const makeTree = dataset => { let hashTable = Object.create(null) dataset.forEach( aData => hashTable[aData.ID] = { ...aData, childNodes : [] } ) let dataTree = [] dataset.forEach( aData => { if( aData.PARENTID ) hashTable[aData.PARENTID].childNodes.push(hashTable[aData.ID]) else dataTree.push(hashTable[aData.ID]) } ) return dataTree }
Un exemple: p>
const flatArray = (arr) => { return arr.reduce((flat, toFlatten) => { return flat.concat(Array.isArray(toFlatten) ? flatArray(toFlatten) : toFlatten); }, []); }
Je dois répondre à ma propre question avec l'aide de Nina ci-dessus:
Avec l'objet JSON donné - réponse de Nina:
recurse(data,0,0);
J'ai trouvé ceci fonction:
var LHR= '',folderid = 0, parentid = 0; var seg = location.pathname.split('/')[2]; if(seg){ LHR = seg.split('_')[0]; folderid = seg.split('_')[1] || 0; //~ alert(folderid); parentid = seg.split('_')[2] || 0; if(isLike(LHR,['share']) == true){ sharedFileID = LHR.split('-')[1]; } } LHR = LHR.replace(/%20/g,' '); var MLHR = isLike(LHR, ['share']) == true ? LHR.split('-')[0] : LHR; var folders = ''; function recurse(data, indent, limit){ if(limit < 10){ for(var i = 0;i<data.length;i++){ if(folderid == data[i].ID){ folders += '<div><input style="margin-left:60px" type="checkbox" data-id="'+folderid+'" data-name="' + data[i].NAME + '" class="check-folder tooltip">'+ '<img style="margin-left:0px" data-pid="'+parentid+'" id="folder-'+folderid+'" src="/fa/folder-open.svg" class="blk tooltip"> ' + MLHR.replace(/%20/g,' ') + ' </div>'; } else { folders += '<input type="checkbox" style="margin-left:'+indent+'px" data-id="'+data[i].ID+'" data-name="' + data[i].NAME + '" class="check-folder tooltip">'+ '<a style="margin-left:70px" ondrop="drop(event)" ondragover="allowDrop(event)" class="dsp-ib w150 blk folders drop drag" draggable="true" droppable="true" href="/dashboard/'+data[i].NAME+'_'+data[i].ID+'_'+data[i].PARENTID+'">'+ '<img data-pid="'+data[i].PARENTID+'" src="/fa/folder.svg" class="fa ml--80 blk dsp-ib" id="folder-'+data[i].ID+'"> ' + data[i].NAME + '</a><br>'; } if(data[i].children){ recurse(data[i].children, indent+=20, ++limit); } } } $('#folders').html(folders); }
et appelez-la comme ceci:
[{"ID":12,"NAME":"ktc","PARENTID":0},{"ID":11,"NAME":"root","PARENTID":0},{"ID":1,"NAME":"rwhitney","PARENTID":0},{"ID":21,"NAME":"shared folder","PARENTID":0},{"ID":2,"NAME":".config","PARENTID":1},{"ID":5,"NAME":"wallpapers","PARENTID":1},{"ID":3,"NAME":"geany","PARENTID":2},{"ID":4,"NAME":"colorschemes","PARENTID":3},{"ID":13,"NAME":"efast","PARENTID":12},{"ID":15,"NAME":"includes","PARENTID":13},{"ID":14,"NAME":"views","PARENTID":13},{"ID":17,"NAME":"css","PARENTID":15},{"ID":16,"NAME":"js","PARENTID":15},{"ID":27,"NAME":"images","PARENTID":16}]
La fonction remplit l'arborescence des "dossiers" id p>
avec la sortie suivante:
Merci encore de m'avoir mis sur la bonne voie!
il est généralement préférable d'utiliser une bibliothèque existante pour cela.
Merci, mais j'ai besoin d'apprendre les mécanismes d'un menu en forme d'arbre. Et je ne veux pas utiliser une bibliothèque, si je peux l'aider.
Ok, je pensais que c'était pour un vrai projet. (Dans ce cas, il perdrait beaucoup de temps).
Pourquoi avez-vous besoin du côté serveur pour un menu arborescent?
la sécurité, c'est pour un vrai projet
il est préférable de mettre les sous-dossiers à l'intérieur de l'objet parent en tant que tableau de sous-dossiers .. cela éliminera ParentID et facilitera la traversée