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

######################## EDIT ########################
According to #Criss's answer, the method did not work, because the child item is different from the parent item.
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??

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...

Related

How can I make navbar items with vue-router-links to toggle the navbar?

I have a nav-bar that works fine. Except for the fact that it does not close when an item is clicked.
It does close when I click anywhere else in the window.
I work in laravel 8 and vue-3, have bootstrap-5 installed.
The navbar:
<template>
<div class="container-fluid navbar-custom-header">
<a class="close-navbar-toggler collapsed" data-bs-toggle="collapse" data-bs-target="#mySideBar" aria-controls="mySideBar" aria-expanded="false" aria-label="Toggle navigation">
</a>
<nav class='navbar-custom navbar-dark fixed-top' >
<div class="row " style="vertical-align:center">
<div class="col-2">
<button class="openbtn dropdown-toggle" data-bs-toggle="collapse" data-bs-target="#mySideBar">☰</button>
</div>
<div class="col-3">
Cards
</div>
<div class="col-3" v-if="!loggedIn">
<router-link to="/login"> Login </router-link>
</div>
<div class="col-3" v-if="loggedIn">
<router-link to="/logout"> Logout </router-link>
</div>
</div>
</nav>
</div>
<div class="navbar-custom-container" style="z-index:10">
<nav id="mySideBar" class="collapse navbar-custom navbar-collapse">
<div class="navbar-custom-items">
<ul class="nav navbar-nav">
<br>
<br>
<li class="nav-item"><router-link to="/memory" class="nav-link"> MemoryGame </router-link></li>
<br>
<li><router-link to="/cards" > Manage Cards </router-link></li>
<br>
<li><router-link to="/aanmelden"> Nieuwe Speler aanmelden </router-link></li>
<br>
<li><router-link to="/game"> Game spelen </router-link></li>
<br>
<li><router-link to="/game/admin"> GameAdmin </router-link></li>
</ul>
</div>
</nav>
</div>
</template>
<script>
export default {
computed: {
loggedIn() {
return this.$store.getters.loggedIn
}
}
}
</script>
and the accompanying css:
// Variables
#import 'variables';
// Bootstrap
#import '~bootstrap/scss/bootstrap';
.close-navbar-toggler{
position:absolute;
top:0;
left:0;
height:100%;
width:100%;
z-index:1;
cursor:pointer;
}
.close-navbar-toggler.collapsed{
z-index:-1;
}
.navbar-custom-header {
background-color: rgb(5, 4, 71);
color:rgb(245, 209, 8);
margin:auto;
}
.navbar-custom-container {
display:flex;
justify-content:flex-start;
position:absolute;
//padding:0px 12px;
}
.navbar-header {
background-color: rgb(5, 4, 71);
}
.navbar-custom {
background-color: rgb(17, 15, 172);
color:yellow;
padding:12px -12px;
}
.navbar-toggler-icon {
vertical-align:middle;
text-align:left;
}
.navbar-custom-items > a:link {
color:black;
}
.navbar-custom-items > a:active {
color:rgb(73, 7, 7);
}
.navbar-custom-items > a:hover {
color:rgb(138, 59, 241);
}
I realize that I do not fully understand how Bootstrap catches the collapse-command.
Can anyone explain?
In vue3you would have a component that represents the nav menu as a template. Then, the component would look like this (using bootstrap-vue-3 components such as b-collapse, but you can use div tags as well):
<template>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container-fluid">
<button class="navbar-toggler" type="button"
:class="visible ? null : 'collapsed'"
:aria-expanded="visible ? 'true' : 'false'"
#click="visible = !visible"
aria-controls="navbarSupportedContent"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<b-collapse class="collapse navbar-collapse" id="navbarSupportedContent" v-model="visible">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<router-link class="nav-link" :to="{name: 'home'}" #click="visible = !visible">
home
</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="{name: 'page1'}" #click="visible = !visible">
page1
</router-link>
</li>
</ul>
</b-collapse>
</div>
</nav>
</template>
<script setup>
import {ref} from 'vue'
const visible = ref(false)
</script>
In the template example you can see that clicking on the navbar-toggler or on the links, the visible attribute of the components gets toggled. And the navbarSupportedContentelement is visible, depending on the value of visible (v-model="visible"). If you do not use bootstrap-vue-3, then you would use v-show="visible" inside your div to toggle it.

