CPK_2011
CPK_2011

Reputation: 1150

mat-checkbox change event not returning checked value in onSubscriberCheck function

I am using mat-checkbox of Angular Material and I have added a change event as below...

<div *ngFor="let subscriber of selectedSubscribers">
    <mat-checkbox (change)="onSubscriberCheck(subscriber)">
        {{ subscriber.name }}
    </mat-checkbox>
</div>

The onSubscriberCheck(subscriber) code is as below...

onSubscriberCheck(subscriber: Subscribers) {
    if (subscriber.checked) {
        //Do Something
    } else {
        //Do Something else
    }
}

Here on click of the checkbox, I am always getting the value of subscriber.checked as undefined.

My expected result is, if it is checked, then the value should be true instead of undefined. If it is unchecked, then the value should be false instead of undefined.

EDIT

If I add [(ngModel)], then the checkbox list does not work properly. Let me add the complete scenario...

I have 2 sets of checkbox lists. One is a set of checked checkbox list and below that one I will be showing a set of unchecked checkbox list. So, in onSubscriberCheck(subscriber) event, the Do Something is as below..

onSubscriberCheck(subscriber: Subscribers) {
    if (subscriber.checked) {
        this.selectedSubscribers.push(subscriber);
        this.unselectedSubscribers = this.unselectedSubscribers.filter(s => s.id !== subscriber.id);
    } else {
        this.unselectedSubscribers.push(subscriber);
        this.selectedSubscribers = this.selectedSubscribers.filter(s => s.id !== subscriber.id);
    }
}

So, here both [(ngModel)] = subscriber.checked and change event fires. How to overcome this one?

I just want to show the checked checkboxes at the top of the list and unchecked checkboxes at the bottom. So, on change event, I am rearranging the arrays selectedSubscribers and unselectedSubscribers

SECOND EDIT

I am using the below functions to populate the Subscribers

GetSelectedSubscribers() {
    this.selectedSubscribers = this.allSubscribers
      .filter(subscriber => subscriber.id !== undefined) 
      .map(subscriber => ({ id: subscriber.id, name: subscriber.name, checked: subscriber.checked }));
}

GetUnselectedSubscribers(){
    this.unselectedSubscriberGroupItems = this.subtractListIds(this.allSubscriberGroupItems, this.selectedSubscriberGroupItems);
    this.unselectedSubscribers = this.unselectedSubscriberGroupItems.lists.map(subscriber => ({ id: subscriber.id, name: subscriber.name, checked: subscriber.checked }));
}

Here the last checkbox name is coming as empty but has checkbox control. Don't know why it is not displaying..

Please clarify...

Upvotes: 1

Views: 2699

Answers (2)

Eliseo
Eliseo

Reputation: 58039

The argument of the method changeof the mat-checkBox is a MatCheckboxChange, see the API. Futhermore, you get this argument using $event

You can choose use the two binding [(ngModel)] or use the event (change) and the property [checked].

As Naren explain using ngModel, I want to show another approach. The idea is use an unique array and sort the array.

<div *ngFor="let subscribe of subscribers;let index=index">
    <mat-checkbox [checked]="subscribe.checked" 
                  (change)="subscribe.checked=$event.checked;sort()">
        {{ subscribe.name }}
    </mat-checkbox>
</div>

where

  subscribers: any = [
    { checked: false, name: 'test'},
    { checked: false, name: 'test2'},
    ...
  ]

And the function sort

  sort()
  {
    setTimeout(()=>{
      this.subscribers.sort((a:any,b:any)=>
            (a.checked && b.checked) ||(!a.checked && !b.checked)?
                           a.name>b.name?1:-1:
             a.checked?-1:
             1)
    })
  }

It's necessary the setTimeout, else the mat-checkbox mark the position where we are.

a stackblitz

Upvotes: 1

Naren Murali
Naren Murali

Reputation: 58334

You need to bind the checked variable to an ngModel please find below working example!

html

SELECTED
<div *ngFor="let subscriber of selectedSubscribers">
  <mat-checkbox
    [(ngModel)]="subscriber.checked"
    (ngModelChange)="onSubscriberCheck()"
  >
    {{ subscriber.name }}
  </mat-checkbox>
</div>
<br /><br />
UNSELECTED
<div *ngFor="let subscriber of unselectedSubscribers; trackBy: trackByFn">
  <mat-checkbox
    [(ngModel)]="subscriber.checked"
    (ngModelChange)="onSubscriberCheck()"
  >
    {{ subscriber.name }}
  </mat-checkbox>
</div>

ts

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatRadioModule } from '@angular/material/radio';
import { FormsModule } from '@angular/forms';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatCardModule } from '@angular/material/card';

/**
 * @title Configurable checkbox
 */
@Component({
  selector: 'checkbox-configurable-example',
  templateUrl: 'checkbox-configurable-example.html',
  styleUrls: ['checkbox-configurable-example.css'],
  standalone: true,
  imports: [
    MatCardModule,
    MatCheckboxModule,
    FormsModule,
    MatRadioModule,
    CommonModule,
  ],
})
export class CheckboxConfigurableExample {
  allSubscribers: any = [
    {
      checked: false,
      name: 'test',
    },
    {
      checked: false,
      name: 'test2',
    },
  ];
  unselectedSubscribers: any = [];
  selectedSubscribers: any = [];

  ngOnInit() {
    this.unselectedSubscribers = this.allSubscribers;
  }

  onSubscriberCheck() {
    this.selectedSubscribers = this.allSubscribers.filter(
      (x: any) => x.checked
    );
    this.unselectedSubscribers = this.allSubscribers.filter(
      (x: any) => !x.checked
    );
  }

  trackByFn(i: number, val: any) {
    return val.name;
  }
}

stackblitz

Upvotes: 1

Related Questions