66

My problem is really simple: I have a list of checkboxes like this:

<div class="form-group">
    <label for="options">Options :</label>
    <label *ngFor="#option of options" class="form-control">
        <input type="checkbox" name="options" value="option" /> {{option}}
    </label>
</div>

And I would like to send an array of the selected options, something like: [option1, option5, option8] if options 1, 5 and 8 are selected. This array is part of a JSON that I would like to send via an HTTP PUT request.

Thanks for your help!

12 Answers 12

117

Here's a simple way using ngModel (final Angular 2)

<!-- my.component.html -->

<div class="form-group">
    <label for="options">Options:</label>
    <div *ngFor="let option of options">
        <label>
            <input type="checkbox"
                   name="options"
                   value="{{option.value}}"
                   [(ngModel)]="option.checked"/>
            {{option.name}}
        </label>
    </div>
</div>

// my.component.ts

@Component({ moduleId:module.id, templateUrl:'my.component.html'})

export class MyComponent {
  options = [
    {name:'OptionA', value:'1', checked:true},
    {name:'OptionB', value:'2', checked:false},
    {name:'OptionC', value:'3', checked:true}
  ]

  get selectedOptions() { // right now: ['1','3']
    return this.options
              .filter(opt => opt.checked)
              .map(opt => opt.value)
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

How would you access the selected options? I'm not familiar with the get function declaration
just leave off the () (ie. this.selectedOptions instead of this.selectedOptions())
how the selectedOptions event gets fired as there is no event in html
doesn't getter selectedOptions get called on every user action (click, keypress, etc.) to be avaluated. If the array of options is large it might cause performance issues.
35

I have find a solution thanks to Gunter! Here is my whole code if it could help anyone:

<div class="form-group">
            <label for="options">Options :</label>
            <div *ngFor="#option of options; #i = index">
                <label>
                    <input type="checkbox"
                           name="options"
                           value="{{option}}"
                           [checked]="options.indexOf(option) >= 0"
                           (change)="updateCheckedOptions(option, $event)"/>
                    {{option}}
                </label>
            </div>
        </div>

Here are the 3 objects I'm using:

options = ['OptionA', 'OptionB', 'OptionC'];
optionsMap = {
        OptionA: false,
        OptionB: false,
        OptionC: false,
};
optionsChecked = [];

And there are 3 useful methods:

1. To initiate optionsMap:

initOptionsMap() {
    for (var x = 0; x<this.order.options.length; x++) {
        this.optionsMap[this.options[x]] = true;
    }
}

2. to update the optionsMap:

updateCheckedOptions(option, event) {
   this.optionsMap[option] = event.target.checked;
}

3. to convert optionsMap into optionsChecked and store it in options before sending the POST request:

updateOptions() {
    for(var x in this.optionsMap) {
        if(this.optionsMap[x]) {
            this.optionsChecked.push(x);
        }
    }
    this.options = this.optionsChecked;
    this.optionsChecked = [];
}

5 Comments

i think according to your solution its must to know the all values of array of checkboxes is't it ?
see my answer. hope it may help you. where if you dont know the length of array or even don't know about the all entries, code run without error. try Plnkr given
this shouldnt be that difficult, why doesnt the ngModel just take care of it :(
I believe my answer here: stackoverflow.com/a/41027266/4496240, would be better suited for this as it's requires much less work and is done in a more "angular" centric way. It's also updated for the new forms library.
@YannickMorel how did you write the post request for this? coz i have the same issue and i did the same as you wrote but i dont know how to handle the post request to send it as an array
30

create a list like :-

this.xyzlist = [
  {
    id: 1,
    value: 'option1'
  },
  {
    id: 2,
    value: 'option2'
  }
];

Html :-

<div class="checkbox" *ngFor="let list of xyzlist">
            <label>
              <input formControlName="interestSectors" type="checkbox" value="{{list.id}}" (change)="onCheckboxChange(list,$event)">{{list.value}}</label>
          </div>

then in it's component ts :-

onCheckboxChange(option, event) {
     if(event.target.checked) {
       this.checkedList.push(option.id);
     } else {
     for(var i=0 ; i < this.xyzlist.length; i++) {
       if(this.checkedList[i] == option.id) {
         this.checkedList.splice(i,1);
      }
    }
  }
  console.log(this.checkedList);
}

1 Comment

Stuck for many hours figuring out the issue. This solution worked like charm!
6
<input type="checkbox" name="options" value="option" (change)="updateChecked(option, $event)" /> 

export class MyComponent {
  checked: boolean[] = [];
  updateChecked(option, event) {
    this.checked[option]=event; // or `event.target.value` not sure what this event looks like
  }
}

5 Comments

this.checked return [undefined: Event] after checked or uncheck why ?
I don't know what this.checked should refer to and at what time. Can you create a Plunker?
Sorry, I only looked at the source of the question, not of my answer ;-p. option is not defined. If you add a field with this name it's no longer undefined (see plnkr.co/edit/MsJDlEimeeeV4Wk3NNk5?p=preview). In the question option is the value variable of *ngFor="#option of xxx". It just needs to exist in the scope.
sorry but still confused in your plnkr how to get list of checked checkbxoes ?
An example plnkr.co/edit/N9NXBYcwhon6ITr8RP5y?p=preview There are different ways to store the checked state (with the option, or store the index instead of the value, ...)
6

I have encountered the same problem and now I have an answer I like more (may be you too). I have bounded each checkbox to an array index.

First I defined an Object like this:

SelectionStatusOfMutants: any = {};

Then the checkboxes are like this:

<input *ngFor="let Mutant of Mutants" type="checkbox"
[(ngModel)]="SelectionStatusOfMutants[Mutant.Id]" [value]="Mutant.Id" />

As you know objects in JS are arrays with arbitrary indices. So the result are being fetched so simple:

Count selected ones like this:

let count = 0;
    Object.keys(SelectionStatusOfMutants).forEach((item, index) => {
        if (SelectionStatusOfMutants[item])
            count++;
    });

And similar to that fetch selected ones like this:

let selecteds = Object.keys(SelectionStatusOfMutants).filter((item, index) => {
        return SelectionStatusOfMutants[item];
    });

You see?! Very simple very beautiful. TG.

2 Comments

Thank you so much man, I was doing some funny things. You saved me in this late night :-)
@ConductedClever can you create an stackblitz for this?
6

Here's a solution without map, 'checked' properties and FormControl.

app.component.html:

<div *ngFor="let item of options">
  <input type="checkbox" 
  (change)="onChange($event.target.checked, item)"
  [checked]="checked(item)"
>
  {{item}}
</div>

app.component.ts:

  options = ["1", "2", "3", "4", "5"]
  selected = ["1", "2", "5"]

  // check if the item are selected
  checked(item){
    if(this.selected.indexOf(item) != -1){
      return true;
    }
  }

  // when checkbox change, add/remove the item from the array
  onChange(checked, item){
    if(checked){
    this.selected.push(item);
    } else {
      this.selected.splice(this.selected.indexOf(item), 1)
    }
  }

DEMO

Comments

4

I hope this would help someone who has the same problem.

templet.html

<form [formGroup] = "myForm" (ngSubmit) = "confirmFlights(myForm.value)">
  <ng-template ngFor [ngForOf]="flightList" let-flight let-i="index" >
     <input type="checkbox" [value]="flight.id" formControlName="flightid"
         (change)="flightids[i]=[$event.target.checked,$event.target.getAttribute('value')]" >
  </ng-template>
</form>

component.ts

flightids array will have another arrays like this [ [ true, 'id_1'], [ false, 'id_2'], [ true, 'id_3']...] here true means user checked it, false means user checked then unchecked it. The items that user have never checked will not be inserted to the array.

flightids = []; 
confirmFlights(value){  
    //console.log(this.flightids);

    let confirmList = [];
    this.flightids.forEach(id => {
      if(id[0]) // here, true means that user checked the item 
        confirmList.push(this.flightList.find(x => x.id === id[1]));
    });
    //console.log(confirmList);

}

Comments

4

In Angular 2+ to 9 using Typescript

Source Link

enter image description here

we can use an object to bind multiple Checkbox

  checkboxesDataList = [
    {
      id: 'C001',
      label: 'Photography',
      isChecked: true
    },
    {
      id: 'C002',
      label: 'Writing',
      isChecked: true
    },
    {
      id: 'C003',
      label: 'Painting',
      isChecked: true
    },
    {
      id: 'C004',
      label: 'Knitting',
      isChecked: false
    },
    {
      id: 'C004',
      label: 'Dancing',
      isChecked: false
    },
    {
      id: 'C005',
      label: 'Gardening',
      isChecked: true
    },
    {
      id: 'C006',
      label: 'Drawing',
      isChecked: true
    },
    {
      id: 'C007',
      label: 'Gyming',
      isChecked: false
    },
    {
      id: 'C008',
      label: 'Cooking',
      isChecked: true
    },
    {
      id: 'C009',
      label: 'Scrapbooking',
      isChecked: false
    },
    {
      id: 'C010',
      label: 'Origami',
      isChecked: false
    }
  ]

In HTML Template use

  <ul class="checkbox-items">
    <li *ngFor="let item of checkboxesDataList">
      <input type="checkbox" [(ngModel)]="item.isChecked" (change)="changeSelection()">{{item.label}}
    </li>
  </ul>

To get selected checkboxes, add the following method in class

  // Selected item
  fetchSelectedItems() {
    this.selectedItemsList = this.checkboxesDataList.filter((value, index) => {
      return value.isChecked
    });
  }

  // IDs of selected item
  fetchCheckedIDs() {
    this.checkedIDs = []
    this.checkboxesDataList.forEach((value, index) => {
      if (value.isChecked) {
        this.checkedIDs.push(value.id);
      }
    });
  }

Comments

3
  1. I have just simplified little bit for those whose are using list of value Object. XYZ.Comonent.html

    <div class="form-group">
            <label for="options">Options :</label>
            <div *ngFor="let option of xyzlist">
                <label>
                    <input type="checkbox"
                           name="options"
                           value="{{option.Id}}"
    
                           (change)="onClicked(option, $event)"/>
                    {{option.Id}}-- {{option.checked}}
                </label>
            </div>
            <button type="submit">Submit</button>
        </div> 
    

    ** XYZ.Component.ts**.

  2. create a list -- xyzlist.

  3. assign values, I am passing values from Java in this list.
  4. Values are Int-Id, boolean -checked (Can Pass in Component.ts).
  5. Now to get value in Componenet.ts.

    xyzlist;//Just created a list
    onClicked(option, event) {
        console.log("event  " + this.xyzlist.length);
        console.log("event  checked" + event.target.checked);
        console.log("event  checked" + event.target.value);
        for (var i = 0; i < this.xyzlist.length; i++) {
            console.log("test --- " + this.xyzlist[i].Id;
            if (this.xyzlist[i].Id == event.target.value) {
                this.xyzlist[i].checked = event.target.checked;
            }
            console.log("after update of checkbox" + this.xyzlist[i].checked);
    
        }
    

Comments

2

I just faced this issue, and decided to make everything work with as less variables as i can, to keep workspace clean. Here is example of my code

<input type="checkbox" (change)="changeModel($event, modelArr, option.value)" [checked]="modelArr.includes(option.value)" />

Method, which called on change is pushing value in model, or removing it.

public changeModel(ev, list, val) {
  if (ev.target.checked) {
    list.push(val);
  } else {
    let i = list.indexOf(val);
    list.splice(i, 1);
  }
}

Comments

2

@ccwasden solution above works for me with a small change, each checkbox must have a unique name otherwise binding wont works

<div class="form-group">
    <label for="options">Options:</label>
    <div *ngFor="let option of options; let i = index">
        <label>
            <input type="checkbox"
                   name="options_{{i}}"
                   value="{{option.value}}"
                   [(ngModel)]="option.checked"/>
            {{option.name}}
        </label>
    </div>
</div>

// my.component.ts

@Component({ moduleId:module.id, templateUrl:'my.component.html'})

export class MyComponent {
  options = [
    {name:'OptionA', value:'1', checked:true},
    {name:'OptionB', value:'2', checked:false},
    {name:'OptionC', value:'3', checked:true}
  ]

  get selectedOptions() { // right now: ['1','3']
    return this.options
              .filter(opt => opt.checked)
              .map(opt => opt.value)
  }
}

and also make sur to import FormsModule in your main module

import { FormsModule } from '@angular/forms';


imports: [
    FormsModule
  ],

Comments

2

Since I spent a long time solving a similar problem, I'm answering to share my experience. My problem was the same, to know, getting many checkboxes value after a specified event has been triggered. I tried a lot of solutions but for me the sexiest is using ViewChildren.

import { ViewChildren, QueryList } from '@angular/core';

/** Get handle on cmp tags in the template */
@ViewChildren('cmp') components: QueryList<any>;

ngAfterViewInit(){
    // print array of CustomComponent objects
    console.log(this.components.toArray());
}

Found here: https://stackoverflow.com/a/40165639/4775727

Potential other solutions for ref, there are a lot of similar topic, none of them purpose this solution...:

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.