Bulma Navbar-burger not collapsing the navbar item data

Hi i am a newbie in vuejs, Buefy. I wanted to add navigation bar. Navigation Bar works in the desktop however when view it in mobile responsive when the burger click doesn't show anything. the navbar item not collapsible. can anyone help me? Thank you.
Here is my code.
<template>
<div id="app">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="https://bulma.io">
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
</a>
<a
role="button"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
data-target="navbarBasicExample"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item">Home</a>
<a class="navbar-item">Documentation</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">More</a>
<div class="navbar-dropdown">
<a class="navbar-item">About</a>
<a class="navbar-item">Jobs</a>
<a class="navbar-item">Contact</a>
<hr class="navbar-divider">
<a class="navbar-item">Report an issue</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">
<strong>Sign up</strong>
</a>
<a class="button is-light">Log in</a>
</div>
</div>
</div>
</div>
</nav>
</div>
</template>
<script>
import $ from "jquery";
export default {
name: "App",
mounted() {
$(document).ready(function() {
document.addEventListener("DOMContentLoaded", () => {
const $navbarBurgers = Array.prototype.slice.call(
document.querySelectorAll(".navbar-burger"),
0
);
if ($navbarBurgers.length > 0) {
$navbarBurgers.forEach(el => {
el.addEventListener("click", () => {
const target = el.dataset.target;
const $target = document.getElementById(target);
el.classList.toggle("is-active");
$target.classList.toggle("is-active");
});
});
}
});
});
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Can access here:
https://codesandbox.io/s/stupefied-khayyam-mnb7x
Well, the way you trying to do it is a bit different from the official documentation. In order to create a navbar you should wrap your whole navbar within a <b-navbar> like this:
<b-navbar>
<template slot="brand">
<a class="navbar-item" href="https://bulma.io">
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
</a>
</template>
<template slot="start">
<div class="navbar-start">
<a class="navbar-item">Home</a>
<a class="navbar-item">Documentation</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">More</a>
<div class="navbar-dropdown">
<a class="navbar-item">About</a>
<a class="navbar-item">Jobs</a>
<a class="navbar-item">Contact</a>
<hr class="navbar-divider">
<a class="navbar-item">Report an issue</a>
</div>
</div>
</div>
</template>
<template slot="end">
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">
<strong>Sign up</strong>
</a>
<a class="button is-light">Log in</a>
</div>
</div>
</div>
</template>
</b-navbar>
Then fill each slot with appropriate content of yours.
Working DEMO:

Bootstrap Changing Width of Downtown Menu

I am trying to change the width of drowpdown menu in Bootstrap. Please guide where should i insert the custom CSS to change/reduce the width of drop-down menu.
<body>
<div class="container-fluid">
<div class="dropdown">
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown">MENU <span class="caret"></span></button>
<ul class="dropdown-menu">
<li class="dropdown-header">HEADER-1</li>
<li>ITEM-1</li>
<li>ITEM-1</li>
<li>ITEM-1</li>
<li class="divider"></li>
<li class="dropdown-header">HEADER-2</li>
<li>ITEM-1</li>
<li>ITEM-1</li>
</ul>
</div>
</div>
</div>
</body>
</html>
Bootstrap's dropdown has some min-width to it. Change the min-width of drop-down menu so reduce its width.
.dropdown-menu {
min-width: 125px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
.dropdown-menu {
min-width: 125px;
}
</style>
<div class="container-fluid">
<div class="dropdown">
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown">MENU <span class="caret"></span></button>
<ul class="dropdown-menu">
<li class="dropdown-header">HEADER-1</li>
<li>ITEM-1</li>
<li>ITEM-1</li>
<li>ITEM-1</li>
<li class="divider"></li>
<li class="dropdown-header">HEADER-2</li>
<li>ITEM-1</li>
<li>ITEM-1</li>
</ul>
</div>
</div>
add custom class in your tag <li>, example
.dropdown-custom > .dropdown-menu {
min-width:220px;
padding:15px;
color:red;
}
try my fiddle

Casperjs scrape DOM element looping through list tag

<div id="joblist-panel">
<ul class="list-job-box">
<li id="row" class="row bt-gray-border job white-bg list-arrow">
<div class="circle-outline">
<div class="circle-job circle-color" style="background-color: transparent; border: 1px solid rgb(183, 183, 183);">
<div class="circle-inner">
<div class="score-text"><i class="fa fa-file-text-o"></i></div>
</div>
</div>
</div>
title
<div class="row list-job">
<ul>
<li>
<div><i class="icon-glyph-111"></i></div>
3-6 Years
</li>
<li>
<div><i class=" icon-glyph-83"></i></div>
1 Opening
</li>
<li class="location-text"><i class=" icon-glyph-14"></i>
Bengaluru
</li>
</ul>
</div>
</li>
</ul>
Have content like this and I want to loop all 'li' tag and get href of 'a' tag and innertext of list-job class .. How can we achieve this by casperjs, phantomjs

Bootstrap 3 - navbar dropdown menu still visible after closing the dropdown - on viewport < 768px

I've been trying to fix the issue with the navbar dropdown menu when using viewport smaller than 768px (mobile/touchscreen).
When tested on touchscreen, one click is supposed to open the dropdown (this works fine), the second click is supposed to close it (closing of the dropdown works, but on touchscreen it still shows the dropdown menu on the side like it is ul.dropdown-menu:hover ).
I am trying to have it hidden after the dropdown toggle is clicked to close, and the cursor is still hovers on the toggle (touchscreen).
Here is the code:
ul.dropdown-menu {
background-color: #4474a8;
}
ul.dropdown-menu li a {
background-color: #4474a8
}
ul.dropdown-menu li a:hover {
background-color: #4474a8;
color: #111111!important;
}
.dropdown:hover .dropdown-menu {
display: block;
}
a.dropdown-toggle:focus {
color: #2f1b09;
}
.dropdown-link {
text-align: center;
background-color: #4474a8;
color: #FFFFFF !important;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<img src="#" class="img-responsive center-block" id="logo-top">
</div>
<div class="col-md-1"></div>
</div>
</div>
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="fa fa-anchor"></span>
</button>
</div>
<div class="navbar-collapse collapse" id="myNavbar">
<ul class="nav navbar-nav">
<li class="active" id="active-nav">Home</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#">MENU 1<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><i class="fa fa-ship" aria-hidden="true"></i> SUBMENU 1</li>
<li> SUBMENU 2</li>
<li> SUBMENU 3<b>$</b></li>
<li> SUBMENU 4</li>
</ul>
</li>
<li>MENU 2</li>
<li>MENU 3</li>
<li>MENU 4</li>
<li class="dropdown">
<i class="fa fa-camera" aria-hidden="true"></i> MENU 5<span class="caret"></span>
<ul class="dropdown-menu">
<li>Photos</li>
<li>Video</li>
<li><i class="fa fa-youtube" aria-hidden="true"></i>YouTube</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!-- # #banner-->
<div class="container-fluid" id="banner">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6" id="bannerCol1L">
</div>
<!-- / #bannerCol1L -->
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6" id="bannerCol2R">
<a class="orange pillboxLarge" id="getstarted">BUTTON</a>
</div>
</div>
<!-- / .row -->
</div>
<!-- / .container-fluid #banner -->
</body>
In your CSS, delete the following:
.dropdown:hover .dropdown-menu {
display: block;
}