Vue.js : How to make dynamic menu? - javascript

Could someone help me with creating menus dynamically from a database? Lets say all the data from the database is already supplied by me, but I want to show a dynamic menu if a user is logged in or not.
I created some Vue components
App.vue
<template>
<div id="app">
<navbar></navbar>
<div class="page-container">
<leftmenu></leftmenu>
<container></container>
</div>
</div>
</template>
<script>
import Menu from './components/Menu.vue'
import LeftMenu from './components/Leftmenu.vue'
import Container from './components/Container.vue'
export default {
components: {
'navbar': Menu,
'leftmenu': LeftMenu,
'container': Container,
}
}
</script>
The LeftMenu component is in charge of making the menu that will make use of the database data:
Leftmenu.vue
<template>
<div class="page-sidebar-wrapper">
<div class="page-sidebar navbar-collapse collapse">
<ul class="page-sidebar-menu page-header-fixed " data-keep-expanded="false" data-auto-scroll="true"
data-slide-speed="200" style="padding-top: 20px">
<li class="sidebar-toggler-wrapper hide">
<div class="sidebar-toggler">
<span></span>
</div>
</li>
<li class="nav-item start active open">
<a href="javascript:;" class="nav-link nav-toggle">
<i class="icon-home"></i>
<span class="title">Dashboard</span>
<span class="selected"></span>
<span class="arrow open"></span>
</a>
<ul class="sub-menu">
<router-link
to="/home"
tag="li">
<a class="nav-link">
<i class="icon-layers"></i>
<span class="title">Home</span>
<span class="badge badge-danger">5</span>
</a>
</router-link>
<router-link
to="/grafik"
tag="li">
<a class="nav-link">
<i class="icon-layers"></i>
<span class="title">Grafik</span>
<span class="badge badge-danger">5</span>
</a>
</router-link>
<router-link
to="/form"
tag="li">
<a class="nav-link">
<i class="icon-layers"></i>
<span class="title">Form</span>
<span class="badge badge-danger">5</span>
</a>
</router-link>
<router-link
to="/uploadfile"
tag="li">
<a class="nav-link">
<i class="icon-layers"></i>
<span class="title">Upload File</span>
<span class="badge badge-danger">5</span>
</a>
</router-link>
<router-link
to="/login"
tag="li">
<a class="nav-link">
<i class="icon-layers"></i>
<span class="title">Login</span>
<span class="badge badge-danger">5</span>
</a>
</router-link>
</ul>
</li>
<li class="nav-item ">
<a href="javascript:;" class="nav-link nav-toggle">
<i class="icon-settings"></i>
<span class="title">System</span>
<span class="arrow"></span>
</a>
<ul class="sub-menu">
<li class="nav-item ">
<a href="ui_metronic_grid.html" class="nav-link ">
<span class="title">Login</span>
</a>
</li>
<li class="nav-item ">
<a href="ui_metronic_grid.html" class="nav-link ">
<span class="title">Ganti Password</span>
</a>
</li>
<li class="nav-item ">
<a href="ui_metronic_grid.html" class="nav-link ">
<span class="title">Ganti Profil</span>
</a>
</li>
<li class="nav-item ">
<a href="ui_metronic_grid.html" class="nav-link ">
<span class="title">Logout</span>
</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</template>
<script>
import _ from 'lodash'
export default {
created() {
if(_.isEmpty(this.$auth.getAuthenticatedUser())) {
alert('empty')
} else {
alert('user authenticated')
}
}
}
</script>
this.$auth.getAuthenticatedUser() is already done but will return an empty object if my localStorage is empty. It will but filled if I am logged in.
I am using this bit of code for it:
this.$http.get('api/getmenu')
.then(response => {
this.data = response.body
})
In which component should I query the database to obtain the data to render a menu for the logged in user?
If I place a function to query the database inside my App.vue component, then the application will show an error.
What should I put in the Leftmenu component ?

Related

How To Keep Sidebar Open When Click Sub Menu

