Samanta Silva
Samanta Silva

Reputation: 267

how to make a conditional multilevel menu with vue.js?

######################## EDIT ########################

According to @Criss's answer, the method did not work, because the child item is different from the parent item.

enter image description here

A simple item without child should look like this:

<li class="sidebar-item">
    <a class="sidebar-link" href="/test.html">
        <span class="align-middle">Test</span>
    </a>
</li>

When an item has a child it should have the option data-toggle="collapse"

<li class="sidebar-item">
    <a class="sidebar-link" href="/test.html" data-toggle="collapse" >
        <span class="align-middle">Test</span>
    </a>
    <ul class="sidebar-dropdown list-unstyled collapse">
        ##<li>#### CHILD ITENS ####</li>##
    </ul>
</li>

And the subitems when they do not have more childs should look like this:

<li class="sidebar-item">
    <a class="sidebar-link" href="/test3.html">Test3</a>
</li>

my new attempt based on @Criss's response, went like this:

Vue.component('menu-item', {
    props: ['cmitens'],
    template: '#menu-item'
});
new Vue({el: '#vuesadminmenu', 
            data: {
             menuitens: {"test0":{"titulo":"Test0","open":"false","selected":"false","link":"http:\/\/www.link.com\/test0","child":""},"test1":{"titulo":"Test1","open":"true","selected":"false","link":"http:\/\/www.link.com\/test1","child":{"test2":{"titulo":"Test2","open":"true","selected":"false","link":"http:\/\/www.link.com\/test2","child":{"test3":{"titulo":"Test3","open":"true","selected":"true","link":"http:\/\/www.link.com\/test3","child":""}}},"test4":{"titulo":"Test4","open":"false","selected":"false","link":"http:\/\/www.link.com\/test4","child":""}}},"test5":{"titulo":"Test5","open":"false","selected":"false","link":"http:\/\/www.link.com\/test5","child":{"test6":{"titulo":"Test6","open":"false","selected":"false","link":"http:\/\/www.link.com\/test6","child":""}}},"test7":{"titulo":"Test7","open":"false","selected":"false","link":"http:\/\/www.link.com\/test7","child":""}}
            }
       });
ol ol, ol ul, ul ol, ul ul { margin-left: 20px; }
<script src="https://appstack.bootlab.io/js/app.js"></script>
    <link href="https://appstack.bootlab.io/css/app.css" rel="stylesheet"/>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <div class="wrapper">
    <nav class="sidebar">
        <div class="sidebar-content">
            <ul id="vuesadminmenu" class="sidebar-nav">
            <template id="menu-item">
                <li class="sidebar-item" v-for="(mitem, mkey) in menuitens" v-bind:class="[(mitem.open == 'true') ? 'active' : '']">
                    <a class="sidebar-link" v-bind:href="mitem.child !== '' ? '#'+mkey : mitem.link" :data-toggle="[(mitem.child !== '') ? 'collapse' : '']" v-bind:class="[(mitem.open == 'true') ? '' : 'collapsed']">
                        <span class="align-middle">{{mitem.titulo}} {{mitem.open}}</span>
                    </a>
                    <ul class="sidebar-dropdown list-unstyled collapse" v-if="mitem.child !== ''" v-bind:class="[(mitem.open == 'true') ? 'show' : '']">
                        <menu-item :cmitens="mitem.child"></menu-item>
                    </ul>
                </li>
            </template> 
            </ul>
        </div>
    </nav>
    </div>

But the subitems are still disappearing.


######################## QUESTION ########################

I try to make a multilevel menu

In vue.js I only get the first level. I have no idea how to do the loop for all levels, and treat the conditions of when it is a fixed item or item with child.

I'm trying to do so:

--> moved to the above edition <--

I have this multidimensional json

