6

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.

AT82
  • 71,416
  • 24
  • 140
  • 167
Gyuzal
  • 1,581
  • 10
  • 52
  • 99
  • What part isn't working. This code `this.permissions.forEach(filter => filter.checked = true);` looks very weird. You use filter, but ignore the result, as filter criteria you are using an assignment. The `setTimeout` also looks redundant. – Günter Zöchbauer Oct 30 '17 at 05:02

3 Answers3

6

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

Komal12
  • 3,340
  • 4
  • 16
  • 25
  • Got it, the problem was in this line ` value="{{perm.permission_id}}" `, I needed to remove it. thanks anyways! – Gyuzal Oct 31 '17 at 10:47
  • 1
    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. – Natta Wang Jun 12 '19 at 09:35
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);
        });
    }
}
  • 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 Oct 31 '17 at 04:12
0

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

abid Hussain
  • 43
  • 10