htmlarraysangularfor-loopngmodel

Display only shows last value of an Angular for loop even though devtools HTML has correct values


I'm using a for loop to display different sections of my blog for editing purposes.

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Route, ParamMap } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Content } from '../model/Content';

@Component({
  selector: 'app-edit-story',
  templateUrl: './edit-story.component.html',
  styleUrls: ['./edit-story.component.css']
})
export class EditStoryComponent implements OnInit {

  story: any;
  storyName: any;
  isMe: boolean= false;

  constructor(private route: ActivatedRoute, private httpClient: HttpClient) { }

  ngOnInit(): void {
    if (localStorage.getItem('userId')=='62e348924d52fa7420bb96bc') {
      this.isMe = true;
    }

    this.storyName = this.route.snapshot.paramMap.get('storyName');
    var url = 'http://localhost:3002/api/stories/' + this.storyName;
    this.httpClient.get(url).subscribe(data => {
      this.story = data;
      console.log(this.story);
    })
  }

  editStory() {

  }

  addContent() {
    var newContent = new Content("", "", "");
    this.story.contents.push(newContent);
  }
}
<div *ngIf="isMe">
  <form #editStoryForm = "ngForm" (ngSubmit)="editStory()" class="addStory">
    
      <label for="title">Title</label>
      <input name="title" type="text" [(ngModel)]="story.title" req/>
      <label for="subtitle">Subtitle</label>
      <input type="subtitle" [(ngModel)]="story.subtitle" name="subtitle" req>
      <label for="name">Name</label>
      <input type="name" [(ngModel)]="story.name" name="name" req>
      <button (click)="addContent()">Add Content</button>
      <div *ngFor="let content of story.contents">
        <label for="type">Type</label>
          <select name='type' [(ngModel)]="content.type" value="{{content.type}}">
            <option value=''>Pick one</option>
            <option value='text' selected="selected">text</option>
            <option value='image'>image</option>
          </select>
        <label for="text">Text</label>
        <textarea name="text" cols="50" rows="7" [(ngModel)]="content.text">{{content.text}}</textarea>
        <label for="url">url</label>
        <input name="url" type="text" value="{{content.url}}" [(ngModel)]="content.url">
      </div>
      <button type="submit">Edit</button>
  </form>
</div>

In the console.log to display the story, the contents array appears fine. Even when I open devtools and check the HTML elements, the values are correct.

devtools showing the innerHTML values are all different

enter image description here

However the page itself has all these element with only the values of the last array item.

contarary to the devtools html, the page displays the last array values over and over

enter image description here

please help.


Solution

  • You are using template-driven forms. The problem is in the way you're registering the child controls using ngModel and the name attribute.

    In your ngFor you do:

    <textarea name="text" [(ngModel)]="content.text">{{content.text}}</textarea>
    

    So basically you're assigning the same name to all children.

    Instead, you should do something like this:

    <div *ngFor="let content of story.contents; index as i">
       <!-- other elements -->
       <label for="text">Text</label>
       <textarea name="{{ 'text-' + i }}" [(ngModel)]="content.text">
          {{ content.text }}
       </textarea>
       <!-- other elements -->
    </div>
    

    You may also find the last section of this article helpful.

    Cheers.