How to check all checkboxes on selecting one in Vuejs? - javascript

isCheckAll: false,
methods: {
checkAll: function(){
this.isCheckAll = !this.isCheckAll;
},
updateCheckall: function(){
this.isCheckAll = true;
},
<div class="checkbox-alignment-form-filter">
<input type="checkbox" id="three" class="vh-product" #click='checkAll()' v-model='isCheckAll' />
<label class="productlist-specific" for="three"
> : 2011</label
>
</div>
<div class="checkbox-alignment-form-filter2">
<input type="checkbox" id="four" class="vh-product" #change='updateCheckall()'/>
<label class="productlist-specific" for="four">E0A</label>
</div>
<div class="checkbox-alignment-form-filter3">
<input type="checkbox" id="five" class="vh-product" #change='updateCheckall()'/>
<label class="productlist-specific" for="five">BR</label>
</div>
<div class="checkbox-alignment-form-filter4">
<input type="checkbox" id="six" class="vh-product" #change='updateCheckall()'/>
<label class="productlist-specific" for="six">E11350A</label>
</div>
<div class="checkbox-alignment-form-filter5">
<input type="checkbox" id="seven" class="vh-product" #change='updateCheckall()'>
<label class="productlist-specific" for="seven">E0BR</label>
</div>
How to select check and uncheck all checkboxes, on selecting one checkbox.
I don't know what stopping me to proceed, For every checkbox taken one #click and sub checkboxes also taken one #click. and then in js i am toggling that condition to check and uncheck.

I think you had some problems with your logic, so let me explain this for you:
You need to have a v-model on all of them, to be able to control state updates (whenever a user clicks something it needs to be updated).
You don't need to have two methods for all of this, you can have just one to enable all of the checkboxes. The rest can be handled by v-model.
The following code will enable/disable all of the checkboxes by clicking the first one, and if you click the other ones, it'll just enable/disable that particular checkbox.
<div id="app">
<input type="checkbox" v-model="checkboxes[0]" v-on:click="checkAll()">
<input type="checkbox" v-model="checkboxes[1]">
<input type="checkbox" v-model="checkboxes[2]">
<input type="checkbox" v-model="checkboxes[3]">
</div>
const app = new Vue({
el: "#app",
data: {
// control the state of checkboxes
checkboxes: [false, false, false, false]
},
methods: {
checkAll: function(){
for(let i = 1; i < this.checkboxes.length; i++){
// update all of the checkboxes to the value of the first one.
this.checkboxes[i] = !this.checkboxes[0];
}
}
}
})

your problem was your data handling.
i made you a playable example in CodeSandbox.
with this you are able to control the main checkbox bidirectional.
if all sub checkboxes are true the main checkbox will be set to true as well.
<template>
<div id="app">
<div class="checkbox-group">
<div class="main-checkbox">
<input
type="checkbox"
:name="checkboxes.main.label"
v-model="checkboxes.main.value"
#input="toggleAllCheckboxes()"
/>
<label :for="checkboxes.main.label">{{ checkboxes.main.label }}</label>
</div>
<div
class="sub-checkbox"
v-for="(checkbox, index) in checkboxes.sub"
:key="index"
>
<input
type="checkbox"
:name="checkbox.label"
v-model="checkbox.value"
/>
<label :for="checkbox.label">{{ checkbox.label }}</label>
</div>
</div>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
checkboxes: {
main: {
value: false,
label: ":2011",
},
sub: [
{
value: false,
label: "E0A",
},
{
value: false,
label: "BR",
},
{
value: false,
label: "E11350A",
},
{
value: false,
label: "E0BR",
},
],
},
}),
computed: {
mainIsChecked: function () {
return this.checkboxes.main.value;
},
allSubsAreChecked: function () {
return this.checkboxes.sub.every((checkbox) => checkbox.value);
},
},
watch: {
allSubsAreChecked: function () {
this.checkboxes.main.value = this.allSubsAreChecked;
},
},
methods: {
toggleAllCheckboxes() {
for (const checkbox of this.checkboxes.sub) {
checkbox.value = !this.mainIsChecked;
}
},
},
};
</script>

