Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 checkbox state not updated even if model changed

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.

like image 488
Gyuzal R Avatar asked Oct 26 '17 07:10

Gyuzal R


2 Answers

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

like image 78
raviteja.kvns Avatar answered Nov 02 '22 09:11

raviteja.kvns


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);
        });
    }
}
like image 26
Llorenç Pujol Ferriol Avatar answered Nov 02 '22 10:11

Llorenç Pujol Ferriol