I have two layer navbar and the app is using Lazy loading, but every time I clcik on Team Management button the component is working but the Admin Panel navbar is dispear:
Here is my admin-routing.module.ts:
const routes: Routes = [
{ path: '', component: AdminComponent },
{
path: 'team',
loadChildren: () => import('./team/team.module').then((m) => m.TeamModule),
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AdminRoutingModule {}
Here is HTML for the admin.component.html:
<div>
<nav class="navbar navbar-expand-sm navbar-light bg-light mb-3">
<div class="container">
<a class="navbar-brand" href="#">Admin Panel</a>
<button
class="navbar-toggler"
data-toggle="collapse"
data-target="#team-navbarNav"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="team-navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/team" routerLink="team"
>Team Management</a
>
</li>
<li class="nav-item">
<a class="nav-link" href="">Others</a>
</li>
</ul>
</div>
</div>
</nav>
</div>
<router-outlet></router-outlet>
Here is the result of after click on Team Management button:
As you can see the second navbar is gone, I do set up
<router-outlet></router-outlet>
in admin.component.html, but it feels like never works..
team is the sub component of admin.
admin-routing. module.ts:
Here is my Github repo:
https://github.com/qwe3804132/BusyQA-CRM/tree/main/CRMFrontEnd
any suggestions?
I have character component where I have a listing of characters. Each characters have a router-link which is redirecting to characters detail component. I want to add router-link-exact-active in Nvabra's character when character detail is in view.
{
path: '/characters',
name: 'characterList',
component: () => import('../components/characters/characterList.vue')
},
{
path: '/characters/:id',
name: 'characterDetail',
component: () => import('../components/characters/charactersDetail.vue')
},
Navbar
<ul class="navbar-nav m-auto custom-nav">
<li class="nav-item">
<router-link to="/">home</router-link>
</li>
<li class="nav-item">
<router-link to="/about-Us">about us</router-link>
</li>
<li class="nav-item">
<router-link to="/characters">characters</router-link>
</li>
<li class="nav-item">
<router-link to="/our-comics">comics</router-link>
</li>
</ul>
I am using bootstrap 4.3.1 and vue#2.6.10
I have this menu (is using collapse - and I don`t want to use JQuery):
<li class="nav-item">
<a class="nav-link" href="#sidebar-products" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="sidebar-products">
<i class="ni ni-single-copy-04 text-primary"></i>
<span class="nav-link-text">Products</span>
</a>
<div class="collapse" id="sidebar-products">
<ul class="nav nav-sm flex-column">
<li class="nav-item">
Item List 1
</li>
<li class="nav-item">
Item List 2
</li>
</ul>
</div>
</li>
This is only a single block that contains 2 sub-items.
What I saw using JQuery, when click on "Products" the #sidebar-products receives the .show class and aria-expanded="true".
When having multiple blocks - when click on a block to close (if there are collapsed) the others blocks.
How can I make it work the collapse with vue?
UPDATE 1
I created a click event that do the job:
<a class="nav-link" href="javascript:void(0)" #click="navItemCollapse('sidebar-products', $event)" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="sidebar-products">
and the event:
navItemCollapse(id, event) {
let expanded = event.target.getAttribute('aria-expanded').toLocaleLowerCase() == 'true' ? true : false;
let el = document.getElementById(id);
expanded ? el.classList.remove('show') : el.classList.add('show');
event.target.setAttribute('aria-expanded', !expanded);
}
But what if I have more blocks ? When click to open the current collapse on a block to close the others ???
This is the implementation of no jquery
new Vue({
el: '#app',
data() {
return {
menuList: [{
name: 'Products',
expand: false,
items: [{
name: 'Item List 1',
link: ''
},
{
name: 'Item List 2',
link: ''
}
]
},
{
name: 'Others',
expand: false,
items: [{
name: 'Other Item 1',
link: ''
},
{
name: 'Other Item 2',
link: ''
}
]
}
]
}
},
methods: {
navItemCollapse(index) {
this.menuList = this.menuList.map((item, i) => {
item.expand = !item.expand
if (i !== index) {
item.expand = false
}
return item
})
}
}
})
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<ul id="app">
<li v-for="(navItem,i) in menuList" :key="i" class="nav-item">
<a class="nav-link" href="javascript:;" data-toggle="collapse" role="button" :aria-expanded="navItem.expand" aria-controls="sidebar-products" #click.prevent="navItemCollapse(i)">
<i class="ni ni-single-copy-04 text-primary"></i>
<span class="nav-link-text">{{navItem.name}}</span>
</a>
<div v-if="navItem.items.length>0" class="collapse" :class="{show: navItem.expand}">
<ul class="nav nav-sm flex-column">
<li v-for="(subItem,j) in navItem.items" :key="j" class="nav-item">
{{subItem.name}}
</li>
</ul>
</div>
</li>
</ul>
I integrate the menu data into an array of objects. Each object has an expand flag to determine whether it is currently expanded. When you click on the menu, switch the expand flag of the current menu.
Note: You don't need to care about the id of the <a> tag.
No jQuery or bootstrap-vue ...
Create a function in the Component to handle the normal Bootstrap class and timing logic...
data() {
return {
classArr: ['collapse'],
styleObj: {}
};
},
methods: {
toggleCollapse(ref) {
let show = this.classArr.indexOf('show')>-1?false:'show'
this.classArr = ['collapsing']
setTimeout(() => {
if (show){
let height = this.$refs[ref].firstChild.clientHeight + 'px';
this.styleObj = { height }
}
else {
this.styleObj = {}
}
}, 10)
setTimeout(() => {
this.classArr = ['collapse', show]
}, 340)
}
}
In the component template, bind the class and style attrs to the data manipulated by the method. The ref of the specific collapse is passed in to the method...
<li class="nav-item">
<a class="nav-link" href="#sidebar-products" role="button" #click="toggleCollapse('sidebar')">
<i class="ni ni-single-copy-04 text-primary"></i>
<span class="nav-link-text">Products</span>
</a>
<div :class="classArr" :style="styleObj" id="sidebar-products" ref="sidebar">
<ul class="nav nav-sm flex-column">
<li class="nav-item">
Item List 1
</li>
<li class="nav-item">
Item List 2
</li>
</ul>
</div>
</li>
https://www.codeply.com/p/GA5CaNMzmc
EDIT: I updated the demo to make it scaleable for multiple collapses
This is a fully working version using bootstrap-vue:
<div class="accordion" role="tablist">
<b-card v-for="(value, key) in this.jobs" :key="key" no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab">
<b-button block v-b-toggle="'accordion-'+key" variant="primary">{{ value.title }}</b-button>
</b-card-header>
<b-collapse :id="'accordion-'+key.toString()" accordion="my-accordion" role="tabpanel">
<b-card-body>
<b-card-text>{{ value.specs }}</b-card-text>
</b-card-body>
</b-collapse>
</b-card>
</div>
Data object:
data() {
return {
jobs: [
{
title: 'Design artist',
specs: 'Have an eye for web beauty'
},
{
title: 'Backend guru',
specs: 'Do stuff that don\'t break'
},
{
title: 'Frontend master',
specs: 'Create an UI that works'
}
]
}
}
I like the #sugars approach :)
So...the final version is this:
<li v-for="(navItem, i) in sidenavItems" class="nav-item">
<router-link v-if="!navItem.isCollapsible" class="nav-link" #click.native="navItemCollapse(i)" active-class="active" :to="{name: navItem.route}" exact>
<i :class="navItem.class"></i>
<span class="nav-link-text">{{ navItem.name }}</span>
</router-link>
<a v-if="navItem.isCollapsible" class="nav-link" href="javascript:void(0)" #click="navItemCollapse(i)" data-toggle="collapse" :aria-expanded="navItem.expanded">
<i :class="navItem.class"></i>
<span class="nav-link-text">{{ navItem.name }}</span>
</a>
<div v-if="navItem.isCollapsible" class="collapse" :class="navItem.expanded ? 'show' : ''">
<ul class="nav nav-sm flex-column">
<li v-for="subItem in navItem.items" class="nav-item">
<router-link class="nav-link" :to="{name: subItem.route}">{{ subItem.name }}</router-link>
</li>
</ul>
</div>
</li>
the sidenavItems:
sidenavItems: [
{name: 'Dashboard', isCollapsible: false, route: 'dashboard', class: 'class1'},
{name: 'Categories', isCollapsible: false, route: 'category', class: 'class2'},
{name: 'Brands', isCollapsible: false, route: 'brand', class: 'class3'},
{name: 'Products', isCollapsible: true, expanded: false, class: 'class4', items: [{name: 'List', route: 'product'}]},
{name: 'Orders', isCollapsible: false, route: 'order', class: 'class5'},
{name: 'Blog', isCollapsible: true, expanded: false, class: 'class6', items: [{name: 'List', route: ''}]},
],
and the navItemCollapse method:
navItemCollapse(index) {
this.sidenavItems = this.sidenavItems.map( (item, i) => {
item.expanded = !item.expanded;
if(i !== index) {
item.expanded = false;
}
return item;
})
}
I tried laravel 5.7 and vue project below sample code with two components. But i had an error.
It gives that error.
[Vue warn]: Failed to mount component: template or render function not defined.
Can someone help me to fix this.
master.blade.php
<nav class="mt-2">
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
<li class="nav-item has-treeview menu-open">
<a href="#" class="nav-link active">
<i class="nav-icon fa fa-dashboard"></i>
<p>
Dashboard
<i class="right fa fa-angle-left"></i>
</p>
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<router-link to="/dashboard" class="nav-link">
<i class="fa fa-circle-o nav-icon"></i>
<p>Dashboard</p>
</router-link>
</li>
<li class="nav-item">
<router-link to="/profile" class="nav-link">
<i class="fa fa-circle-o nav-icon"></i>
<p>Profile</p>
</router-link>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<section class="content">
<div class="container-fluid">
<router-view></router-view>
</div>
</section>
app.js
require('./bootstrap');
window.Vue = require('vue');
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let Dashboard = require('./components/Dashboard.vue');
let Profile = require('./components/Profile.vue');
let routes = [
{ path: '/dashboard', component: Dashboard },
{ path: '/profile', component: Profile }
]
const router = new VueRouter({
//mode: 'history',
routes // short for `routes: routes`
})
const app = new Vue({
el: '#app',
router
});
I have html like this:
<div id="nav">
<homenav v-on:navigation="switchNav(this.nav)" v-if="nav == 'homeNav'"></homenav>
<mainav v-if="nav == 'mainNav'"></mainav>
</div>
My Js is like this:
Vue.component('homenav', Navigation);
Vue.component('mainav', Navigation2);
new Vue({
el: '#nav',
data: {
nav: 'homeNav'
},
methods: {
switchNav: function (test) {
console.log(test);
console.log(this.nav);
}
}
});
Part of homenav component to show what I want to do:
<template>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="">Website Builder</a>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav nav-fill w-100">
<li class="nav-item">
<a class="nav-link" href="/#/">Create</a>
</li>
<li class="nav-item">
<a v-on:click="navData" class="nav-link" href="/#/how">How</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/#/about">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/#/youtube">Videos</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/#/login">Go to main site</a>
</li>
</ul>
</div>
</nav>
</template>
<script>
export default {
data() {
return {
nav: ''
}
},
methods: {
navData () {
this.nav = 'mainNav';
this.$emit('navigation');
console.log(this.nav);
}
}
}
So what I am trying to accomplish here is a dynamic switch in navigation, for example if user click on Go to main site link the nav would change from homenav to mainav dynamically. However, I don't know how to accomplish it and my attempt is above. Help..
Edit so in my newest attempt I have managed so that it console log from child + parent function. it consoles homeNav and mainNav together. However I need to also pass the child this.nav to parent so parent can update it's this.nav? Because at the moment despite it outputting both, navigation doesn't change.
The best way to achieve that is using Vue Router.
But, if you want to do that without routing you should do it with Dynamic Components
<component is=""></component>
You can see an example here: https://jsfiddle.net/lucaskatayama/256Lo0xa/1/
There is an App, with a button to toggle a component inside <component></component>.
It simulates your switch, by changing the selected component.