Home > Software design >  How do I resolve all the dropdown menu opening at the same time in Vue.js?
How do I resolve all the dropdown menu opening at the same time in Vue.js?

Time:11-06

I have created an application which is used to get your tasks in form of todo lists. These lists can be edited and deleted. I wanted to add a dropdown menu in the list which helps us to access the list update or delete page. But the Problem is whenever I click the dropdown Icon the dropdown menus of all the lists are opening at the same time. Can anybody help me resolve this issue. I am attaching my Vue.JS code here and my screenshot of the dashboard in which the lists are present.

DashboardView.vue:

<template>
  <div >
    <Navbar  />
    <h1 >Welcome {{ name }}</h1>
    <div >
      <div  v-if="len_list === 0">
        <h2 >There are No lists here tap to add</h2>
      </div>
      <div  v-else>
        <div  v-for="(item, index) in items" :key="index">
          <div >
            <div >
              <div >
                <h1 >{{ item.list_name }}</h1>
                <div >
                  <button @click="toggleMenu">
                    <fa  icon="fa-solid fa-arrow-down" />
                  </button>
                  <div v-if="showMenu" >
                    <div
                      
                      v-for="(item, index) in links_list"
                      :key="index"
                      @click="itemClicked"
                    >
                      {{ item.title }}
                    </div>
                  </div>
                </div>
                <!-- V-menu -->
                <!--menu ends-->
              </div>
            </div>
            <div >
              <div  v-if="item.no_of_tasks === 0">
                <h3>There are no tasks added yet</h3>
              </div>
              <div  v-else>
                <h4>Here are your tasks</h4>
              </div>
            </div>
            <div >
              Number of Completed tasks: {{ item.no_completed }}/{{
                item.no_of_tasks
              }}
            </div>
          </div>
        </div>
      </div>
      <router-link :to="`/createList/${id}`">
        <fa  icon="fa-solid fa-plus" />
      </router-link>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

import Navbar from '../components/NavBar.vue';
export default {
  name: 'DashboardView',
  data() {
    return {
      name: localStorage['name'],
      len_list: 0,
      items: [],
      id: localStorage['id'],
      links_list: [{ title: 'Click Me' }, { title: 'Click Me' }],
      showMenu: false,
    };
  },
  methods: {
    getTrackers() {
      const path = 'http://localhost:5000/dashboard/'   localStorage['id'];
      axios
        .get(path)
        .then((res) => {
          this.items = res.data.list;
          console.log(res.data.list);
          this.len_list = res.data.list[0]['len_list'];
        })

        .catch((err) => {
          console.log(err);
        });

      console.log(this.items);
    },
    toggleMenu() {
      this.showMenu = !this.showMenu;
    },
    itemClicked() {
      this.toggleMenu();
    },
  },
  components: {
    Navbar,
  },
  created() {
    this.getTrackers();
  },
};
</script>

<style>
.dashboard {
  width: 100%;
  min-height: 100vh;
  color: #ffd700;
  background-image: url('../assets/wood-texture.jpg');
  overflow-x: auto;
  overflow-y: hidden;
}
.dashboard__welcome {
  margin-top: 2rem;
  font-weight: 600;
}
.plus__icon {
  margin-left: 58rem;
  width: 32px;
  height: 32px;
  margin-top: 1rem;
  color: #ffd700;
  padding: 1rem;
  border: 1px solid #ffd700;
  border-radius: 50%;
}
.no_lists {
  text-align: center;
  margin-top: 15rem;
}

