0

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.

Louis A.
  • 1
  • 3

2 Answers2

0

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.

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • WOW. Is this one way data binding? then what is the difference between `[ngModel]="product.selected"` and `[(ngModel)]="{{product.selected}}"?` – Ramesh Rajendran Sep 05 '17 at 09:49
  • It changes nothing. In fact my "select" method was doing the other way binding (by reverting the concerned product selection). Since then I kind of found some hints. I have a workaround, by setting a timeout on the service method (which is pretty terrible). So maybe angular has the time to handle first the model change, and the service change after ? – Louis A. Sep 05 '17 at 10:04
0

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" >

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Adawg
  • 278
  • 2
  • 13