If you are working with multiple checkboxes, you should bind them to the same Array using v-model according to the Vue docs. https://v2.vuejs.org/v2/guide/forms.html#Checkbox
In your case, this means that you should have one array managing all the checkboxes except the one which controls selecting them all, that should be handled differently.
Each of those checkboxes should have a value binding as well, telling Vue which value they represent in the array.
You could also store all the possible checkbox values in an array which would help you reducing code duplication in your template.
You can render all 4 checkboxes which can be separately checked using a v-for loop, and manage them with the same v-model.
The checkbox controlling the "all checked" state should be managed with a different v-model. When that checkboxes value changes, we should check/uncheck all the other checkboxes, which can be done easily using a watcher.
Here's an example using this approach https://codesandbox.io/s/inspiring-dijkstra-fzkmn?file=/src/App.vue
export default {
name: "App",
data: () => ({
selectedValues: [],
allChecked: false,
}),
computed: {
isAllChecked() {
return false;
},
allCheckboxOptions() {
return [
{
label: "E0A",
value: "four",
},
{
label: "BR",
value: "five",
},
{
label: "E11350A",
value: "six",
},
{
label: "E0BR",
value: "seven",
},
];
},
},
methods: {
checkAll() {
this.selectedValues = this.allCheckboxOptions.map(
(option) => option.value
);
},
checkNone() {
this.selectedValues = [];
},
},
watch: {
allChecked(isAllChecked) {
if (isAllChecked) {
this.checkAll();
} else {
this.checkNone();
}
},
},
};
<template>
<div id="app">
<div class="checkbox-alignment-form-filter">
<input
type="checkbox"
id="three"
class="vh-product"
v-model="allChecked"
/>
<label class="productlist-specific" for="three"> : 2011</label>
</div>
<template v-for="(checkboxOption, index) in allCheckboxOptions">
<div
:key="checkboxOption.value"
:class="`checkbox-alignment-form-filter${index + 2}`"
>
<input
type="checkbox"
:id="checkboxOption.value"
:value="checkboxOption.value"
v-model="selectedValues"
class="vh-product"
/>
<label class="productlist-specific" for="four">
{{ checkboxOption.label }}
</label>
</div>
</template>
checked: {{ selectedValues }}
</div>
</template>

Related

vuejs filter array with checkboxes

