How can I create dynamic menu with submenu in vue 2? - javascript

I have a problem and if you can help me I would be grateful, because I am working with vue for 3 weeks.
I try to create a menu with submenu in vue 2 by two weeks and I can't succeed. the menu is created , but when I go to submenu is won't create it. the code is next:
<script>
import image from "./assets/img/logo-just-escape.png"
import axios from "axios"
export default {
data(){
const lang = localStorage.getItem('lang')
return {
imagel: image,
lang: lang,
languages:null,
menu:null,
submenu:null
}
},
async created(){
try {
var res =await axios.get(`lng`);
this.languages=res.data;
const valmenu="titles/value?language="+this.lang;
res=await axios.get(valmenu);
this.menu=res.data;
this.submenu=this.getSubMnu(this.menu);
console.log(this.submenu)
}catch(e){
console.error(e);
}
},
methods: {
handleChange(event){
localStorage.setItem('lang',event.target.value);
window.location.reload();
},
getSubMnu(value){
let temp='';
let sbmenu=[];
let variable=null;
for(temp in value){
if('2'==value[temp].subtitle){
variable=value[temp];
let temp1=value[temp].link+"\/"+this.menu[temp].id;
variable.link=temp1;
sbmenu.push(variable);
}
}
return sbmenu;
}
}
}
</script>
<template>
<div id="app" class="bg-dark">
<div>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="/">
<img width="100" height="50" :src="imagel"/>
</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<div v-for="menuButton in this.menu" :value="menuButton.title" :key="menuButton.id">
<li class="nav-item" v-if="menuButton.subtitle ===0">
<router-link :to="menuButton.link" ><span class="nav-link">{{menuButton.title}}</span></router-link>
</li>
<li class="nav-item dropdown" v-if="menuButton.subtitle ===1" style="color: white;">
<span class="nav-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{menuButton.title}}</span>
<div v-for="tempor in this.submenu" class="dropdown-menu dropdown-menu-right bg-dark" :value="tempor.title" :key="tempor.id">
<span class="nav-link">{{tempor.title}}</span>
<router-link :to="tempor.link" #click.name><span class="nav-link">{{tempor.title}}</span></router-link>
</div>
</li>
</div>
<li class="nav-item">
<select class="selectpicker form-control" v-model="lang" data-width="fit" #change="handleChange($event)">
<option v-for="langu in languages" :value="langu.language_short" :key="langu.id">
{{langu.language}}
</option>
</select>
</li>
</ul>
</div>
</nav>
<div class="divmargin" >
<router-view/>
</div>
</div>
</div>
</template>
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in render: "TypeError: Cannot read property 'submenu' of undefined"
found in
---> at src/App.vue
If someone can give me some answer to this I will be very grateful.
Thank you,
Vlad.

Related

Vue/Nuxt app is rendering content (not components, just content) twice on every page

