Checkbox state not reflecting ngModel value in Angular 2

1.9k views Asked by At

So my problem is that I have a checkbox for which the state not reflects its ngModel value. Let me explain the architecture : I have a Service which manage a list of products, and a component that is supposed to display this list and let the user select or unselect any product. If the user unselect a product and there are no selected products anymore, I try to reselect them all. But when I do this, the checkbox that triggers the event is not updated (graphically, because its ngModel is), while all others checkboxes are updated correctly.

So here is the service (I use BehaviourSubject so that my component can listen its changes) :

@Injectable()
export class ProductService {
    private productsSubject: BehaviorSubject<Array<{name: string, selected: boolean}>>
    public products = this.productsSubject.asObservable();

    constructor() {
        this.productsSubject.next([
            {name: 'Product 1', selected: true},
            {name: 'Product 2', selected: true},
            {name: 'Product 3', selected: true}
        ]);
    }

    public select(name: string) {
        // In this method I change "selected" for the corresponding product.
        // if no product is selected, I select them all.
    }
}

Here is the component view :

<li *ngFor="let product of ProductService.products | async">
      {{product.name}}{{product.selected}}
      <input type="checkbox" [(ngModel)]="product.selected" (ngModelChange)="ProductService.select(product.name)">
</li>

For the compoenent it self, it does nothing particular except injecting ProductService.

At the end, when I run the app, everything works correctly, when I check and uncheck checkboxes, the model is updated, and the checkbox state also. Except in one situation

Start :

Product 1 -> selected: true + checkbox ticked
Product 2 -> selected: false + checkbox not-ticked
Product 3 -> selected: false + checkbox not-ticked

I uncheck the first product, the "select" method does its jobs of reselecting all products, and I have this :

Product 1 -> selected: true + checkbox **NOT-TICKED**
Product 2 -> selected: true + checkbox ticked,
Product 3 -> selected: true + checkbox ticked

Do you know why the checkbox that triggers the event doesn't get updated graphically ?

Thank you by advance for your help.

2

There are 2 answers

2
Jeremy Thille On

Currently you're using one-way data binding :

[ngModel]="product.selected"

Use two-way data binding :

[(ngModel)]="product.selected"

so the changes get reflected in your UI.

0
Adawg On

To use ngModel you need to have a name attribute, in addition if you are using a bootstrap styled checkbox it actually hides the checkbox, in that case you need for="id" on your label. Typically I set <input type="checkbox" name="something" id="something" >