I am using vuejs and I want to filter my array using checkboxes. I have tried using v-model to filter an array based on three options. If the name contains "Truck", "Van", or "Tx". I am not having any luck. Also i don't want to use a computed method.
new Vue({
el: "#app",
data: {
selection:[],
todos: [
{
"Name": "CHS_200_TL_L62_TRUCK"
},
{
"Name": "VHS_600_TL_L62_TRUCK"
},
{
"Name": "VHS_116_TL_L62_TRUCK"
},
{
"Name": "VHS_146_TX_L62_VAN"
},
{
"Name": "VHS_613_TL_L62_TRUCK"
},
{
"Name":"JE_50_OL_T62_TRUCK"
},
{
"Name": "VHS_T10_OL_L62_TRUCK"
},
{
"Name":"JE_59_OL_T62_TRUCK"
},
{
"Name": "LEE_100_TL_L62_TRUCK"
}
],
mounted:function(){
},
methods: {
}
},
methods: {
fin: function(todo){
todo
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<input type="checkbox" id="vehicle1" name="vehicle1" value="Truck" v-model="checkedNames"> Truck<br>
<input type="checkbox" id="vehicle2" name="vehicle2" value="Van" v-model="checkedNames"> Van<br>
<input type="checkbox" id="vehicle1" name="vehicle1" value="TX" v-model="checkedNames">
<label for="vehicle1"> TX</label><br>
<li v-for="todo in todos">
{{todo.Name}}
</li>
</div>
If you don't want to use computed property , you can use watcher:
new Vue({
el: "#app",
data() {
return {
selection:[],
filtered: [],
todos: [{"Name": "CHS_200_TL_L62_TRUCK"}, {"Name": "VHS_600_TL_L62_TRUCK"}, {"Name": "VHS_116_TL_L62_TRUCK"}, {"Name": "VHS_146_TX_L62_VAN"}, {"Name": "VHS_613_TL_L62_TRUCK"}, {"Name":"JE_50_OL_T62_TRUCK"}, {"Name": "VHS_T10_OL_L62_TRUCK"}, {"Name":"JE_59_OL_T62_TRUCK"}, {"Name": "LEE_100_TL_L62_TRUCK"}],
}
},
watch: {
selection: {
handler() {
this.filtered= []
if (this.selection.length) {
this.todos.forEach(t => {
this.selection.forEach(s => {
if (t.Name.split('_').find(w => w === s.toUpperCase())) {
if (!this.filtered.find(f => f.Name === t.Name)) this.filtered = [ ...this.filtered, t]
}
})
})
} else {
this.filtered = [...this.todos]
}
},
deep: true,
immediate: true
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<input type="checkbox" id="vehicle1" name="vehicle1" value="Truck" v-model="selection"> Truck<br>
<input type="checkbox" id="vehicle2" name="vehicle2" value="Van" v-model="selection"> Van<br>
<input type="checkbox" id="vehicle1" name="vehicle1" value="TX" v-model="selection"> TX<br>
<ul>
<li v-for="todo in filtered">
{{todo.Name}}
</li>
</ul>
</div>
First of all, you have typos in your code :
In the script you've defined selection:[] but in the template you have used checkedNames which is undefined
To respond on your question, you should use a computed value that searchs for todos that contains selection
In your script define a computed value named todosFiltered
...
computed: {
todosFiltered() {
return this.todos.filter((todo) => {
return this.selection.every((select) => todo.Name.toLowerCase().includes(select.toLowerCase()));
});
},
},
....
In your template use todosFiltered instead of todos
<template>
<div id="app">
<h2>Todos:</h2>
<input
type="checkbox"
id="vehicle1"
name="vehicle1"
value="Truck"
v-model="selection"
/>
Truck<br />
<input
type="checkbox"
id="vehicle2"
name="vehicle2"
value="Van"
v-model="selection"
/>
Van<br />
<input
type="checkbox"
id="vehicle1"
name="vehicle1"
value="TX"
v-model="selection"
/>
<label for="vehicle1"> TX</label><br />
<li v-for="todo in todosFiltered">
{{ todo.Name }}
</li>
</div>
</template>

Angular Reactive form set Multiselect Checkbox values

The form is having 1 textbox , 1 radio button and 1 multi select Checkbox The HTML template is like below
<form *ngIf="notificationSettings | async; else loading"
[formGroup]="notificationForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<div *ngFor="let option of notifyBackAlertOptions; let i=index">
<input type="checkbox" class="form-check-input" [value]="option.value" formControlName="notifyBackOptions" />
<label> {{option.name}} </label>
</div>
</div>
<div class="form-group">
<label for="notifyBackEmail">Where shall we send the alerts?</label>
<input type="email" class="form-control" formControlName="notifyBackEmail">
</div>
<div class="form-check" *ngFor="let option of discontinuedAlertOptions;">
<label>
<input formControlName="discontinuedOption" class="form-check-input"
type="radio"
name="discontinuedOption"
[value]="option.value" />
{{option.name}}
</label>
</div>
<div class="float-left">
<button class="btn btn-primary mr-1">Update</button>
</div>
</form>
<ng-template #loading>
Loading ---...
</ng-template>
The component is like below
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
export class NotifcationsComponent implements OnInit {
notificationSettings: Observable<NotificationSetting>;
notificationForm: FormGroup;
submitted = false;
notifyBackAlertOptions = [
{ name: 'Option 1', value: '1' },
{ name: 'Option 2', value: '2' },
{ name: 'Option 3', value: '3' },
{ name: 'Option 4', value: '4' }
];
discontinuedAlertOptions = [
{ name: 'Yes for any', value: '1' },
{name: 'Yes for all', value: '2' },
{ name: 'No', value: '3' }
];
constructor(private formBuilder: FormBuilder,private userService: UserService) { }
ngOnInit() {
this.getCurrentSettings();
this.notificationForm = this.formBuilder.group({
notifyBackEmail: [''],
discontinuedOption: [''],
notifyBackOptions: new FormArray([]),
});
}
getCurrentSettings(): void {
this.notificationSettings = this.userService
.getUserNotificationSettings()
.pipe(tap(data => {
console.log("GET")
this.notificationForm = this.formBuilder.group({
notifyBackEmail: new FormControl(data.notifyBackEmail),
discontinuedOption: new FormControl(data.discontinuedOption),
notifyBackOptions: new FormControl(data.notifyBackOptions)
});
console.log(this.notificationForm) //I can see the values are mapping correctly against notificationForm. Checkbox property ie notifyBackOptions value is coming as ["1", "2"] at this stage
}
));
//This code maps / sets the values of textbox and radio buttons correctly at page loading based on response from API. But not setting values for multiselect checkbox correctly.
//I can see all checkbox values are coming as selected. IN this case 4 checkbox values are selected
//How to set only the notifyBackOptions checkbox selected values marked as checked
}
// convenience getter for easy access to form fields in HTML page
get f() { return this.notificationForm.controls; }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.notificationForm.invalid) {
return;
}
console.log(this.notificationForm.value);
}
}
The HTML is rendering correctly and capturing the values at form submission . At load time of the component i have to read the values from API endpoint and prefill form based on current settings
The JSON response from API endpoint is like below
{
notifyBackEmail: "email#email-domain.in"
notifyBackOptions: ["1","2"]
discontinuedOption: "1"
}
The existing implementation of getCurrentSettings() is setting values of radio and textbox correctly but not checkbox.
At present this is setting all values of checkbox as selected. How can i set the Checkbox values as selected based on response form API with help of model binding
Since you are handling with array of values, you need to create array of formControl instead of single formControl. Try something like this:
Try this:
notificationForm: FormGroup;
getCurrentSettings(): void {
this.notificationSettings = this.userService
.getUserNotificationSettings()
.pipe(
tap(data => {
const notifyBackOptions = data.notifyBackOptions;
const notificationControls = this.notifyBackAlertOptions.map(
item => new FormControl(notifyBackOptions.includes(item.value))
);
this.notificationForm = this.formBuilder.group({
notifyBackEmail: [''],
discontinuedOption: [''],
notifyBackOptions: this.formBuilder.array(notificationControls)
});
})
);
}
Then in HTML You need to add formArrayName directive to sync with FormGroup
<form [formGroup]="notificationForm" (ngSubmit)="onSubmit()">
<div class="form-group" formArrayName="notifyBackOptions">
<div *ngFor="let option of notifyBackOptionsArr.controls; let i=index">
<input [formControlName]="i" type="checkbox" class="form-check-input" />
<label> {{notifyBackAlertOptions[i].name}} </label>
</div>
</div>
<div class="form-group">
<label for="notifyBackEmail">Where shall we send the alerts?</label>
<input
type="email"
class="form-control"
formControlName="notifyBackEmail"
/>
</div>
<div class="form-check" *ngFor="let option of discontinuedAlertOptions;">
<label>
<input
formControlName="discontinuedOption"
class="form-check-input"
type="radio"
name="discontinuedOption"
[value]="option.value"
/>
{{option.name}}
</label>
</div>
<div class="float-left">
<button class="btn btn-primary mr-1">Update</button>
</div>
</form>
Working Example

How to add one to a field in my object from radio button on submit

I have this voting web app I am building, I need to take a value from when my radio button is checked for a particular cantidate and add it to my database, but for mow I am using an object has my database and I will like to add one to the vote_count of any candidate selected when the submit vote button is clicked.
<div class="container">
<div>
<form id="the-form" action="#">
<h1 class="text-center">{{Title}}</h1>
<div v-for="(candidate) in candidates" :key="candidate.topic_id">
<label>
<input type="radio" class="option-input radio" value="1" id="radio" name="example" />
{{candidate.candidate_name}}
</label>
</div>
<b-button href="#" class= "btn" variant="primary" router-link to="/votingpage">
Submit Vote</b-button>
</form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
selected: [], // Must be an array reference!
Title: 'Providence Class Captain Election',
candidates: [
// {
// Title: 'Providence Class Captain'
// },
{
candidate_name: 'Babangida',
candidate_party: 'pdp',
vote_count: 0,
vote_id:'1'
},
{
candidate_name: 'Rochas',
candidate_party: 'Anpp',
vote_count: 0,
vote_id:'2'
},
{
candidate_name: 'Ajimobi',
candidate_party: 'Apc',
vote_count: 0,
vote_id:'3'
},
{
candidate_name: 'Buhari',
candidate_party: 'Apc',
vote_count: 0,
vote_id:'4'
}
]
}
}
}
</script>

Vue dynamic v-model within v-for

I have the following fieldsets containing checkboxes:
<fieldset>
<label v-for="(count, value) in availableFilters.level"><input type="checkbox" data-filterName="level" :value="value" v-model="level" #change="(e) => handleCheckbox(e, 'level')"> {{value}} ({{count}})</label>
</fieldset>
<fieldset>
<label v-for="(count, value) in availableFilters.subject"><input type="checkbox" data-filterName="subject" :value="value" v-model="subject" #change="(e) => handleCheckbox(e, 'subject')"> {{value}} ({{count}})</label>
</fieldset>
<fieldset>
<label v-for="(count, value) in availableFilters.delivery"><input type="checkbox" data-filterName="delivery" :value="value" v-model="name" #change="(e) => handleCheckbox(e, 'delivery')"> {{value}} ({{count}})</label>
</fieldset>
Notice there's a bit of repetition here, but it works. Here's my Vue instance:
var vm = new Vue({
el: '#app',
data: {
level: [],
subject: [],
delivery: [],
availableFilters: {
level: {
"UG": 12,
"PG": 12,
}
}
},
...
I want something more like this so I don't have to repeat the same block over again:
<fieldset v-for="(filters, name) in availableFilters">
<label v-for="(count, value) in filters">
<input type="checkbox" :data-filterName="name" :value="value" v-model="name" #change="(e) => handleCheckbox(e, name, value)"> {{value}} ({{count}})
</label>
</fieldset>
However, this doesn't work and it seems that the v-model is not bound to the data property. How do I correctly pass that now? The data property name will be whatever name is.
To with situation you should put that properties (level, subject, delivery) inside an object called selected as follows :
selected: {
level: [],
subject: [],
delivery: []
}
and you should loop using v-for like :
<fieldset v-for="(filters, key,index) in availableFilters">
where the filters represents the value, key represents the key like level and ìndex represents the index such 0, using the key item we could access selected like selected[key] so we could bind the checkbox to that property easily.
Full example
new Vue({
el: '#app',
data() {
return {
selected: {
level: [],
subject: [],
delivery: []
},
availableFilters: {
level: {
"UG": 12,
"PG": 12,
},
subject: {
}
}
}
}
});
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app" class="container">
<fieldset v-for="(filters, key,index) in availableFilters">
<label v-for="(count, value) in filters">
<input type="checkbox" :data-filterName="this[filters]" :value="value" v-model="selected[key]" #change="onchange"> {{value}} ({{count}})
</label>
</fieldset>
<pre>{{selected}}</pre>
</div>

Update parent class in Vue.js

I'm a Vue.js noob and trying to figure out how to toggle a class inside a for loop for the parent of the link that is clicked.
I want to click on the "Advanced" link and then toggle a class of overlay for the section and .advanced-fields elements only in that section. I know I can add the onOff data attribute to each section but I am saving to a database and don't want to add in unnecessary data fields.
Can anyone point me in the right direction. Thanks.
Here is a simplified version of my code.
<div id="app">
<section v-bind:class="{ overlay: onOff }" v-for="section in sections">
Advanced
<div class="advanced-fields" v-bind:class="{ overlay: onOff }" v-show="onOff">
<fieldset>
<label>
ID
<input type="text" name="section[id]">
</label>
</fieldset>
<fieldset>
<label>
Class
<input type="text" name="section[css_class]">
</label>
</fieldset>
</div>
</section>
</div>
<script>
new Vue({
el: "#app",
data:{
"sections": [
{
"id": "section-1",
"css_class": ""
},
{
"id": "section-2",
"css_class": ''
}
],
"onOff": false
},
methods: {
showAdvanced: function(section) {
this.onOff = !this.onOff;
}
}
});
</script>
This answer Vue bind click that adds active class (and removes from the last one) helped me figure it out.
https://jsfiddle.net/ferne97/n1hfde94/
Here is the updated code that works properly.
<div id="app">
<section v-bind:class="{ overlay: index == isActive }" v-for="(section, index) in sections">
Advanced
<div class="advanced-fields" v-bind:class="{ overlay: index == isActive }" v-show="index == isActive">
<fieldset>
<label>
ID
<input type="text" name="section[id]" v-model="section.id">
</label>
</fieldset>
<fieldset>
<label>
Class
<input type="text" name="section[css_class]" v-model="section.css_class">
</label>
</fieldset>
</div>
</section>
<pre>{{ $data }}</pre>
</div>
<script>
new Vue({
el: "#app",
data:{
"sections": [
{
"id": "section-1",
"css_class": ""
},
{
"id": "section-2",
"css_class": ''
}
],
"isActive": null
},
methods: {
showAdvanced: function(index) {
this.isActive = this.isActive === index ? null : index
}
}
});
</script>

Categories

Resources