I use bootstrap 5, i want when a sidebar item is clicked it will be active and when a sub sidebar item is clicked it will also be active
And when reloading the item that was selected earlier it is still stored
Here my code
<div class="row row-offcanvas row-offcanvas-left vh-100" style="width: 1700px">
<div class="col-md-3 col-lg-2 sidebar-offcanvas h-100 overflow-auto bg-light pl-0" id="sidebar" role="navigation">
<ul class="nav flex-column sticky-top pl-2 mt-0">
<li>
<a href="/home">
<i class="nc-icon nc-bank"></i>
<p>Dashboard</p>
</a>
</li>
{{-- Menu Manajemen Karyawan --}}
<li>
<a class="nav-link" href="#submenu1" data-toggle="collapse" data-target="#submenu1">
<i class="nc-icon nc-tile-56"></i>
Manajemen Karyawan
</a>
<ul class="sub-menu list-unstyled flex-column collapse pl-2" id="submenu1" aria-expanded="false">
<li style="margin-top: -15px">
<a href="{{ route('karyawan.index') }}">
<i class="nc-icon nc-badge"></i>
<p>Karyawan </p>
<p></p>
</a>
</li>
<li style="margin-top: -15px">
<a href="#">
<i class="nc-icon nc-ruler-pencil"></i>
<p>Pengkinian Data </p>
<p></p>
</a>
</li>
<li class="dropdown" style="margin-top: -15px">
<a href="" data-toggle="dropdown" aria-expanded="false">
<i class="nc-icon nc-chart-bar-32"></i>
<p class="dropdown-toggle" id="navbarDropdownMenuLink">Pergerakan Karir </p>
<p></p>
</a>
<div class="dropdown-menu dropdown-primary dropdown-menu-right">
<a class="dropdown-item" href="{{ route('mutasi.index') }}">Mutasi</a>
<a class="dropdown-item" href="{{ route('demosi.index') }}">Demosi</a>
<a class="dropdown-item" href="{{ route('promosi.index') }}">Promosi</a>
<a class="dropdown-item" href="{{ route('karyawan.penonaktifan') }}">Penonaktifan</a>
</div>
</li>
</ul>
</li>
</ul>
</div>
</div>
can anyone help ?

JS on click collapse bootstrap list

