RKS
RKS

Reputation: 1410

Validation of Checkbox list in Template form(not Reactive forms) Angular 2

How can I do the validation of checking that at least 1 checkbox is selected from a checkbox list in Angular 2 template forms?

HTML code.

   <div class="form-control" style="max-height: 300px; overflow: auto">
        <div *ngFor="let item of items" class="checkbox">
            <label for="{{item.id}}">
                <input type="checkbox" value="{{item.id}}" required id="{{item.id}}" [(ngModel)]="item.isSelected" />
                <span class="text-body">{{item.name}}</span>
            </label>
        </div>
   </div>
   <div *ngIf="!isAtleastOneItemSelected()" class="alert alert-error">
        Select at least one item
   </div>

Component Code.

public isAtleastOneItemSelected() {
    const selectedItems = this.items.filter((item) => item.isSelected);
    if (selectedItems.length > 0) {
        return true;
    } else {
        return false;
    }
}

I have already checked the Reactive form way of doing this here. So, wanted to check how we can do this in Template Forms. Using the code that I have pasted above, things are working fine but on page load the error message is showing up as there is no check for dirty or touched there. I was stuck with this issue.

Any help on this would be appreciated.

Thanks.

Upvotes: 4

Views: 3160

Answers (2)

AVJT82
AVJT82

Reputation: 73377

Well I see two viable options here. I would go with the first, just because I would suggest to avoid any methods in the template, because you cannot restrict when and how often the method will be fired. Especially if you have a view with many ways to modify data in some way, the method will be fired even though it has nothing to do with the actual checkboxes. Look for a sample later.

So what I would do, is to change the

*ngIf="!isAtleastOneItemSelected()"

to check a variable instead:

*ngIf="nonChecked"

and have some type of change event when checkboxes are clicked, which fires some method, e.g:

check() {
  const selectedItems = this.items.filter((item) => item.isSelected === true);
  if (selectedItems.length > 0) {
     this.nonChecked = false;
  } else {
     this.nonChecked = true;
  }    
}

Now this will only be fired when ever the checkboxes are touched.


The other option I see, if you want to keep the similar setup, is to wrap the checkboxes in a formgroup and watch for when the group is touched and only then show the error message if there's no item checked. So you would wrap the checkboxes inside a group:

<div ngModelGroup="checkboxes">
  <!-- .... -->
</div>

and then you can do:

<div *ngIf="!isAtleastOneItemSelected() && f.controls?.checkboxes?.dirty">
  Select at least one item
</div>  

where f is the name of the form. But as earlier mentioned, this will fire on change detections and doing anything else in the DOM. Here is a sample of this solution, and where we only have one other field in DOM (see the console), so if you have lots of stuff going on, I'd suggest the first solution :) But either way, both works!

http://plnkr.co/edit/VuLNR8H3lasFoK7mRDlG?p=preview

Upvotes: 1

sancelot
sancelot

Reputation: 2063

Look at this, you will need to adapt:

<div *ngFor="let item of items; let i = index" class="checkbox"> 
        <label for="{{item.id}}">
            <input type="checkbox" value="{{item.id}}" required id="{{item.id}}" [(ngModel)]="item.isSelected" (change)="CheckBoxChanged(i,$event)"/>
            <span class="text-body">{{item.name}}</span>
        </label>
 </div>
   <div [hidden]="isAtleastOneItemSelected()" class="alert alert-error">
        Select at least one item
   </div>

put your check logic here...:

CheckBoxChanged(i,e){
    console.log(i);
    if (e.target.checked)
       console.log("checked");
    else 
       console.log("unchecked");
}

Upvotes: 0

Related Questions