Vue.js and Symfony — nested menu

Dariusz Włodarczyk
3 min readMay 16, 2021

Based on hierarchical structure of categories (parent / child relations)

There are tones o ways to build nested menu structure, where one are simply hardcoded arrays and other rely on… recursion — and that’s the solution for current “code case”.

“Can You actually use recursion in Vue.js template?”

The thing is… that You actually can and it’s pretty simple to do it.

I’m simply converting this database structure:

Database structure

Into parent / child relational array:

Parent child hierarchy array obtained from backend

And then output the menu

Rendered menu in Vue.js

In this solution, not only the deepest child is a link but also the parents themselves, which mean that in the structure presented above each element is a router link:

  • clicking on Finances will load category data,
  • clicking on Goals will load category data,
  • clicking on arrow will show / hide nesting,

Keep in mind that in this case I’m using:

  • bootstrap: 5.0.0-beta2,
  • vue: 3.0.5,
  • php8.0,
  • Symfony 5.x

Backend

What we need here is a logic which will convert the database structure into the presented array structure above which will then be handled on the frontend.

Database structure into array of depths

First of all I simply fetch all data from database and output an array where categoryId is a key and value is depth level.

Array of depths into parent / child array

As next we use the previously fetched id / depth to build relation array. CategoryId is being used to fetch category data, which is then passed to the recursive call of buildParentChildDtoForHierarchy (as each category can contain children and these children can consist of children which children… “You get the point”).

Now the last polishing of data structure and this can be sent to the frontend.

Frontend

Frontend handling get’s way much easier in here, as the only things we need to do is:

  • fetch data from backend,
  • converting json response into parentChildDtoArray,
  • pass the array to the component,

Keep in mind:

So first thing first — fetching the data from backend with Axios:

We will also need a component nested-menu-node.vue .

And that’s it, now call the component in Your template, like this:

<template #submenu>
<nested-menu-node :nodes="parentChildDtoArray"
:node-identifier="notesCategoriesMenuNodeId"
:to-path-name="routeNameModuleNotesCategory"
:to-id-param-name="routeNameModuleNotesCategoryIdParam"
/>
</template>

“But… where is the recursion actually happening in Vue template?”

In nested-menu-node.vue component the component itself gets imported:

<script type="ts">
import NestedMenuNode from "./nested-menu-node";
</script>

Which is then being used like that:

<li v-for="node in nodes"
class="sidebar-item"
>
...
<nested-menu-node :nodes="node.children"
:node-identifier="node.id"
:to-path-name="toPathName"
:to-id-param-name="toIdParamName"
></nested-menu-node>
</li>

ParentChildDto used in the process

Frontend

Backend

--

--

Dariusz Włodarczyk

Hobby frontend / backend developer — author of Personal Management System. https://git.io/JePh1. You can find me also here: https://ko-fi.com/volmarg.