I am using bootstrap 5 I have taken a sample of JavaScript that allows a pop-out sidebar open on the left with the option to close the sidebar once opened.
Inside the sidebar I have a navigation menu with menu-links (in list format)
I want it so when the user has opened the sidebar, if they decide to click to close the sidebar it will also de-collapse/close the menu lists (#submenu1, #submenu2 and #submenu3) if any and all that are open/collapsed.
I am unsure of how to achieve this in JavaScript... surely its something simple?
The javascript also makes some adjustments to the body... this does not need to be changed/effected so ignore the parts of the JS regarding body classes etc...
JS:
document.addEventListener("DOMContentLoaded", function(event) {
const showNavbar = (toggleId, navId, bodyId, headerId) =>{
const toggle = document.getElementById(toggleId),
nav = document.getElementById(navId),
bodypd = document.getElementById(bodyId),
headerpd = document.getElementById(headerId)
// Validate that all variables exist
if(toggle && nav && bodypd && headerpd){
toggle.addEventListener('click', ()=>{
// show navbar
nav.classList.toggle('show')
// change icon
toggle.classList.toggle('bx-x')
// add padding to body
bodypd.classList.toggle('body-pd')
// add padding to header
headerpd.classList.toggle('body-pd')
})
}
}
showNavbar('header-toggle','nav-bar','body-pd','header')
/*===== LINK ACTIVE =====*/
const linkColor = document.querySelectorAll('.nav_link')
function colorLink(){
if(linkColor){
linkColor.forEach(l=> l.classList.remove('active'))
this.classList.add('active')
}
}
linkColor.forEach(l=> l.addEventListener('click', colorLink))
// Your code to run since DOM is loaded and ready
});
HTML:
<div class="header_toggle"> <i class="bx bx-menu" id="header-toggle"></i> </div>
<div class="l-navbar show" id="nav-bar">
<nav class="nav">
<div> <a href"="" shopuserproducts"="" class="nav_logo"> <img style="width: 30px;" src="/Images/favicon.svg"> <span class="nav_logo-name">ABC Test</span> </a>
<li>
<a href="#submenu1" data-bs-toggle="collapse" class="nav_link collapsed" aria-expanded="false"> <i class="bx bxs-car-mechanic"></i> <span class="nav_name">
Commercial Parts</span></a>
<ul class="nav-sub-cat flex-column ms-1 custom-scrollbar-js collapse" id="submenu1" data-bs-parent="#menu" style="">
<li class="w-100">
<span class="d-none d-sm-inline">Suspension</span>
</li>
<li>
<span class="d-none d-sm-inline">Braking</span>
</li>
<li>
<span class="d-none d-sm-inline">Filtration</span>
</li>
<li>
<span class="d-none d-sm-inline">Engine</span>
</li>
<li>
<span class="d-none d-sm-inline">Exhaust</span>
</li>
</ul>
</li>
<li>
<i class="bx bx-spray-can nav_icon"></i><span class="nav_name">Refinish</span>
<ul class="nav-sub-cat flex-column ms-1 custom-scrollbar-js collapse" id="submenu2" data-bs-parent="#menu" style="">
<li class="w-100">
<span class="d-none d-sm-inline">Spray Guns</span>
</li>
<li>
<span class="d-none d-sm-inline">Clearcoat Kits</span>
</li>
<li>
<span class="d-none d-sm-inline">Primers</span>
</li>
<li>
<span class="d-none d-sm-inline">Body Fillers</span>
</li>
<li>
<span class="d-none d-sm-inline">Panel Wipe</span>
</li>
<li>
<span class="d-none d-sm-inline">Tinters</span>
</li>
<li>
<span class="d-none d-sm-inline">Abrasives</span>
</li>
</ul>
</li>
<li>
<a href="#submenu3" data-bs-toggle="collapse" class="nav_link active" aria-expanded="true"> <i class="bx bxs-t-shirt"></i> <span class="nav_name">
PPE & Workwear</span></a>
<ul class="nav-sub-cat flex-column ms-1 custom-scrollbar-js collapse show" id="submenu3" data-bs-parent="#menu" style="">
<li class="w-100">
<span class="d-none d-sm-inline">T-Shirts & Polo's</span>
</li>
<li>
<span class="d-none d-sm-inline">Jackets</span>
</li>
<li>
<span class="d-none d-sm-inline">Hi-Visibility</span>
</li>
<li>
<span class="d-none d-sm-inline">Eye Protection</span>
</li>
<li>
<span class="d-none d-sm-inline">Headwear</span>
</li>
<li>
<span class="d-none d-sm-inline">Gloves</span>
</li>
</ul>
</li>
<hr style="color: white;">
<div class="nav_list">
<i class="bx bx-grid-alt nav_icon"></i> <span class="nav_name">Dashboard</span>
<i class="bx bx-shopping-bag nav_icon"></i> <span class="nav_name">Shop</span>
<i class="bx bx-cart"></i> <span class="nav_name">Cart</span>
<a href="/AccountManage" class="nav_link"> <i class="bx bx-user nav_icon"></i> <span class="nav_name">My
Account</span> </a>
</div>
<i class="bx bx-log-out nav_icon"></i> <span class="nav_name">SignOut</span>
</div></nav>
</div>

React problem with AdminLTE3 sidebar treeview

So I want to make a React sidebar with an item 'Employee' that when clicked will expand three child items.
Here is the code
import React, { Component } from "react";
export default class Sidebar extends Component {
constructor(props) {
super(props);
this.state = {
user: {}
}
}
componentDidMount() {
let userData = JSON.parse(localStorage.getItem('user'))
this.setState({user: userData})
}
render() {
return (
<aside className="main-sidebar sidebar-dark-primary elevation-4" >
{/* Brand Logo */}
<a href="/" className="brand-link">
<span className="brand-text font-weight-light ml-1">HRMS</span>
</a>
{/* Sidebar */}
<div className="sidebar">
{/* Sidebar user panel (optional) */}
<div className="user-panel mt-3 pb-3 mb-3 d-flex">
<div className="image">
<img
src={process.env.PUBLIC_URL + '/dist/img/user2-160x160.jpg'}
className="img-circle elevation-2"
alt="User Image"
/>
</div>
<div className="info">
<a href="#" className="d-block">
{this.state.user.fullname}
</a>
</div>
</div>
{/* Sidebar Menu */}
<nav className="mt-2">
<ul
className="nav nav-pills nav-sidebar flex-column"
data-widget="treeview"
role="menu"
data-accordion="false"
>
{/* Add icons to the links using the .nav-icon class
with font-awesome or any other icon font library */}
<li className="nav-item">
<a href="/" className="nav-link active">
<i className="nav-icon fas fa-tachometer-alt" />
<p>
Dashboard
<span className="right badge badge-success">Home</span>
</p>
</a>
</li>
<li className="nav-item">
<a href="pages/widgets.html" className="nav-link">
<i className="nav-icon fas fa-th" />
<p>
Widgets
<span className="right badge badge-danger">New</span>
</p>
</a>
</li>
<li className="nav-item has-treeview">
<a href="#" className="nav-link">
<i className="nav-icon fa fa-user" />
<p>
Employee
<i className="right fas fa-angle-left" />
</p>
</a>
<ul className="nav nav-treeview">
<li className="nav-item">
<a href="/employee-add" className="nav-link">
<i className="fa fa-user-plus nav-icon" />
<p>Add Employee</p>
</a>
</li>
<li className="nav-item">
<a href="/employee-list" className="nav-link">
<i className="fas fa-users nav-icon" />
<p>Employee List</p>
</a>
</li>
<li className="nav-item">
<a href="/employee-add" className="nav-link">
<i className="far fa-circle nav-icon" />
<p>Employee Award</p>
</a>
</li>
</ul>
</li>
The problem is after login redirects to this page and I click the Employee item, the href activates and just reloads the page (what href="#" usually does). However if i remove the <i></i> tag or the href the css gets all messed up.
I am using AdminLTE3 so here is the documentation: https://adminlte.io/docs/3.0/javascript/treeview.html
I found the answer as it is a problem to many people. The problem occurs when you redirect from another page (i.e login page)
Here is the link to the answer: https://github.com/ColorlibHQ/AdminLTE/issues/1570#issuecomment-615841382
Try This
index.html
add this code to the script after body tag
<script>
$(document).ready(function(){
$('.nav-item ').click(function(){
if($(this).hasClass('menu-open')){
$(this).removeClass("menu-open");
$(this).children().removeClass("active");
}else{
$(this).addClass("menu-open");
$(this).children().addClass("active");
}
$('.nav-item').children().removeClass('active').not(this);
$(this).children().addClass("active");
});
});
</script>

Submenu of a menu doesn't open

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<header>
<nav class="navbar navbar-expand-sm navbar-light bg-light">
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="nav navbar-nav ml-auto">
<li class="nav-item dropdown mr-2 cursor-pointer" dropdown>
<a class="btn nav-link dropdown-toggle" dropdownToggle>
</a>
<div class="dropdown-menu dropdown-menu-right" *dropdownMenu>
<a class="btn dropdown-item" *ngFor="let language of languages" (click)="setLanguage(language)">
<span style="vertical-align: super;"></span>
</a>
</div>
</li>
<!-- utente con avatar -->
<li class="nav-item dropdown mr-2 cursor-pointer" dropdown>
<a class="btn nav-link float-right mt-1 pr-4" dropdownToggle>
<span class="float-left mt-1">
<i class="fa fa-user" style="font-size: 1.5rem;"></i>
<!-- prevedere user image -->
</span>
<span class="float-right mt-1 ml-1">
<div><b>user</b></div>
<div *ngIf="currentUser.roles && currentUser.roles.length == 1">desc</div>
<div *ngIf="currentUser.roles && currentUser.roles.length > 1">role</div>
</span>
</a>
<!-- menu -->
<div class="dropdown-menu dropdown-menu-right" *dropdownMenu>
<!-- logo confidi -->
<div class="dropdown-item text-center user-image">
<img [src]="userService.getUserPicture(currentUser?.image?.content)" class="img-fluid" alt="">
</div>
<!-- ultimo accesso -->
<div class="dropdown-item">
<div class="font-weight-bold">access </div>
<div>date</div>
</div>
<!-- matricola -->
<div class="dropdown-item">
<div class="font-weight-bold">numer </div>
<div>user</div>
</div>
<!-- ruoli -->
<div class="nav-item dropdown mr-2 cursor-pointer" dropdown>
<a class="btn nav-link dropdown-toggle font-weight-bold" dropdownToggle>roles</a>
<div class="dropdown-menu dropdown-menu-right" *dropdownMenu>
<a class="btn dropdown-item" *ngFor="let role of currentUser.roles; let i = index">
code - desc
</a>
</div>
</div>
<a class="dropdown-item logout-link" (click)="logout()">
<i class="fa fa-lock"></i> <span class="font-weight-bold">logout</span></a>
</div>
</li>
</ul>
</div>
</nav>
</header>
I have a dropdown-menu that contains multiple dropdown-item and an item that I want to be a submenu(that contains a list of item).
I add the submenu on my menu but when I try to open it does not open.
Here is the stackblitz
https://angular6-bootstrap4-navbar-j8ar1z.stackblitz.io
As you see there is a submenu called roles that doesn't open. How can I fix it?
The problem lies in your HTML - you cannot nest <li> tag inside of another <li> tag.
The HTML <li> element is used to represent an item in a list. It must be contained in a parent element: an ordered list (<ol>), an unordered list (<ul>), or a menu (<menu>).
Source: MDN web docs
You can put <ul> inside of <li> though. It is actually a proper way to create a nested list.
Another thing is that you are trying to use nested dropdown and these seem to still be an experimental feature of ngx-bootstrap
Basic working example:
<!-- template.html !-->
<ul >
<li dropdown [autoClose]="false" container="body">
<a dropdownToggle class="dropdown-item dropdown-toggle"
(click)="false">Languages <span class="caret"></span></a>
<ul id="dropdown-nested" *dropdownMenu class="dropdown-menu"
role="menu" aria-labelledby="button-nested">
<li role="menuitem" *ngFor="let lang of languages"><a class="dropdown-item" href="#/dropdowns#nested-dropdowns">{{lang}}</a></li>
</ul>
</li>
<li dropdown [autoClose]="false" container="body">
<a dropdownToggle class="dropdown-item dropdown-toggle"
(click)="false">User <span class="caret"></span></a>
<ul id="dropdown-nested" *dropdownMenu class="dropdown-menu"
role="menu" aria-labelledby="button-nested">
<li role="menuitem"><a class="dropdown-item" href="#/dropdowns#nested-dropdowns">Settings</a></li>
<li role="menuitem" dropdown triggers="mouseover" placement="right" container="body">
<a dropdownToggle class="dropdown-item dropdown-toggle"
(click)="false">Roles<span class="caret"></span></a>
<ul *dropdownMenu class="dropdown-menu" role="menu">
<li role="menuitem" *ngFor="let role of currentUser.roles"><a class="dropdown-item" href="#/dropdowns#nested-dropdowns">{{role}}</a></li>
</ul>
</li>
<li role="menuitem"><a class="dropdown-item" href="#/dropdowns#nested-dropdowns">Logout</a></li>
</ul>
</li>
</ul>
// Component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html'
})
export class AppComponent {
public menu: {}[] = [];
languages = ['pl', 'en', 'de', 'es'];
currentUser = {roles: ['admin', 'inboxUser', 'developer']}
}
Example on Stackblitz

Sidebar menu not working in Laravel+vue+adminlte

I have installed AminLte v3 using npm in my Laravel + vue project ad evrything is working great but when i click on the Side navbar main menu which is tagged as
<li class="nav-item has-treeview">
<a href="#" class="nav-link">
<i class="nav-icon fas fa-users"></i>
<p>
Members
<i class="fas fa-angle-left right"></i>
<span class="badge badge-warning right">new:2</span>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<router-link :to="{name : 'members'}" class="nav-link">
<i class="fas fa-user-check nav-icon"></i>
<p>All</p>
</router-link>
</li>
<li class="nav-item">
<router-link :to="{name:'membersLatest'}" class="nav-link">
<i class="fas fa-user-plus nav-icon"></i>
<span class="badge badge-danger right">2</span>
<p>Latest</p>
</router-link>
</li>
<li class="nav-item">
<router-link :to="{name:'membersPending'}" class="nav-link">
<i class="fas fa-user-clock nav-icon"></i>
<p>Pending</p>
</router-link>
</li>
<li class="nav-item">
<router-link :to="{name:'membersSuspended'}" class="nav-link">
<i class="fas fa-user-lock"></i>
<span class="badge badge-danger right">2</span>
<p>Suspended</p>
</router-link>
</li>
</ul>
</li>
It is redirecting me to # router path which is coming from
<a href="#" class="nav-link">
<i class="nav-icon fas fa-users"></i>
<p>
Members
<i class="fas fa-angle-left right"></i>
<span class="badge badge-warning right">new:2</span>
</p>
</a>
This part and it is not opening sub-menus inside the main-menu and I am including the navBar from a another vue component.
Can anybody give an idea how am I going to solve this?
When you are hitting on another route instead of admitlte routes, the treeview selector is unable to find the element. When you push the url to redirect into adminlte , the treeview won't work because the selector is defined before element mounted.
To fix this problem define a mounted hook in the sidebar component.
mounted(){
$('[data-widget="treeview"]').Treeview('init');
}
in the bootstrap.js file put require('admin-lte') below
require('bootstrap')

Categories