Choose all checkboxes that have a certain identifier

Currently, I am developing a menu permission project using vue.js. Within this project, I have various submenus that are children of different menus. My objective is to automatically select all submenus under a selected menu when the user clicks on "select All". You can view the code implementation I am experimenting with here.

// Setting up a new VueJS instance
var app = new Vue({
  el: "#app",
  data: {
    menus: [
      { id: 1, menuName: "Tech 1" },
      { id: 2, menuName: "Tech 2" },
      { id: 3, menuName: "Tech 3" }
    ],
    selectedAllSubMenu:[],
    selectedMenu: [],
    selectedSubMenu: [],
    submenus: [
      { id: 1, menuId: 1, subMenuName: "architecture" },
      { id: 2, menuId: 1, subMenuName: "Electrical" },
      { id: 3, menuId: 1, subMenuName: "Electronics" },
      { id: 4, menuId: 2, subMenuName: "IEM" },
      { id: 5, menuId: 3, subMenuName: "CIVIL" }
    ]
  },
  computed: {
    isUserInPreviousUsers() {
      return this.previousUsers.indexOf(this.userId) >= 0;
    },
    filteredProduct: function () {
      const app = this,
        menu = app.selectedMenu;

      if (menu.includes("0")) {
        return app.submenus;
      } else {
        return app.submenus.filter(function (item) {
          return menu.indexOf(item.menuId) >= 0;
        });
      }
    }
  },
  methods: {
    selectAllSubMenu(event) {
  for (let i = 0; i < this.submenus.length; i++) {
    if (event.target.checked) {
      if (this.submenus[i].menuId == event.target.value) {
        this.selectedSubMenu.push(this.submenus[i].id);
      }
    } else {
      if (this.submenus[i].menuId == event.target.value) {
      var index = this.selectedSubMenu.indexOf(event.target.value);
      this.selectedSubMenu.splice(index, 1);
      }
    }
  }
},
    }
});
<!-- Adding the library to the page -->
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5422213114667a667a6479363120357a65">[email protected]</a>/dist/vue.js"></script>

<!-- App -->
<div id="app">
  <h4>By clicking on any menu, you can expand its submenus. To select all submenus of the chosen menu, click on "select All"</h4>
  <table class="table">
    <thead>
      <tr>
        <th>Menu</th>
        <th>Submenu</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(menu,index) in menus" :key="menu.id">
        <td>
          <label>
            <input type="checkbox" :value="menu.id" v-model="selectedMenu" />{{ menu.menuName }}
          </label>
        </td>
        <td v-if="selectedMenu.length != 0">
          <ul>
             <label >
                                  <input
                                    type="checkbox"
                                    :value="menu.id"
                                    v-model="selectedAllSubMenu"
                                    @change="selectAllSubMenu"
                                  />
                                 Select all
                                </label>
            <li v-for="submenu in filteredProduct" :key="submenu.id" v-if="menu.id == submenu.menuId">

              <input type="checkbox" :value="submenu.id" v-model="selectedSubMenu" />
              <label>{{ submenu.subMenuName }} </label>

            </li>
          </ul>
        </td>
              </tr>
    </tbody>
  </table>

</div>

As part of my project, each menu contains specific submenus. When a submenu is selected and then "select all" is clicked, all the submenus get selected. However, an issue arises when "select all" is unchecked as previously selected submenus remain selected. How can I address this challenge?

Answer №1

Consider using the code snippet below:

