Angular 4 checkbox state not updated even if model changed

10,182

Solution 1

This works. It will always keep things in sync using 2-way data binding.

<input type="checkbox" 
name="check-box-{{filter.text}}"
[(ngModel)]="filter.selected"
attr.id="check-box-{{filter.text}}">

If you need to trigger some function on change, use the change event.

<input type="checkbox" 
name="check-box-{{filter.text}}"
[(ngModel)]="filter.selected"'
(change)="myCustomFun()"
attr.id="check-box-{{filter.text}}">

Updated the same in your plunk from your workaround link

Solution 2

I think that the error here is because you are always 'mutating the array'. When angular does the change detection run, it sees no changes, and the ngFor is not updated. Try this code, look that the only thing I am doing is making a copy of the array before I mutate it.

getPermissions(role: Role): void {
this.permissions = [];
this.userService.getPermissions().then(perms => {            
    if (role != null) {
        this.permissions = perms;
        for (let rp of role.permissions) {          
            let index = this.permissions.indexOf(this.permissions.find(p => p.permission_id == rp.permission_id));
            if (index >= 0) {  
                 this.permissions = this.permissions.slice(0) // copy the array.
                 this.permissions[index].checked = true;
                //this.onSelectFilter(true, this.permissions[index]); not sure if this should be called
            }      
        }
        console.log("before selected perms on update");
        console.log(this.permissions);
    }
    else {
        this.permissions = perms;
    }

}).catch(this.handleError);
}

   onSelectFilter(selected: boolean, filter: Permission) {
    filter.checked = selected;
    if (this.permissions.every(filter => !filter.checked)) {
        setTimeout(() => {
            this.permissions = this.permissions.slice(0) // copy the array.
            this.permissions.forEach(filter => filter.checked = true);
        });
    }
}

Solution 3

Please use [(ngModel)] with boolean variable because check boxes are two way data binding

Share:
10,182
Gyuzal R
Author by

Gyuzal R

Updated on June 22, 2022

Comments

  • Gyuzal R
    Gyuzal R about 2 years

    I know this issue with is still open, but according to this workaround Angular 2 - Checkbox not kept in sync it should work as expected, however I still struggle to make it work with my case.

    I have the list of permissions which are granted to a role. When the user wants to update a role, I display the form with editable role name and the list of it's permissions as checkbox list. Now, I need to make some of the list items checked, if the role already has a permission from the list.

    My form:

    <tr *ngFor ="let perm of permissions, let i = index">
            <td>
                <label>
                <input type="checkbox" 
                        name="check-box-{{perm.permission_alias}}"                                            
                        value="{{perm.permission_id}}"  
                        (ngModel)="perm.checked"
                        (ngModelChange)="onSelectFilter($event,perm)"
                        attr.id="check-box-{{perm.permission_alias}}"
                        /> 
                {{perm.permission_alias}}
                </label>                                
            </td>
        </tr>
    

    My component:

    getPermissions(role: Role): void {
        this.permissions = [];
        this.userService.getPermissions().then(perms => {            
            if (role != null) {
                this.permissions = perms;
                for (let rp of role.permissions) {          
                    let index = this.permissions.indexOf(this.permissions.find(p => p.permission_id == rp.permission_id));
                    if (index >= 0) {  
                         this.permissions[index].checked = true;
                        //this.onSelectFilter(true, this.permissions[index]); not sure if this should be called
                    }      
                }
                console.log("before selected perms on update");
                console.log(this.permissions);
            }
            else {
                this.permissions = perms;
            }
    
        }).catch(this.handleError);
    }
    
       onSelectFilter(selected: boolean, filter: Permission) {
            filter.checked = selected;
            if (this.permissions.every(filter => !filter.checked)) {
                setTimeout(() => {
                    this.permissions.forEach(filter => filter.checked = true);
                });
            }
        }
    

    I have no idea why this isn't working, I have no items checked in the list. I'd appreciate any help.

  • Gyuzal R
    Gyuzal R over 6 years
    Thanks for reply, I've tried to apply your changes but it didn't help. I think the model is ok, because if I display {{perm.checked}} in the list label, I can see that some of the elements are true and others are false. The problem is in updating checkbox state.
  • Gyuzal R
    Gyuzal R over 6 years
    Got it, the problem was in this line ` value="{{perm.permission_id}}" `, I needed to remove it. thanks anyways!
  • Natta Wang
    Natta Wang about 5 years
    I love this solution, but what I has tried gave me the disappoint result. So solution is that create a Promise and setTimeout for 200 ms to check the items that were checked after action performed.
  • Sylens
    Sylens almost 5 years
    Some explanation as to why this qualifies as the solution would be good.