I am very new to Vue/Nuxt programming and followed a "add a blog" tutorial which I then modified for my site. It all works perfectly except the actual it is rendering content twice. It renders
NavPage (component) > content > FooterDiv(component) then content again. See image:
Image of the page showing duplicated content
This happens on every page.
I am including my blogpage code ecasue in testing it seems to be where the problem lives :
<template>
<div>
<div class="home-page">
<h2>Latest Posts</h2>
<div class="articles">
<div class="article" v-for="article of articles" :key="article.slug">
<nuxt-link :to="{ name: 'slug', params: { slug: article.slug } }">
<div class="article-inner">
<img :src="require(`~/assets/resources/${article.img}`)" alt="" />
<div class="detail">
<h3>{{ article.title }}</h3>
<p>{{ article.description }}</p>
</div>
</div>
</nuxt-link>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "BlogPage",
data() {
return {
name: ''
}
},
mounted() {
let user = localStorage.getItem('user-info');
if (!user) {
this.$router.push({ name: "BlogPage" })
}
},
async asyncData({ $content, params }) {
const articles = await $content('articles', params.slug)
.only(['title', 'description', 'img', 'slug'])
.sortBy('createdAt', 'asc')
.fetch()
return {
articles
}
}
}
I have also included the structure being rendered by Vue per the Vue Dev Tools
This image is what I see in the dev tools when the page is rendered
I have spent hours troubleshooting this and can find no other info on the issue.
Thank you for any help, and your patience with a newbie. Let me know if you need to see any other code.
As requested here is my NavPage component code:
<template>
<!-- Navigation-->
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand" href="#page-top">Denise Pedro</a>
<button class="navbar-toggler text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto">
<li class="navbar-brand"> <NuxtLink to="/">Home</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/PortfolioPage">Portfolio</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/ResumePage">Resume</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/ContactPage">Contact</NuxtLink></li>
<li class="navbar-brand"> <NuxtLink to="/BlogPage">Blog</NuxtLink></li>
</ul>
</div>
</div>
</nav>
</template>
and my FooterDiv component
<template>
<!-- Footer-->
<footer class="footer text-center">
<div class="container">
<div class="row">
<!-- Footer Location-->
<div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">Location</h4>
<p class="lead mb-0">
Seattle through Olympia, WA
<br />
</p>
</div>
<!-- Footer Social Icons-->
<div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">Around the Web</h4>
<!-- <a class="btn btn-outline-light btn-social mx-1" href="#!"><font-awesome-icon icon="fa-brands fa-facebook" /></a> -->
<a class="btn btn-outline-light btn-social mx-1" href="#!"><img src="../assets/img/facebook-brands.svg" alt="facebook icon" /></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><img src="../assets/img/twitter-brands.svg" alt="twitter icon"/></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><img src="../assets/img/linkedin-in-brands.svg" alt="linkedin icon"/></a>
</div>
<!-- Footer About Text-->
<div class="col-lg-4">
<h4 class="text-uppercase mb-4">Denise Pedro</h4>
<p class="lead mb-0">
desiraes#gmail.com
<!-- Start Bootstrap -->
</p>
</div>
</div>
</div>
</footer>
</template>
and lastly, my layout code
<template>
<div>
<NavPage />
<Nuxt />
<FooterDiv />
<Nuxt />
</div>
</template>
<script>
import NavPage from '../src/components/NavPage.vue';
import FooterDiv from '../src/components/FooterDiv.vue'
export default {
components: {
NavPage,
FooterDiv
},
}
</script>
Thank you
In your layout, you've put </Nuxt> twice, that's why the page content is duplicated, you should remove it.
your layout.vue should look like that:
<template>
<div>
<NavPage />
<Nuxt />
<FooterDiv />
</div>
</template>
<script>
import NavPage from '../src/components/NavPage.vue';
import FooterDiv from '../src/components/FooterDiv.vue'
export default {
components: {
NavPage,
FooterDiv
},
}
</script>

Vue not passing data in component