// Initialize new VueJS instance
var app = new Vue({
  el: "#app",
  data(){
    return {
      menus: [{ id: 1, menuName: "Tech 1" }, { id: 2, menuName: "Tech 2" }, { id: 3, menuName: "Tech 3" }],
      selectedMenu: [],
      selectedSubMenu: [],
      selectedAllSubMenu: [],
      submenus: [{ id: 1, menuId: 1, subMenuName: "architecture" }, { id: 2, menuId: 1, subMenuName: "Electrical" }, { id: 3, menuId: 1, subMenuName: "Electronics" }, { id: 4, menuId: 2, subMenuName: "IEM" }, { id: 5, menuId: 3, subMenuName: "CIVIL" }]
    }
  },
  computed: {
    isUserInPreviousUsers() {
      return this.previousUsers.indexOf(this.userId) >= 0;
    },
  },
  methods: {
    filteredProduct (id) {
      return this.submenus.filter(s => s.menuId === id)
    },
    selectSubMenu(id) {
      if (this.selectedSubMenu.filter(s => s.menuId === id).length === this.submenus.filter(s => s.menuId === id).length) {
        this.selectedAllSubMenu.push(id)
      } else {
        this.selectedAllSubMenu = this.selectedAllSubMenu.filter(s => s !== id)
      }
    },
    selectAllSubMenu(id){ 
      const checked = this.selectedAllSubMenu.some(s => s === id)
      if (this.selectedSubMenu.filter(s => s.menuId === id).length === this.submenus.filter(s => s.menuId === id).length && !checked) {
        this.selectedSubMenu = this.selectedSubMenu.filter(s => s.menuId !== id)
      } else if (checked) {
         this.selectedSubMenu = [... new Set([...this.selectedSubMenu].concat(this.submenus.filter(s => s.menuId === id)))]
      }
    },
  }
});
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a9dfdccce99b879b879984cbccddc88798">[email protected]</a>/dist/vue.js"></script>
<div id="app">
  <table class="table">
    <thead>
      <tr>
        <th>Menu</th>
        <th>Submenu</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(menu,index) in menus" :key="menu.id">
        <td>
          <label>
            <input type="checkbox" :value="menu" v-model="selectedMenu" />{{ menu.menuName }}
          </label>
        </td>
        <td v-if="selectedMenu.filter(s => filteredProduct(menu.id).some(i => i.menuId === s.id)).length">
          <ul >
             <label >
              <input
                type="checkbox"
                :value="menu.id"
                v-model="selectedAllSubMenu"
                @change="selectAllSubMenu(menu.id)"
              />
             Select all
            </label>
            <li v-for="submenu in filteredProduct(menu.id)" :key="submenu.id">
              <input type="checkbox" :value="submenu" v-model="selectedSubMenu" @change="selectSubMenu(menu.id)" />
              <label>{{ submenu.subMenuName }} </label>
            </li>
          </ul>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Answer №2

Spending an hour on the task led me to discover the root cause and come up with a solution :

The issue in the code was identified in the selectAllSubMenu method, where splicing of elements was not effectively removing duplicate values from an array. To address this, I made a small adjustment by filtering the selectedSubMenu based on submenu ids of the selected menu.

