Search code examples
vue.jsvuejs2bootstrap-vue

How to keep a multi layer b-collapse menu open on re-fresh in VUE.js?


I'm struggling to find the best way to keep my multi-layer menu open on re-fresh.

Basically if someone drills down to the third layer in my menu and clicks re-fresh, then I want the menu to open back up to where they navigated to in the third layer without having to re-open the menu.

Please see my code below: (Using Vue-Bootstrap and Vue.js)

As you can see, I'm repeating over each layer I get from my data.

        <div v-for="(main, index) in mainMenu" :key="index">
          <template v-if="main.title === 'News'">
            <b-link @click="closeAll" v-if="main.type === 'post_type' " :to="'/' + main.slug" v-b-toggle="'collapse'"  class="m-1 nobutn" v-html="main.title"></b-link>
          </template>
          <template v-else>
            <b-link v-if="main.type === 'post_type' " :to="'/' + main.slug" v-b-toggle="main.post_name" class="m-1 nobutn" v-html="main.title"></b-link>
            <b-link v-else :to="'/' + main.url" v-b-toggle="main.post_name" class="m-1 nobutn" v-html="main.title"></b-link>
          </template>
          <b-collapse v-model="main.show" v-for="(sub, index) in main.child_items" :key="index" v-bind:id="sub.menu_item_parent" accordion="my-accordion" role="tabpanel">
            <template v-if="sub.type === 'post_type'">
              <b-link class="secondLayer" :to="'/' + main.slug + '/' + sub.slug" :class="sub.classes">
                <b-card v-b-toggle="sub.post_name" class="subTitle" v-html="sub.title"></b-card>
              </b-link>
            </template>
            <template v-else>
              <b-link :href="sub.url" target="_blank" :class="sub.classes">
                <b-card v-b-toggle="sub.post_name" class="subTitle" v-html="sub.title"></b-card>
              </b-link>               
            </template>
            <b-collapse v-for="(subchild, index) in sub.child_items" :key="index" v-bind:id="subchild.menu_item_parent" accordion="my-accordiontwo" role="tabpanel">
              <template v-if="subchild.title === 'Members Portal' ">
                <b-link class="thirdLayer" :href="subchild.url" target="_blank" :class="subchild.classes">
                  <b-card v-b-toggle="subchild.post_name" class="subchildTitle" v-html="subchild.title"></b-card>
                </b-link>
              </template>
              <template v-else>
                <b-link class="thirdLayer" :to="'/' + main.slug + '/' + sub.slug + '/' + subchild.slug" :class="subchild.classes">
                  <b-card v-b-toggle="subchild.post_name" class="subchildTitle" v-html="subchild.title"></b-card>
                </b-link>
              </template>
              <b-collapse v-for="(fourthsubchild, index) in subchild.child_items" :key="index" :id="fourthsubchild.menu_item_parent">
                <b-link class="fouthLayer" :to="'/' + main.slug + '/' + sub.slug + '/' + subchild.slug + '/' + fourthsubchild.slug" :class="fourthsubchild.classes">
                  <b-card class="fourthchildTitle" v-html="fourthsubchild.title"></b-card>
                </b-link>
              </b-collapse>
            </b-collapse>
          </b-collapse>
        </div>

Thanks in advance.


Solution

  • A detailled answer is hard, because I don't know your setup and am not familliar with vue-bootstrap.

    It could look something like this in your components setup function:

    onBeforeMount(() => {
      const thirdMenu = sessionStorage.getItem("thirdMenu");
      if (thirdMenu) {
        yourVariableWhatMenuIsOpen = thirdMenu; // open your third level menu as you want
      }
    });
    
    watch(
      () => yourVariableWhatMenuIsOpen,
      () => {
        yourVariableWhatMenuIsOpen
          ? sessionStorage.setItem("key", yourVariableWhatMenuIsOpen)
          : sessionStorage.removeItem("key");
      }
    );
    

    yourVariableWhatMenuIsOpen is something you probably have initialized for your menu. Instead of a watcher you could use a reactive state.

    Hope, this helps. Maybe you have to dig a bit deeper into Vue, but it will be all fun, I promise. :)