1

How can I use the result of a v-if to render two different components in Vue? If it matters, I'm also trying to do this while rendering a TreeView using v-for. Here's what I tried so far.

TreeView.vue:

<template> <span> <ul v-show="isOpen" v-if="isFolder"> <p v-for="(child, index) in item.children" v-bind:item="child" v-bind:key="index" <span v-if="!child.isFolder"> <slot v-bind:individualBookmark="child"></slot> </span> <span v-else> <div v-bind:class="{bold: isFolder}" v-on:click="toggle" v-on:dblclick="makeFolder" v-on:contextmenu="rightClick"> {{ child.name }} <span v-if="isFolder">[{{ isOpen ? '-' : '+' }}]</span> </div> </span> </p> </ul> </span> </template> <script> export default { name: "TreeView", props: { item: Object }, components: { }, data: function() { return { isOpen: false } }, computed: { isFolder: function() { return this.item.children.length > 0; //return this.item.children && this.item.children.length; } }, methods: { toggle: function() { if (this.isFolder) { this.isOpen = !this.isOpen; } }, makeFolder: function() { if (!this.isFolder) { this.$emit("make-folder", this.item); this.isOpen = true; } }, rightClick: function() { alert("Right click action") } } } </script> 

App.vue (the Bookmark tag is a custom component I built that does not have the isFolder computed property):

<template> <div id="app"> <TreeView v-slot:default="slotProps" v-bind:item="treeData" v-on:make-folder="makeFolder" v-on:add-item="addItem"> <Bookmark v-bind="slotProps.individualBookmark"></Bookmark> </TreeView> </div> </template> <script> import Bookmark from './components/Bookmark.vue' import TreeView from './components/TreeView.vue' import Vue from 'vue' export default { name: 'App', components: { Bookmark, TreeView }, data: function() { return { treeData : { name: "My Tree", children: [ { name: "hello" }, { name: "wat" }, { name: "child folder 1", children: [ { name: "child folder", children: [{ name: "hello" }, { name: "wat" }] }, { name: "hello" }, { name: "wat" }, { name: "child folder", children: [{ name: "hello" }, { name: "wat" }] } ] } ] } } }, methods: { makeFolder: function(item) { Vue.set(item, "children", []); this.addItem(item); }, addItem: function(item) { item.children.push({ name: "new stuff" }); } } } </script> 

When I run this, for some reason, the v-if="!child.isFolder" in TreeView.vue always evaluates to true so it renders the Bookmark component. Even in the case when the v-if should be evaluating to false like when given the "child folder 1" child object of treeData, it still evaluates to true. I have a feeling the problem is to do with how I'm using <slot></slot> in TreeView.vue but I'm not sure. Why is the v-if always evaluating to true and never false?

The problem may also have to do with how I wrote the isFolder property.

1
  • "you map the item prop inside the Treeview component and add that property" could you explain how to do this? I don't fully understand how to implement it in code Commented Jul 26, 2020 at 16:33

1 Answer 1

2

Add a computed property called computedChildren inside the Treeview component which maps the item prop by adding isFolder property :

 computed: { isFolder: function() { return this.item.children.length > 0; //return this.item.children && this.item.children.length; }, computedChildren(){ return this.item.children.map(child=>{ child.isFolder=child.children?child.children.length>0:false //this add the property isFolder return child }) } }, 

Then loop through it as follows :

<p v-for="(child, index) in computedChildren" ... 

For replacing the slot you could use template element :

 <TreeView v-bind:item="treeData" v-on:make-folder="makeFolder" v-on:add-item="addItem"> <template v-slot:default="slotProps"> <Bookmark v-bind="slotProps.individualBookmark"></Bookmark> </template> </TreeView> 
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you, this finally renders the child folder as a folder. Do you know how I could render the bookmarks within the child folder though? The child folder doesn't show the bookmarks that it contains.
you're welcome, please check my edited answer where i used template element to render the slot content
That didn't seem to work, here is a picture of what I am talking about. The child folder looks like it is expanded but it's not displaying the bookmarks that it contains. Also, for some reason when I click the [-] button on child folder, it retracts the whole tree, when it's only supposed to retract the bookmarks within the child folder.
could you provide some codepen codesandbox sample in order to debug it
Here is all of my code. Thank you again for your assistance.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.