0

So I'm making a folder list like structure in VueJs my problem is traversing down this object tree. Here's my tree:

    var data= {
      name:"root"
      id:0,
      isLeaf:false,
      parents:null,
      children:[
          {
        type: "TEST",
        linkageId: {},
        linkageWebProfileId: {},
        isActive: true,
        isLeaf: false,
        name: "TESTDATA",
        id: "1000",
        children:[
          {
            type: "TEST",
            linkageId: {},
            linkageWebProfileId: {},
            isActive: true,
            isLeaf: false,
            name: "TESTDATA",
            id: "1001",
          },
          {
            type: "TEST",
            linkageId: {},
            linkageWebProfileId: {},
            isActive: true,
            isLeaf: false,
            name: "TESTDATA",
            id: "1002",
          }
        ]
      },
      {
        type: "TEST",
        linkageId: {},
        linkageWebProfileId: {},
        isActive: true,
        isLeaf: false,
        name: "TESTDATA",
        id: "1003",
        children:[
          {
            type: "TEST",
            linkageId: {},
            linkageWebProfileId: {},
            isActive: true,
            isLeaf: false,
            name: "TESTDATA",
            id: "1004",
          },
          {
            type: "TEST",
            linkageId: {},
            linkageWebProfileId: {},
            isActive: true,
            isLeaf: true,
            name: "TESTDATA",
            id: "1005",
          }
        ]
      },
    
    ]
    
 }

I already made a function that makes a path from the new leaf to the last ancestor before the root, I can access root anytime by just referencing 'data'.

function makePath() {
 let ids=[];
        let treePointer=params //params is just a pointer to the newly created leaf

        while(treePointer.name!=="root"){
          ids.push(treePointer.id)
          treePointer=treePointer.parent
        } //traverses up to the root
}

If I were to insert at folder 1002 it would return:

[1649689828862, '1002', '1000']  //the first one is the auto generated id

children: null
id: 1649731709654
isLeaf: true
name: "New Leaf"
parent: A
children: Array(0)
    id: "1002"
    isActive: true
    isLeaf: false
    linkageId: Object
    linkageWebProfileId: Object
    name: "TESTDATA"
      parent: A
      children: Array(2)
      id: "1000"
      isActive: true
      isLeaf: false
      linkageId: Object
      linkageWebProfileId: Object
      name: "TESTDATA"
         parent: A
         children: Array(2)
         id: 0
         isLeaf: false
         name: "root"
         parent: null    
//This is the generated object that insert leaf creates, an inverted tree with the new leaf at the top

After this I remove the first index of the array, reverse it so the the new leaf's parent is the last index and save the newly generated id in a another variable My problem now is when I want to traverse from root down the tree and look for the new leaf parent it won't return the expected result, this is for when I want to insert a new file inside the same folder

 treePointer=this.data //resets treePointer to the root  

 ids.shift() //remove the leaf from the path

 ids.reverse() //make the path left to right the last one being the parent's leaf

 const children = [...this.data.children]  //gets the children of the root

        while(treePointer.id !== ids[ids.length-1]) {  //short circuit when the pointer is at leaf's parent
          treePointer= children.find(obj=>{ // keep reassigning treePointer until it traverses to the leaf's parent
            let node;
            for(var x =0; obj.id!== ids[x] && x < ids.length;x++, node=x) //traverses through the path and gets the correct id of the current array of children
            return obj.id === ids[node] //returns the obj in the treePointer's array of children that has the correct id
          })
        } 

I've re evaluated that code and logically it is sound however what I don't get is that the treePointer inside the while loop doesn't seem to get reassigned find it just remains at root when I console log it but eventually the treePointer gets to a node that doesn't have the property 'id' which means it has strayed to a wrong path and didn't short circuit and kept traversing down which does not make sense. Is there something wrong with my find function or am is this syntactical error on my end?

The code for the entire component

<template>
  <div class="py-8 px-5" style="min-height: calc(100vh - (112px + 2.75rem))">
    <div class="flex flex-col w-full">
      <button class="cursor-pointer relative flex flex-row items-center h-10 focus:outline-none " @click="addNode">
        <span class="text-sm tracking-wide truncate ml-6">Add Folder</span>
      </button>
    </div>
    <VueTreeList
      @click="onClick"
      @change-name="onChangeName"
      @delete-node="onDel"
      @add-node="onAddNode"
      ref="tree"
      :model="data"
      default-tree-node-name="New Folder"
      default-leaf-node-name="New File"
      v-bind:default-expanded="false"
    >
      <span class="icon" slot="addTreeNodeIcon">📂</span>
      <span class="icon" slot="addLeafNodeIcon">+</span>
      <span class="icon" slot="editNodeIcon">📃</span>
      <span class="icon" slot="delNodeIcon">✂️</span>
      <span class="icon" slot="leafNodeIcon">🍃</span>
      <span class="icon" slot="treeNodeIcon">📂</span>
    </VueTreeList>
  </div>
  
</template>

<script>
import { VueTreeList, Tree } from 'vue-tree-list'

