37
loading...
This website collects cookies to deliver better user experience
the practice of describing numbers, expressions, etc. in terms of the numbers, expressions, etc. that come before them in a series (within Mathematics and Computing contexts).
the practice of putting a structure such as a phrase inside a structure of the same kind (within Language context).
Recursion is the process of defining a problem (or the solution to a problem) in terms of itself.
Imagine that you are building an application similar to a social network where people can comment on posts. Now, imagine that people might be able to comment on comments.
Now, let's say you might need to display the whole structure of a file system containing folders within folders as something we call tree.
we want to build an extensible component in terms of layout because we might need to display different trees;
we must have a breaking point within the component to avoid loops. This will work exactly the same way it does within recursive functions to prevent it from calling itself endlessly;
b-alert
component from Bootstrap Vue just to avoid dealing too much with styling.TreeNode.vue
file within components
folder and implement it like the following:<template>
<b-alert show class="d-flex justify-content-between mb-1">
{{ node.label }}
<span class="fas fa-angle-right" />
</b-alert>
</template>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
}
}
}
Home.vue
page.TreeNode
represents only one node, we need to use a v-for
directive to render all of our nodes.<template>
<div>
<TreeNode v-for="node in nodes" :key="node.id" :node="node" />
</div>
</template>
import TreeNode from '@/components/TreeNode/TreeNode'
export default {
name: 'HomeView',
components: {
TreeNode
},
computed: {
nodes() {
return [
{
id: 1,
label: 'Foods',
children: [
{
id: 2,
label: 'Fruits',
children: [
{
id: 3,
label: 'Banana'
},
{
id: 4,
label: 'Apple'
},
{
id: 5,
label: 'Strawberry'
}
]
},
{
id: 6,
label: 'Vegetables',
children: [
{
id: 7,
label: 'Carrot'
},
{
id: 8,
label: 'Lettuce'
},
{
id: 9,
label: 'Potato'
}
]
}
]
},
{
id: 10,
label: 'Drinks',
children: [
{
id: 11,
label: 'Beers',
children: [
{
id: 12,
label: 'Budweiser'
},
{
id: 13,
label: 'Heineken'
}
]
},
{
id: 14,
label: 'Wines'
},
{
id: 15,
label: 'Whiskey'
}
]
}
]
}
}
}
TreeNode
component must be able to reference itself in order to display the children nodes of each node. As a tree structure may contain several levels, our component must support that.v-for
loop of itself to display the nested nodes.<div>
<b-alert show class="d-flex justify-content-between mb-1">
{{ node.label }}
<span class="fas fa-angle-right" />
</b-alert>
<div v-if="hasChildren">
<TreeNode
v-for="child in node.children"
:key="child.id"
:node="child"
/>
</div>
</div>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
}
},
computed: {
hasChildren() {
const { children } = this.node
return children && children.length > 0
}
}
}
spacing
prop to the TreeNode
component and use it to set a margin-left
style into the layout. We are also going to pass this prop to the children nodes incrementing it by 10 (which result in 10px
when rendering).<template>
<div :style="nodeMargin">
<b-alert show class="d-flex justify-content-between mb-1">
{{ node.label }}
<span class="fas fa-angle-right" />
</b-alert>
<div v-if="hasChildren">
<TreeNode
v-for="child in node.children"
:key="child.id"
:node="child"
:spacing="spacing + 10"
/>
</div>
</div>
</template>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
},
spacing: {
type: Number,
default: 0
}
},
computed: {
nodeMargin() {
return {
'margin-left': `${this.spacing}px`
}
},
hasChildren() {
const { children } = this.node
return children && children.length > 0
}
}
}
click
event of the icon.<template>
<div :style="nodeMargin">
<b-alert show class="d-flex justify-content-between mb-1">
{{ node.label }}
<span
v-if="hasChildren"
:class="toggleChildrenIcon"
@click="toggleChildren"
@keypress="toggleChildren"
/>
</b-alert>
<div v-if="hasChildren" v-show="showChildren">
<TreeNode
v-for="child in node.children"
:key="child.id"
:node="child"
:spacing="spacing + 10"
/>
</div>
</div>
</template>
export default {
name: 'TreeNode',
props: {
node: {
type: Object,
required: true
},
spacing: {
type: Number,
default: 0
}
},
data() {
return {
showChildren: false
}
},
computed: {
nodeMargin() {
return {
'margin-left': `${this.spacing}px`
}
},
hasChildren() {
const { children } = this.node
return children && children.length > 0
},
toggleChildrenIcon() {
return this.showChildren ? 'fas fa-angle-down' : 'fas fa-angle-right'
}
},
methods: {
toggleChildren() {
this.showChildren = !this.showChildren
}
}
}
children
approach but this is not the only way of defining a tree in terms of data.[
{
id: 1,
label: 'Root Node',
parentId: null,
order: 1
},
{
id: 2,
label: 'Child Node',
parentId: 1,
order: 1
},
{
id: 3,
label: 'Grandchild Node',
parentId: 2,
order: 2
},
{
id: 4,
label: 'Root Node 2',
parentId: null,
order: 2
}
]