I am working on a menu permission project using vue.js. I have some submenus which are child of different menus. I want to select all submenus of selected menu if I click on "select All". this is the code I am trying--
// 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);
}
}
}
},
}
});
<!-- Include the library in the page -->
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<!-- App -->
<div id="app">
<h4>Click on any menu. Then the submenus will appear. I want to select all submenus of selected menu if I click on "select All"</h4>
<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>
Here are some menus. every menu has some submenus. Now if I click on any submenu & then click on select all, all the submenus get selected. But the problem is, If I uncheck "select all" the previously selected submenus still got selected. How Do I solve this?
CodePudding user response:
Try like following snippet:
// 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/[email protected]/dist/vue.js"></script>
<div id="app">
<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>
CodePudding user response:
After spending an hour on this requirement to find the root cause, I am here with a solution :
In your selectAllSubMenu
method, splicing of the elements was not working properly as it was not able to remove the duplicate values from an array. Hence, I just changed a approach a bit. I am 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);
}
}