{"test0":{"titulo":"Test0","open":"false","selected":"false","link":"\/test0.html","child":""},
 "test1":{"titulo":"Test1","open":"false","selected":"false","link":"\/test1.html"","child":{
    "test2":{"titulo":"Test2","open":"false","selected":"false","link":"\/test2.html"","child":{
        "test3":{"titulo":"Test3","open":"false","selected":"false","link":"\/test3.html"","child":""}}},
    "test4":{"titulo":"Test4","open":"false","selected":"false","link":"\/test4.html"","child":""}}},
 "test5":{"titulo":"Test5","open":"false","selected":"false","link":"\/test5.html"","child":{
    "test6":{"titulo":"Test6","open":"false","selected":"false","link":"\/test6.html"","child":""}}},
 "test7":{"titulo":"Test7","open":"false","selected":"false","link":"\/test7.html"","child":""}}

I'd like to do something like this:

ol ol, ol ul, ul ol, ul ul {
    margin-left: 20px;
}
<script src="https://appstack.bootlab.io/js/app.js"></script>
<link href="https://appstack.bootlab.io/css/app.css" rel="stylesheet"/>
<div class="wrapper">
<nav class="sidebar">
    <div class="sidebar-content">
        <ul class="sidebar-nav">
            <li class="sidebar-item">
                <a class="sidebar-link" href="/test0.html">
                    <span class="align-middle">Test0</span>
                </a>
            </li>
            <li class="sidebar-item active">
                <a href="/test1.html" data-toggle="collapse" class="sidebar-link">
                    <i class="align-middle" data-feather="layout"></i> <span class="align-middle">Test1</span>
                </a>
                <ul class="sidebar-dropdown list-unstyled collapse show">
                    <li class="sidebar-item active">
                        <a href="/test2.html" data-toggle="collapse" class="sidebar-link">
                            <i class="align-middle" data-feather="layout"></i> <span class="align-middle">Test2</span>
                        </a>
                        <ul class="sidebar-dropdown list-unstyled collapse show">
                            <li class="sidebar-item">
                                <a class="sidebar-link" href="/test3.html">Test3</a>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li class="sidebar-item">
                <a class="sidebar-link" href="/test4.html">
                    <span class="align-middle">Test4</span>
                </a>
            </li>
        </ul>
    </div>
</nav>
</div>

Can someone help me how can I do the other levels??

Upvotes: 0

Views: 3504

Answers (1)

Criss
Criss

Reputation: 983

Vue.component('menu-item', {
    props: ['menuitens'],
    template: '<ul class="sidebar-nav">'+
                '<li class="sidebar-item" v-for="(mitem, mkey) in menuitens" v-bind:class="[(mitem.open == \'true\') ? \'active\' : \'\']">'+
                    '<a class="sidebar-link" v-bind:href="mitem.link">'+
                        '<span class="align-middle">{{mitem.titulo}} {{mitem.open}}</span>'+
                    '</a>'+
                    '<menu-item v-if="mitem.child !== \'\'" :menuitens="mitem.child"></menu-item>'+
                '</li>'+
            '</ul>'
});
new Vue({el: '#vuesadminmenu', 
            data: {
             menuitens: {"test0":{"titulo":"Test0","open":"false","selected":"false","link":"http:\/\/www.link.com\/test0","child":""},"test1":{"titulo":"Test1","open":"true","selected":"false","link":"http:\/\/www.link.com\/test1","child":{"test2":{"titulo":"Test2","open":"true","selected":"false","link":"http:\/\/www.link.com\/test2","child":{"test3":{"titulo":"Test3","open":"true","selected":"true","link":"http:\/\/www.link.com\/test3","child":""}}},"test4":{"titulo":"Test4","open":"false","selected":"false","link":"http:\/\/www.link.com\/test4","child":""}}},"test5":{"titulo":"Test5","open":"false","selected":"false","link":"http:\/\/www.link.com\/test5","child":{"test6":{"titulo":"Test6","open":"false","selected":"false","link":"http:\/\/www.link.com\/test6","child":""}}},"test7":{"titulo":"Test7","open":"false","selected":"false","link":"http:\/\/www.link.com\/test7","child":""}}
            }
       });
ol ol, ol ul, ul ol, ul ul { margin-left: 20px; }
ul {
    padding-bottom: 0 !important;
}
<script src="https://appstack.bootlab.io/js/app.js"></script>
    <link href="https://appstack.bootlab.io/css/app.css" rel="stylesheet"/>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
    <div class="wrapper">
    <nav class="sidebar">
        <div class="sidebar-content" id="vuesadminmenu">
            <menu-item :menuitens="menuitens"></menu-item>
        </div>
    </nav>
    </div>

This works by using recursion - you define a component that holds it's own link and all child links and v-if="menuitem.child" exists, then the component creates a sub-copy of itself.

The beautiful thing about this approach is that you no longer care how deeply nested the child items are.

You should tweak the styling tho...

Upvotes: 2

Related Questions