7

I'm starting my journey with Vue.js, and stumbled upon some problem. I wanted to create a simple sidebar with dropdown menu, and already got this:

new Vue({
  el: '#app',
  data() {
    return {
      openedItems: {},
      selectedSub: '',
      userMenu: false,
      items: [{
          icon: './src/assets/img/icons/dashboard.svg',
          text: 'Element 1',
          path: '#1'
        },
        {
          icon: './src/assets/img/icons/orders.svg',
          text: 'Element 2',
          path: '#2'
        },
        {
          icon: './src/assets/img/icons/products.svg',
          text: 'NestedElement',
          path: '',
          children: [{
              icon: 'now-ui-icons files_paper',
              text: 'Nested 1 ',
              path: '/products'
            },
            {
              icon: 'now-ui-icons files_paper',
              text: 'Nested 2',
              path: '/categories'
            },
            {
              icon: 'now-ui-icons location_bookmark',
              text: 'Nested 3',
              path: '/attribute-sets'
            },
            {
              icon: 'now-ui-icons files_box',
              text: 'Nested 4',
              path: '/variant-groups'
            },
            {
              icon: 'now-ui-icons shopping_box',
              text: 'Nested 5',
              path: '/vendors'
            },
            {
              icon: 'now-ui-icons business_chart-bar-32',
              text: 'Nested 6',
              path: '/vat-rates'
            },
          ],
        },
        {
          icon: './src/assets/img/icons/clients.svg',
          text: 'Element 4',
          path: '#3'
        },
        {
          icon: './src/assets/img/icons/marketing.svg',
          text: 'Element 5',
          path: '#4'
        },
        {
          icon: './src/assets/img/icons/reports.svg',
          text: 'Element 6',
          path: '#5'
        },
        {
          icon: './src/assets/img/icons/settings.svg',
          text: 'Element 7',
          path: '#6'
        },
        {
          icon: './src/assets/img/icons/integrations.svg',
          text: 'Element 8',
          path: '#7'
        },

      ],
    }

  },

  methods: {
    collapseItem(index, item) {

      if (item.children != null) {
        this.openedItems[index] = !this.openedItems[index]
        this.$forceUpdate()
      }

    }
  }
})
body {
  background-color: #F6F7FB;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

a {
  color: white;
  text-decoration: none;
}

ul li {
  list-style-type: none;
}

#sidebar {
  background: linear-gradient(#2595ec, #64DD17);
  top: 0;
  left: 0;
  width: 275px;
  height: 1000px;
  position: absolute;
  z-index: -1;
  color: #FFFFFF;
  font-size: 14px;
  display: grid;
  grid-template-columns: 45px 155px 30px 45px;
  grid-template-areas: ". items . ";
  font-weight: bold;
}

.sidebar-items {
  padding-top: 100px;
  grid-area: items;
  margin-left: -40px;
  display: flex;
  flex-direction: column;
}

.item {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  padding-bottom: 10px;
}

#item-icon {
  width: 25px;
  height: auto;
  filter: invert(100%);
  padding-top: 9px;
  padding-right: 15px;
  grid-area: item-icon;
  float: left;
}

.item-name {
  grid-area: item-name;
  position: static;
  float: left;
}

.child-items {
  padding-top: 50px;
  font-size: 12px;
}

.child-item {
  padding-bottom: 15px;
  white-space: nowrap
}

.slide-fade-enter-active {
  transition: all .8s ease;
}

.slide-fade-leave-active {
  transition: all .3s cubic-bezier(0.5, 1.0, 0.8, 1.0);
}

.slide-fade-enter,
.slide-fade-leave-to {
  transform: translateY(-10px);
  opacity: 0;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
  <div id="sidebar">
    <ul class="sidebar-items">
      <li v-for="(item,index) in items" @click="collapseItem(index, item)" class="item">
        <router-link :to="item.path">
          <!-- <img :src="item.icon" id="item-icon"> -->
          <p class="item-name">{{item.text}}</p>

          <transition name="slide-fade">
            <ul class="child-items" v-if="openedItems[index]">
              <li class="child-item" v-for="child in item.children">
                <router-link :to="child.path">
                  {{child.text}}
                </router-link>
              </li>
            </ul>
          </transition>
        </router-link>
      </li>
    </ul>
  </div>
</div>

My problem here is that when I click on a nested elements child, the element closes and it's supposed to stay open. Any ideas how I could achieve that? I'm pretty sure I would have to change my approach on this, but at this point nothing comes to my mind.

Here's jsfiddle also: https://jsfiddle.net/myeh0mvo/14/

2 Answers 2

8

You need to add a @click.stop on your nested elements to stop the event propagation:

<router-link :to="child.path" @click.stop>
   {{child.text}}
</router-link>

Here is the updated JSFiddle: https://jsfiddle.net/myeh0mvo/23/

You can learn more about event modifiers on this page of the documentation: https://v2.vuejs.org/v2/guide/events.html#Event-Modifiers

Sign up to request clarification or add additional context in comments.

Comments

0

I was looking for exactly this, so thank you. However, I found that for me, I needed to add @click.stop.prevent to the nested elements.

Not sure why, but it was a random try and it keeps the menu open when the child element is clicked.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.