9

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?

user5417542
  • 3,146
  • 6
  • 29
  • 50

8 Answers8

31

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>
cinder
  • 426
  • 4
  • 2
19

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
    }
  }
}
claudios
  • 6,588
  • 8
  • 47
  • 90
4

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>
Tienou
  • 700
  • 6
  • 17
3

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.

0

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>
Umair Qazi
  • 195
  • 3
  • 9
  • 1
    add some explanation to the answer – Arghya Sadhu Jun 15 '20 at 09:24
  • https://bootstrap-vue.org/docs/components/collapse#comp-ref-b-collapse-rootEventListeners Above snippet is watching for route change and then it will get the element by id `#nav-collapse`. Bootstrap adds a class namely `show` when it gets expanded on hamburger click. if its true it will trigger the toggle method which is mentioned in bootstrap-vue docs. – Umair Qazi Jun 16 '20 at 13:59
  • I've updated my answer, have a look for better understanding. – Umair Qazi Jun 16 '20 at 14:27
0

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
    });
0

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
        }
    }
}})())



Nawi
  • 51
  • 5
-1
    router.beforeEach((from,to,next) => {
           $('.navbar-collapse').collapse('hide'); //Be sure to import jquery
        next();
    });

This works

JJRM
  • 1