Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vuetify v-treeview - How to open programmatically a node?

After reloading data in a Vuetify v-treeview component, I need to open the tree programmatically in a specific node (the last opened that I've saved in memory).

Is it possible? What's the right approach?

https://vuetifyjs.com/en/components/treeview/

Thank you for your help.


Update

I've solved my problem. I was wrong.

To refresh data, I was using my loadData() function that uses :loading attribute.

Using it, v-treeview refreshes the dom losing the current opening state. I have created a updateData() function that reloads only :items attribute. The nodes remain open in the same state.

It works right, so I didn't have to implement the opening node programmatically.

Anyway, I leave this question open, because It could be useful to share an approach, if it exists, to open a node programmatically in a v-treeview.

like image 320
Stefano Giraldi Avatar asked Mar 31 '20 16:03

Stefano Giraldi


2 Answers

You can use :open.sync, e.g.

<v-treeview :items="yourItemsTree" :open.sync="openIds" hoverable>

Now, openIds is an array with the open items (its item-key) (both ways using the sync modifier.

Alternatively, you can use

<v-treeview :items="yourItemsTree" @update:open="onOpen" hoverable>

and

methods: {
  onOpen(items) {
    this.openIds = items
  }
}
like image 77
Lambert Avatar answered Oct 17 '22 19:10

Lambert


This solution allows reloading the treeview (Vuetify 1.5) component after adding child nodes without changing open/closed state of nodes. I want the added children to appear immediately if the node is open.

Treeview Component

<v-treeview
  :items="yourItemList"
  :open.sync="openNodes"
  return-object
  @update:open="handleOpenOrClose"
  :key="triggerRerender"
>

Class (uses "vue-property-decorator")

  • You will also need some event listener to increment this.triggerRerender when you modify the data elsewhere.
export default class TreeViewClass extends Vue {
    @Prop({ type: Array, default: () => [] }) public yourItemList!: any[];

    public triggerRerender = 0; // modifying this value will rerender the component.
    public openNodes = [] as any[];
    private actuallyOpenNodes = [] as any[];
    private rerenderCount = 0; // after rerendering, increment this to track if closing a node is due to close action or rerender.

    public handleOpenOrClose(openNodesArray: any[]): void {
        if (openNodesArray.length === 0) {
            if (this.rerenderCount === this.triggerRerender) {
                this.handleClose()
            } else {
                // This is so it doesn't close nodes on rerender.
                this.rerenderCount = this.triggerRerender;
            }
        } else if (openNodesArray.length < this.actuallyOpenNodes.length) {
            this.handleClose()
        } else {
            this.handleOpen(openNodesArray)
        }
    }

    public handleOpen(openNodesArray: any[]): void {
        openNodes.forEach(node => {
            if (this.actuallyOpenNodes.indexOf(node) === -1) {
                this.actuallyOpenNodes.push(node);
            }
        });
    }

    public handleClose(): void {
        this.actuallyOpenNodes.forEach((node, index) => {
            if (this.openNodes.indexOf(node) === -1) {
                this.actuallyOpenNodes.splice(index, 1);
            }
        });
    }

    public updated(): void {
        if (this.openNodes.length !== this.actuallyOpenNodes.length) {
            this.actuallyOpenNodes.forEach(node => {
                if (this.openNodes.indexOf(node) === -1) {
                    this.openNodes.push(node);
                }
            });
        }
    }
}

I'm new to TypeScript, Vue, and Vuetify, so please tell me any improvements!

like image 1
MarkyMark Avatar answered Oct 17 '22 19:10

MarkyMark