selectAllSubMenu(event) {
  if (event.target.checked) {
    for (let i = 0; i < this.submenus.length; i++) {
      if (this.submenus[i].menuId == event.target.value) {
        this.selectedSubMenu.push(this.submenus[i].id);
      }
    }
  } else {
    const filteredMenu = this.submenus.filter(obj => obj.menuId == event.target.value).map(({id}) => id);
    this.selectedSubMenu = this.selectedSubMenu.filter(el => filteredMenu.indexOf(el) === -1);
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Avoid loading the page when the browser's back button is pressed with vue-router

In my application, I have a "Home" page as well as a "Success" page. On the Success page, there is a button that, when clicked, redirects to a URL like https://google.com, using window.location.href='https://google.com'. Currently, I am able to ...

"Transitioning seamlessly from one element to another in the script

How can I transition from one function to another function in a script element? How do I transfer the field validator value to the second function? <script> $('#card_number').validateCreditCard(function(result) { if ...

Utilizing Online Resources for Texturing in Three.js

Struggling with adding textures in Three.js. I've encountered issues using local images in Chrome due to security concerns, so I'm interested in applying web images instead. Is there a method to attach an image from a URL to a Three.js mesh? ...

What is the best way to create a button that can cycle through various divs?

Suppose I want to create a scroll button that can navigate through multiple div elements. Here is an example code snippet: <div id="1"></div> <div id="2"></div> <div id="3"></div> <div id="4"></div> <div ...

ngMaterial flex layout not functioning properly

I can't seem to figure out why ngMaterial is not laying out my simple hello world app in a row. Despite checking the console for errors, I still can't see what I am doing wrong. I expected the content below to be displayed horizontally instead of ...

Can someone explain to me how this AngularJS factory example functions? I have some uncertainty

As a beginner in AngularJS, I am currently studying it through a tutorial and have some questions regarding the use of the factory in Angular. From what I understand, a factory is a pattern that creates objects on request. In the example provided, we see ...

Using Vue Js, I utilized Axios to make a call within a function, receiving and storing the retrieved data into an array

While working inside the function shown in the screenshot, I am encountering an issue when trying to access the data retrieved from the backend using axios.get. After exiting the axios block, the values of the array appear as undefined when I attempt to pr ...

When deployed, Angular 14 and Bootsrap 5 are functioning properly on a local environment but encountering issues on an online

My Angular application (version 14.2.0) is integrated with bootstrap (version 5.2.3). Upon building and deploying the application on a local IIS server, everything displays correctly as shown in the image below: https://i.sstatic.net/pLDs6.jpg However, w ...

Jest test encountering an issue where FileReader, File, and TextDecoder are not defined

While I have primarily used Jasmine for tests in the past, I am now experimenting with Jest. However, I have encountered an issue where classes like FileReader, File, and TextDecoder are not defined in my tests. How can I incorporate these classes with t ...

list of key combinations in a ul element

I programmed a list of world states in PHP using an unordered list (<ul>): $WORLD_STATES = array( "France", "Germany", "Greece", "Greenland", "United Kingdom", "United States", "Uruguay" ...

Error: Attempting to assign a value to the 'firstData' property of an object that is undefined

I am encountering two identical errors in my service. Below are the details of my service and controller: Service code snippet: getData: function (dataRecievedCallback, schemeid, userid) { //Average JSON api averageData = functi ...

Changing the position of an image can vary across different devices when using HTML5 Canvas

I am facing an issue with positioning a bomb image on a background city image in my project. The canvas width and height are set based on specific variables, which is causing the bomb image position to change on larger mobile screens or when zooming in. I ...

Adding a collection to an array in JavaScript

In my dynamic inputs, I am collecting a list of data like the following: FirstNames : Person1 FN, Person2 FN, Person3 FN, ... LastNames : Person1 LN, Person2 LN, Person3 LN, ... To retrieve these values, I use input names as shown below: var Fir ...

The sidebar in tailwind css is not displaying a scrollbar as expected

I'm currently working on a project to create a WhatsApp clone using Tailwind CSS in ReactJS. However, I've encountered an issue with the contacts list where it's not showing the scrollbar and instead overflowing the content, leading to the w ...

Auto language-switch on page load

Wondering if using jQuery is the best approach to create a single French page on my predominantly English website. I want it to work across multiple browsers on pageload, currently using HTML replace. jQuery(function($) { $("body").children().each(funct ...

Arrays passed as query parameters to Next.js router.query may result in the value being

When trying to pass objects from an array to another page using router.query, individual objects like router.query.title work as expected. However, when attempting to pass arrays such as router.query.reviews, it returns something like reviews: ['&apos ...

The Azure pipeline configured for a Vue application is experiencing issues with rendering the webpage

I've been working on deploying my Vue app, hosted in an Azure repository, to an Azure app service using the provided pipeline by Azure. The deployment process goes smoothly with no errors, yet when I access the URL of my Azure app service, I encounter ...

An issue has been detected by Zone.js where the ZoneAwarePromise `(window|global).Promise` has been unexpectedly replaced

I have recently integrated the Angular2 quickstart code into my existing webpack setup, but I seem to be facing an issue where something is interfering with the promise from zone.js, resulting in an error. Based on my research on Stack Overflow, it appears ...

typescript unconventional syntax for object types

As I was going through the TypeScript handbook, I stumbled upon this example: interface Shape { color: string; } interface Square extends Shape { sideLength: number; } var square = <Square>{}; square.color = "blue"; square.sideLength = 10; ...

After triggering an action, I am eager to make a selection from the store

To accomplish my task, I must first select from the store and verify if there is no data available. If no data is found, I need to dispatch an action and then re-select from the store once again. Here is the code snippet that I am currently using: t ...