I am not sure why the data is undefined despite passing the right property from the component.
This is my vue component
Vue.component('store-squaretile-component',{
template: '#store-squaretile-component',
props: [
'storeName'
],
data: function () {
return {}
},
});
This is its template
<script type='text/x-template' id='store-squaretile-component'>
<div class="stores-squaretile__container">
<div class="stores-squaretile__btn stores-squaretile__btn--shadow" >
<!-- background of store-squaretile to be set to img -->
<div class="dropdown">
<div class="stores-squaretile__threedots" data-bs-toggle="dropdown" >
<i class="fas fa-ellipsis-v"></i>
</div>
<ul id="dropdown-menu-store" class="dropdown-menu" >
<div class="'dropdown-item dropdown-title">Quick Actions</div>
<div class="dropdown-line"></div>
<a class="dropdown-item" href="#">Edit Store</a>
<a class="dropdown-item" href="#">Delete Store</a>
</ul>
</div>
</div>
<div class="stores-squaretile__title">{{storeName}}</div>
</div>
</script>
When i pass the component this array:
stores: [
{name: "harry's",},
{name: "Carl's junior",},
{name: "Mcdonald's",}
]
into this component
<store-squaretile-component
v-for="store in stores"
:storeName="store.name"
></store-squaretile-component>
it is suppose to suppose to replace the storeName with the name in the array but instead I get a NaN or the title disappears entirely.
I received an undefined value. Is there a reason for this?
It's working fine, just replaced storeName with storename and added :key to v-for loop:
Vue.component('store-squaretile-component', {
template: '#store-squaretile-component',
props: ['storename'],
})
new Vue({
el: '#demo',
data() {
return {
stores: [
{name: "harry's", },
{name: "Carl's junior",},
{name: "Mcdonald's",}
]
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<store-squaretile-component
v-for="(store, idx) in stores"
:storename="store.name"
:key="idx"
></store-squaretile-component>
</div>
<script type='text/x-template' id='store-squaretile-component'>
<div class="stores-squaretile__container">
<div class="stores-squaretile__btn stores-squaretile__btn--shadow" >
<div class="dropdown">
<div class="stores-squaretile__threedots" data-bs-toggle="dropdown" >
<i class="fas fa-ellipsis-v"></i>
</div>
<ul id="dropdown-menu-store" class="dropdown-menu" >
<div class="'dropdown-item dropdown-title">Quick Actions</div>
<div class="dropdown-line"></div>
<a class="dropdown-item" href="#">Edit Store</a>
<a class="dropdown-item" href="#">Delete Store</a>
</ul>
</div>
</div>
<div class="stores-squaretile__title">{{storename}}</div>
</div>
</script>

Angular 8 loose data after refresh page

I have isAdmin boolean property which I am checking user logged in as user or admin.
Backend is .net core 2.2, db - Postgre.
Everything works fine but after refresh I lose isAdmin value.
I have conditional show hide dropdown which is available only for admin roles.
How don't lose data after refreshing?
P.S. How to add logic also to my guard for isAdmin property?
My component looks like:
model: any = {};
constructor(public authService: AuthService, private alertify: AlertifyService, private router:
Router) { }
ngOnInit() {
}
login() {
this.authService.login(this.model).subscribe(next => {
this.model.isAdmin = true;
this.alertify.success('Logged in as Admin')
}, error => {
this.alertify.error(error)
}, () => {
this.router.navigate(['/projects'])
})
}
loginAsUser() {
this.authService.loginAsUser(this.model).subscribe(next => {
this.model.isAdmin = false;
this.alertify.success('Logged in as User')
}, error => {
this.alertify.error(error)
}, () => {
this.router.navigate(['/home'])
})
}
loggedIn() {
return this.authService.loggedIn();
}
logout() {
localStorage.removeItem('token');
this.alertify.message('logged out');
this.router.navigate(['/home'])
}
My html looks like:
<nav class="navbar navbar-expand-md navbar-light fixed-top bg-light">
<div class="container">
<a class="navbar-brand" [routerLink]="['/home']">
<img [src]="iteraLogo" alt="Itera">
</a>
<div *ngIf="loggedIn()" class="dropdown" dropdown [hidden]="!model.isAdmin">
<a class="dropdown-toggle" dropdownToggle>
<strong class="text-primary">Admin Panel</strong>
</a>
<div class="dropdown-menu mt-4" *dropdownMenu>
<ul class="navbar-nav">
<li class="nav-item" routerLinkActive="router-link-active">
<a class="nav-link" [routerLink]="['/projects']">Projects</a>
</li>
<li class="nav-item" routerLinkActive="router-link-active">
<a class="nav-link" [routerLink]="['/hypervisors']">Hypervisors</a>
</li>
<li class="nav-item" routerLinkActive="router-link-active">
<a class="nav-link" [routerLink]="['/management']">Management</a>
</li>
<li class="nav-item" routerLinkActive="router-link-active">
<a class="nav-link" [routerLink]="['/users']">Users</a>
</li>
<li class="nav-item" routerLinkActive="router-link-active">
<a class="nav-link" [routerLink]="['/user-projects']">Users Projects</a>
</li>
</ul>
</div>
</div>
<ul class="navbar-nav mr-auto">
<li class="nav-item" routerLinkActive="router-link-active">
<a class="nav-link" [routerLink]="['/test']">About</a>
</li>
</ul>
<div *ngIf="loggedIn()" class="dropdown" dropdown>
<a class="dropdown-toggle" dropdownToggle>
Welcome <strong>{{ authService.decodedToken?.unique_name | titlecase }}</strong>
</a>
<div class="dropdown-menu mt-3" *dropdownMenu>
<a class="dropdown-item text-primary" [routerLink]="['/projects/',
authService.decodedToken?.nameid ]"><i class="fa fa-archive"> My Projects</i></a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" (click)="logout()"><i class="fa fa-sign-
out"> Logout</i></a>
</div>
</div>
<form *ngIf="!loggedIn()" #loginForm="ngForm" class="form-inline my-2 my-lg-0">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<i class="fa fa-user-circle-o text-primary" aria-hidden="true"></i>
</div>
</div>
<input class="form-control" placeholder="Username" name="username" required
[(ngModel)]="model.username" />
</div>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<i class="fa fa-unlock text-danger" aria-hidden="true"></i>
</div>
</div>
<input class="form-control" placeholder="Password" name="password" required type="password"
[(ngModel)]="model.password" />
</div>
<div>
<button [disabled]="!loginForm.valid" type="submit" (click)="loginAsUser()" class="btn btn-primary my-2 my-sm-0">
<i class="fa fa-user-circle" aria-hidden="true"></i> User
</button>
<button [disabled]="!loginForm.valid" type="submit" (click)="login()" class="btn btn-success
my-2 my-sm-0">
<i class="fa fa-user-secret" aria-hidden="true"></i> Admin
</button>
</div>
</form>
</div>
</nav>
My guard looks like:
canActivate(): boolean {
if(this.authService.loggedIn()) {
return true
}
this.alertify.error('You have no access to see this page!!!');
this.router.navigate(['/home']);
return false;
}
When you refresh the page it does not persist variable values, you need to store either in local storage or cookie.
A simple way to solve this is to use this lib:
https://www.npmjs.com/package/ng2-cookies
To install this library, run:
npm install ng2-cookies
Component
import { Cookie } from 'ng2-cookies/ng2-cookies';
ngOnInit() {
this.model.isAdmin = Cookie.get('isAdmin');
}
login() {
this.authService.login(this.model).subscribe(next => {
Cookie.set('isAdmin', 'true');
this.alertify.success('Logged in as Admin')
}, error => {
this.alertify.error(error)
}, () => {
this.router.navigate(['/projects'])
})
}
you can use ngx-cookie-service also
https://www.npmjs.com/package/ngx-cookie-service
You will have to store your Auth_Token in localhost/indexDB/SessionStorage and then inside your route guard check if that token is valid or not.
This way your app will not require authentication until your token is valid.
Use this npm module to achieve this : enter link description here
You have to make the auth service API call with ngoninit of the components and get the isAdmin flag. That way when u refresh everytime ngOnInit will get involved and u ll get that flag.
ngOnInit(){ this.authService.login(this.model).subscribe(next => {
this.model.isAdmin = true;
});
}
Set a variable in localStorage upon successful login, like
isloggedIn(authUser) {
return this.httpClient.post<any>(`${this.apiUrl}/api/users/login`, {user: authUser})
.do(res => this.setSession(res.user))
.shareReplay();
}
private setSession = (authResult) => {
localStorage.setItem('TOKEN', authResult.token);
localStorage.setItem('loggedUser', 'y');
this._router.navigate(['dashboard'])
};
Next time when you enter any component, check
if(!localStorage.getItem('loggedUser')){
this._router.navigate(['login']);
return false;
}
return true;
this will authenticate user without calling API again. just get key from LocalStorage.

How to use JavaScript with $ inside render() in Reactjs

I work on content editor in React admin interface.
And I'd love to install my favorite block content editor. But it's an old one and have no react version.
I know how to link .js and .css in head with ReactHelmet
But have no idea how to run following script:
<script>
$(function () {
$("#editor").brickyeditor({
ignoreHtml: true,
blocksUrl: 'data.json',
templatesUrl: 'templates.html',
onChange: function(data) {
console.log(data.html);
}
});
});
</script>
Here is initial html structure
<body>
<header>
<nav class="container navbar navbar-expand-lg navbar-light">
<a class="navbar-brand" href="index.html">BrickyEditor</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="http://brickyeditor.info/examples.html">More Examples</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/yakovlevga/brickyeditor">GitHub Repository</a>
</li>
</ul>
</div>
</nav>
</header>
<main>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="editor"></div>
</div>
</div>
</div>
</div>
</main>
</body>
Im using it like so:
import PageTitle from "../components/common/PageTitle";
import Helmet from "react-helmet";
import $ from 'jquery';
class NewsEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const {
} = this.state;
return (
<Container fluid className="main-content-container px-4">
{/* Page Header */}
<Row noGutters className="page-header py-4">
<PageTitle sm="4" title="News editor" subtitle="Drag and drop interface" className="text-sm-left" />
</Row>
<Helmet
title="Nested Title"
link={[
{"rel": "stylesheet", "href": "https://cdn.jsdelivr.net/npm/brickyeditor/dist/jquery.brickyeditor.min.css"}
]}
script={[
{"src": "https://cdn.jsdelivr.net/npm/brickyeditor/dist/jquery.brickyeditor.min.js"},
]}
/>
<header>
<script>
$(function () {
$("#editor").brickyeditor({
ignoreHtml: true,
blocksUrl: 'data.json',
templatesUrl: 'templates.html',
onChange: function(data) {
console.log(data.html);
}
});
});
</script>
<nav class="container navbar navbar-expand-lg navbar-light">
<a class="navbar-brand" href="index.html">BrickyEditor</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="http://brickyeditor.info/examples.html">More Examples</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/yakovlevga/brickyeditor">GitHub Repository</a>
</li>
</ul>
</div>
</nav>
</header>
<main>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="editor"></div>
</div>
</div>
</div>
</main>
</Container>
);
}
}
export default NewsEditor;
On this stage all I have is Failed to compile error.
UPD: Following advices I keep on getting TypeErrors
I always make re-usable components for external libraries. So in your case, it would be BrickyEditor component which could look like this:
class BrickyEditor extends React.Component {
editorRef = React.createRef();
componentDidMount() {
window.$(this.editorRef.current).brickyeditor(this.props);
}
render() {
return <div ref={this.editorRef}></div>
}
}
// in your NewsEditor component you can use it like so
<BrickyEditor
ignoreHtml={true}
blocksUrl="data.json"
templatesUrl="templates.html"
onChange={function(data) {
console.log(data.html);
}}
/>

VueJS close Hamburger Menu on Route Change

I have a simple VueJS App with a Navigation Bar from Bootstrap:
<template>
<header id="header">
<nav class="navbar mynavbar navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="logo" href="index.html"><img src="images/logo.png" alt=""></a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><router-link to="/home"><a>Home</a></router-link></li>
<li><router-link to="/about"><a>About Us</a></router-link></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
</nav>
</header>
</template>
Now I want to ensure that when I change the route, the Bootstrap Menu gets closed. What is the best way to accomplish this?
Instead of adding event handlers to every router-link, you can simply watch the $route property for changes:
<script>
export default {
watch: {
'$route' () {
$('#navbar-collapse').collapse('hide');
}
}
}
</script>
Without Bootstrap and jQuery, can be easily achieved using class toggle and watch route changes.
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false"
#click="toggledNav = !toggledNav"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
Script:
export default {
data () {
return {
toggledNav: false
}
},
watch: {
'$route' () {
this.toggledNav = false
}
}
}
You could give this a try:
<template>
<header id="header">
<nav class="navbar mynavbar navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="logo" href="index.html"><img src="images/logo.png" alt=""></a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><router-link #click.native="closeMenu()" to="/home"><a>Home</a></router-link></li>
<li><router-link #click.native="closeMenu()" to="/about"><a>About Us</a></router-link></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
</nav>
</header>
</template>
<script>
export default {
methods: {
closeMenu() {
$('#navbar-collapse').collapse('hide');
}
}
}
</script>
With vue3 and bootstrap5, adding this to the router-link element:
data-bs-toggle="collapse" data-bs-target=".navbar-collapse"
did not work for me: the menu would close without the link being followed.
So, I added this to router/index.js:
router.beforeEach(() => {
document.getElementById('navbarCollapse').classList.remove('show');
})
with navbarCollapse being the id of the div holding the menu/nav items.
It seemed to do the trick.
If necessary you can adjust the hamburger button state: its class list would need to contain "collapsed" and aria-expanded set to "false".
This gets corrected though when the user clicks the button again, so I didn't opt to write that code.
If you are using bootstrap-vue and vue-router.
<script>
export default {
watch: {
'$route' () {
const element = document.querySelector("#nav-collapse");
let isShown = element.classList.contains("show");
if(isShown){
this.$root.$emit('bv::toggle::collapse', 'nav-collapse')
}
}
}
}
</script>
<template>
<b-navbar toggleable="lg" type="" class="p-0">
<b-navbar-toggle target="nav-collapse" id="navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<div class="nav-wrapper w-100">
<ul class="app-navigation__list">
<router-link to="/whatever" tag="li" exact class="app-navigation__list__item">
<a href="">
<span class="link-text">Home</span>
</a>
</router-link>
<router-link to="/whatever" tag="li" exact class="app-navigation__list__item">
<a href="">
<span class="link-text">About</span>
</a>
</router-link>
<router-link to="/whatever" tag="li" exact class="app-navigation__list__item">
<a href="">
<span class="link-text">Store</span>
</a>
</router-link>
</ul>
</div>
</b-collapse>
</b-navbar>
</template>
I know this is an old question but my answer might help someone.
do this in your router/index.js
const router = createRouter({}); //P.S I am using Vue3
then add this before each route entering like so.
router.beforeEach(() => {
$('.navbar-collapse').collapse('hide'); //Be sure to import jquery
});
Because this is such a simple task, I try to make it as simple as my simple website.
Vue.mixin((()=> {
let store = Vue.observable({
indexMenu: false,
})
return{
computed: {
menu: {
get() {
return store.indexMenu
},
set(val) {
store.indexMenu = val
}
}
},
watch: {
'$route' () {
this.menu = false
}
}
}})())
router.beforeEach((from,to,next) => {
$('.navbar-collapse').collapse('hide'); //Be sure to import jquery
next();
});
This works

Categories