.navbar__dash {
  background-color: black;
  color: white;
  max-width: inherit;
}
.has__lists {
  display: flex;
}
.list {
  padding: 10rem;
  border: 1px solid #ffd700;
  border-radius: 2rem;
  width: 20%;
  margin-left: 1rem;
  margin-top: 5rem;
  padding-bottom: 0px;
}
.title {
  background: #ffd700;
  color: black;
  width: 320px;
  text-align: center;
  margin-left: -10rem;
  margin-top: -10rem;
  height: 100px;
  border-top-left-radius: 2rem;
  border-top-right-radius: 2rem;
}
.footer {
  margin-top: 10rem;
  background: #ffd700;
  color: black;
  width: 320px;
  margin-left: -10rem;
  margin-top: 0.01rem;
  margin-bottom: 0rem;
  height: 100px;
  border-bottom-left-radius: 2rem;
  border-bottom-right-radius: 2rem;
  text-align: center;
}
.body {
  background-color: white;
  width: 320px;
  color: grey;
  margin-left: -10rem;
  text-align: center;
  height: 10rem;
}
.list_name {
  margin-top: 0.6rem;
  padding: 2px;
  font-weight: 600;
  font-size: 20px;
  border-top-left-radius: 1rem;
  border-bottom-left-radius: 1rem;
}
.list__icon {
  width: 20px;
  height: 20px;
}
.title__options {
  display: flex;
  justify-content: center;
}
.dropdown_icon {
  padding: 0.2rem;
  color: #ffd700;
  background: black;
  margin-top: 15px;
  transition: var(--transition);
  border-radius: 2rem;
}
.dropdown_icon:hover {
  background: white;
  color: black;
  height: 20px;
}
.menu {
  background: white;
  padding-left: 2rem;
  padding-right: 2rem;
  border-radius: 1rem;
}
</style>

Screenshots:

Dashboard Dashboard with dropdown button clicked

CodePudding user response:

In order for each of the lists to act independently, you should isolate the relevant code. The most logical thing would be to isolate the part of the code that displays the items. The logic being isolated, each item would have its own showMenu variable, allowing only one of them to be acted upon at a time.

Component Parent

<template>
  <div >
    <Navbar  />
    <h1 >Welcome {{ name }}</h1>
    <div >
      <div  v-if="len_list === 0">
        <h2 >There are No lists here tap to add</h2>
      </div>
      <div  v-else>
        <div  v-for="(item, index) in items" :key="index">
            <Items :item="item"/> //Call Component Items
        </div>
      </div>
      <router-link :to="`/createList/${id}`">
        <fa  icon="fa-solid fa-plus" />
      </router-link>
    </div>
  </div>
</template>

<script>
import axios from "axios";

import Navbar from "../components/NavBar.vue";
export default {
  name: "DashboardView",
  data() {
    return {
      name: localStorage["name"],
      len_list: 0,
      items: [],
      id: localStorage["id"],
      links_list: [{ title: "Click Me" }, { title: "Click Me" }],
    };
  },
  methods: {
    getTrackers() {
      const path = "http://localhost:5000/dashboard/"   localStorage["id"];
      axios
        .get(path)
        .then((res) => {
          this.items = res.data.list;
          console.log(res.data.list);
          this.len_list = res.data.list[0]["len_list"];
        })

        .catch((err) => {
          console.log(err);
        });

      console.log(this.items);
    }
  },
  components: {
    Navbar, Items
  },
  created() {
    this.getTrackers();
  },
};
</script>

Component Child (Items)

<template>
<div>
  <div >
    <div >
      <div >
        <h1 >{{ item.list_name }}</h1>
        <div >
          <button @click="toggleMenu">
            <fa  icon="fa-solid fa-arrow-down" />
          </button>
          <div v-if="showMenu" >
            <div
              
              v-for="(item, index) in links_list"
              :key="index"
              @click="itemClicked"
            >
              {{ item.title }}
            </div>
          </div>
        </div>
      </div>
    </div>
    <div >
      <div  v-if="item.no_of_tasks === 0">
        <h3>There are no tasks added yet</h3>
      </div>
      <div  v-else>
        <h4>Here are your tasks</h4>
      </div>
    </div>
    <div >
      Number of Completed tasks: {{ item.no_completed }}/{{ item.no_of_tasks }}
    </div>
  </div>
</div>
</template>

<script>
export default {

  props: {
    item: Item,
  },

  data() {
    return {
      showMenu: false,
    };
  },
  
  methods: {
    toggleMenu() {
      this.showMenu = !this.showMenu;
    },
    itemClicked() {
      this.toggleMenu();
    },
  },
};
</script>
  • Related