Search code examples
angulartypescriptngmodel

ngModel does not update value on change


I have ngModel, inside ngFor loop:

<div *ngFor="let comment of comments">
   <div *ngFor="let answer of toArray(comment.answers); let j = index; trackBy: trackByIndex;">
      <textarea id="editAnswer[j]" name="editAnswer[j]" [(ngModel)]="answer.text">

      {{ answer.text }}
   </div>
</div>

In my component i have two functions for index iterate and convert object to array:

  trackByIndex(index: number, obj: any): any {
    return index;
  }

  toArray(answers: object) {
    return Object.keys(answers).map(key => ({
      key,
      ...answers[key]
    }))
  }

But when i change text what was binded in textarea, ngModel does not change.

Stackblitz example: https://stackblitz.com/edit/angular-z6xatv


Solution

  • The toArray method appears to be creating a copy of the original comments.answers.text values. When the text property is modified in the input elements, the change does not affect the original data (the console in this stackblitz shows that the values are not shared).

    If you simplify toArray so that it returns a simple array of the answers, the code works (see this stackblitz). The items in the array share the same text references as the original data.

    comments = [
      {
        text: 'dsddsdsd', answers: {
          FszW: { text: 'answer 1' },
          dsSce: { text: 'answer 2' }
        }
      }
    ]
    
    toArray(answers: object) {
      return Object.keys(answers).map(key => answers[key]);
    }
    

    If you need an access to the key, you can use this version of toArray:

    toArray(answers: object) {
      return Object.keys(answers).map(key => {
        return { key: key, value: answers[key] };
      });
    }
    

    with the following template markup:

    <textarea name="answer_{{j}}" [(ngModel)]="answer.value.text"></textarea>
    {{ answer.key }}: {{ answer.value.text }}
    

    As a side note, I suggest setting the name property in the template with one of the following syntaxes:

    name="answer_{{j}}"
    [name]="'answer_' + j"