3

I am creating an Angular2 project and having a problem with two-way binding for a checkbox.

I have a class called listItem and List like that:

export class ListItem {
  public count: number;
  public value: string;
  public checked: boolean;

  constructor(count: number, value: string, checked: boolean) {
    this.count = count;
    this.value = value;
    this.checked = checked;
  }
}

export class MyList{
  public category: string;
  public listItem : ListItem [];

  constructor(category: string, listItem : ListItem []) {
    this.category = category;
    this.listItem = listItem ;
  }
}

and I am calling the list from Azure search which is working correctly. the problem is when I just set the value to a checkbox.

<div *ngFor="let list of myList; let listIndex = index;">
  <div *ngFor="let item of list.listItems; let itemIndex = index;">
    <input type="checkbox" [name]="list.category + item.value"
         (change)="item.checked = !item.checked"
         [ngModel]="item.checked" />
  </div
</div>

but the value is always false also onClick. I tried to use [(ngModel)] but did not work also. I also tried to make a function:

(change)="oncheck(listIndex, itemIndex)"

oncheck(listIndex: number, itemIndex: number) {
   this.myList[listIndex].listItems[itemIndex].checked =  
           !this.myList[listIndex].listItems[itemIndex].checked;
  } 

but I received this error:

Cannot assign to read-only property 'checked' of object '[object Object]'

why is that and how to fix it? thank you

Samy Sammour
  • 2,298
  • 2
  • 31
  • 66
  • Possible duplicated. Can you elaborate how [(ngModel)] behave on your case? It should work fine. https://stackoverflow.com/questions/40214655/angular-2-checkbox-two-way-data-binding – trungk18 Jun 06 '17 at 11:22
  • I add it like this: [(ngModel)]="item.checked" and I am getting always false. without any error. – Samy Sammour Jun 06 '17 at 11:44
  • Meaning even when you selected the checkbox and it is still false? – trungk18 Jun 06 '17 at 11:46
  • I tried this example but did not work also. and why am I receiving the error message when I try to make an event? – Samy Sammour Jun 06 '17 at 11:46
  • yes, the 'checked' value in the last is false as default. so no matter how much I check. the list still false when I check the debugger and after a button click all the check boxes back to false which is the default. I think one way binding works well but the set of the value is not working. maybe the error message could be the reason. but I did not understand it and know why. – Samy Sammour Jun 06 '17 at 11:49
  • Good question but I don't have your working code so I can't not answer it. Just created a simple plunker for you, normally it works like that. https://plnkr.co/edit/oiDwez?p=preview – trungk18 Jun 06 '17 at 11:49
  • this is the plnkr: https://plnkr.co/edit/PLdXtiAFGHfF7nvnvKXN it will not work correctly because I deleted the service's url and headers for security purpose. but I think it has everything you need to make it work – Samy Sammour Jun 06 '17 at 12:11
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/145993/discussion-between-trungk18-and-samy-sammour). – trungk18 Jun 06 '17 at 16:19

1 Answers1

3

You could use the material2 md-checkbox directive to create styled elements. In my opinion that is not really two-way binding, its just a combination of 1 way binding in both directions (template - data source and data source - template)

UPDATE: I created a small plnkr to reproduce your situation: http://plnkr.co/edit/cr7TokiqSaBGli7mgCBM

@Component({
  selector: 'my-app',
  template: `
    <div *ngFor="let element of elements; let i = index;">
    <span>Val: {{element}}</span>
      <input type="checkbox"
       [checked]="element" (change)="handleChange(element, i)">
    </div>
  `,
})
export class App {
  elements= [
    false,
    true,
    false,
  ]:

  handleChange(val: boolean, index: number){
    console.log("Index: "+index);
    console.log("Val:  "+val);
    this.elements[index] = !val;
  }

The elements in the list are correctly rendered, but the change events will in some cases modify the values of incorrect positions in the elements array. Ill take a furhter look later

UPDATE: refactored plnkr

Please check: http://plnkr.co/edit/Ich0g5kzSiQINZjh3VYo

I made some changes to the plnkr that u sent me.

I changed the iteration variables from const to let (considering that their values arent constant during execution of the loops).

As I mentioned before, most likely there are 2 posibilities: the classes in .ts are being transpiled in a wrong way to .js (class members are being setted as readonly by default), or there is something wrong in the way that you are manually mapping the values to class instances.

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
  • I am not allowed to add any extra library – Samy Sammour Jun 06 '17 at 11:44
  • thank you for the solution, I tried it but it did not work. the same problem. please look at the error message mentioned in the question. – Samy Sammour Jun 06 '17 at 12:15
  • I dont see the error message being triggered on the plnkr. Do you have any small test set that I could use? The error is weird, considering that the property checkd isnt defined as readonly or similar – Jota.Toledo Jun 06 '17 at 12:19
  • I guess the problem is with the set. because when I try to implement an Event as mentioned in the question I receive the error: Cannot assign to read-only property 'checked' of object '[object Object]' but why? – Samy Sammour Jun 06 '17 at 12:21
  • For some reason the objects in you array are write protected. Where are you generating/getting this collection from? – Jota.Toledo Jun 06 '17 at 12:27
  • from an azure search subscribe as json then manual casting. see the plnkr plnkr.co/edit/PLdXtiAFGHfF7nvnvKXN – Samy Sammour Jun 06 '17 at 12:33
  • there are a lot of const being defined in the source code, most likely one of them is causing the problem. Ill take a look – Jota.Toledo Jun 06 '17 at 12:37
  • can you try to manually set through an input field or similar another property in any of the elemens? for example try to set the 'value' member and tell me if you get the same error – Jota.Toledo Jun 06 '17 at 13:03
  • I tried to and I am receiving the same error for all properties also for category – Samy Sammour Jun 06 '17 at 13:06
  • did you created the project with angular cli or manually? I think that this is somehow related to the way that .ts files are being transpiled into .js files – Jota.Toledo Jun 06 '17 at 13:16
  • using angular cli – Samy Sammour Jun 06 '17 at 15:08
  • ooh thank you, I solved the problem today. It was in the way how I call the method. I was using redux and since the redux state is immutable, then I couldn't change it and it was always as read only. but when I called the service normally, the problem is solved. but your solution was right. thank you – Samy Sammour Jun 07 '17 at 09:45