const dummyData = [
  {
    type: "TEST",
    linkageId: {},
    linkageWebProfileId: {},
    isActive: true,
    isLeaf: false,
    name: "TESTDATA",
    id: "1000",
    children:[
      {
        type: "TEST",
        linkageId: {},
        linkageWebProfileId: {},
        isActive: true,
        isLeaf: false,
        name: "TESTDATA",
        id: "1001",
      },
      {
        type: "TEST",
        linkageId: {},
        linkageWebProfileId: {},
        isActive: true,
        isLeaf: false,
        name: "TESTDATA",
        id: "1002",
      }
    ]
  },
  {
    type: "TEST",
    linkageId: {},
    linkageWebProfileId: {},
    isActive: true,
    isLeaf: false,
    name: "TESTDATA",
    id: "1003",
    children:[
      {
        type: "TEST",
        linkageId: {},
        linkageWebProfileId: {},
        isActive: true,
        isLeaf: false,
        name: "TESTDATA",
        id: "1004",
      },
      {
        type: "TEST",
        linkageId: {},
        linkageWebProfileId: {},
        isActive: true,
        isLeaf: true,
        name: "TESTDATA",
        id: "1005",
      }
    ]
  },
]


const dummyData2= {
    type: "TEST",
    linkageId: {},
    linkageWebProfileId: {},
    isActive: true,
    isLeaf: true,
    name: "NEWTEST",
    id: "4",
    children:[]
}

export default {
    components: {
      VueTreeList
    },
    data() {
      return {
        data: new Tree([]),
      }
    },
    async mounted(){
      const parsedData = (dummyData) ? ([...dummyData]) : []
      this.data=new Tree([
        ...parsedData
      ])
    },

    methods: {

      onDel(node) {
        console.log('deletedNode',node)
        node.remove()
      },

      onChangeName(params) {
        console.log(params)
      },

      onAddNode(params) {
        if(params.isLeaf==true){
        let ids=[];
        let treePointer=params
        console.log('paramsContent', params)

        while(treePointer.name!=="root"){
          ids.push(treePointer.id)
          treePointer=treePointer.parent
        }

        console.log('pathLeaf to root', ids)

        this.onDel(params)  //delete the new leaf since the package immediately inserts it 

        treePointer=this.data //let pointer point to the local tree inside this component
        ids.shift()
        ids.reverse()
        const children = [...this.data.children]

        
        console.log('pathRoot to leafParent', ids)

        while(treePointer.id !== ids[ids.length-1]) {
          treePointer= children.find(obj=>{
            let node;
            for(var x =0;obj.id!== ids[x] && x< ids.length;x++, node=x)
            return obj.id === ids[node]
          })
        }

        treePointer.addChildren(dummyData2) //dummyData2 is the new data that is inputted by user
        }

      },


      onClick(params) {
        console.log(params)
      },

      addNode() {

      },

      
      addChild() {

      },
      
    }
  }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"></style>
6
  • Please provide code with which we can reproduce this. You reference a parent property, but the data structure has no parent properties. Can you provide one block of code that is runnable and reproduces your issue? Commented Apr 11, 2022 at 18:02
  • @trincot edited the post github.com/ParadeTo/vue-tree-list/blob/master/src/… <--- this is the tree component I'm working with the insertion and pathing is working fine the problem is in the traversing downwards Commented Apr 12, 2022 at 3:00
  • 1
    @Jam please can you share just the snippet part with structure of your code Commented Apr 12, 2022 at 7:19
  • @Chandan edited my post, added my entire code. Commented Apr 12, 2022 at 10:52
  • 1
    @Jam please check the answer and let know if explanation needs any changes. Commented Apr 12, 2022 at 14:59

1 Answer 1

1

There are few problems in below code

while(treePointer.id !== ids[ids.length-1]) {
  treePointer= children.find(obj => {
    let node;
    for(var x = 0; obj.id !== ids[x] && x < ids.length; x++, node=x)
      return obj.id === ids[node]
  })
}
  • First problem obj.id !== ids[x] this condition will never let the for loop run in case when it is equal so the loop will never check for obj.id === ids[node] so find would always get undefined which is equal to false
  • Second problem is node will remain undefined until second iteration because the increment part only runs after first iteration instead of node you can use x of for loop
  • Third problem is children is never getting update to next set of childrens so even though it find the leaf in first iteration it would find nothing in the second iteration so the while loop will run continuously
  • Fourth problem is even after removing obj.id !== ids[x] condition and updating children it would fail in second iteration because the foor loop will return in first iteration and it would never find leaf when moved to second obj.id

To solve the issues you can update the code as below:

let children = [...this.data.children];
while(treePointer.id !== ids[ids.length-1]) {
  treePointer = children.find(obj => {
    let result = false;
    for(var x = 0; x < ids.length; x++) {
      if (obj.id === ids[x]) {
        result = true;
        break;
      }
    }
    return result;
  });
  children = treePointer.children;
}

Working Example

Refactor Version

Since we already know the ids are sorted from root to the leaf node which we want to find we can update the code as below;

let children = [...this.data.children];
idx = 0;
while(treePointer.id !== ids[ids.length-1]) {
  treePointer = children.find(obj => ids[idx] == obj.id);
  children = treePointer.children;
  idx += 1;
}

Working Example

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.