James Peart
James Peart

Reputation: 1

ngFor creates new element, but does not display newly POSTed data until browser refresh

I'm new to Angular and am getting an unexpected result from my *ngFor directive.

When I click the 'add' button a new <li> element is created, but it's {{ tomato.name }} data isn't displayed until I refresh the browser:

Screenshots of when I added a 'Test2' input, and after refreshing browser:

added 'Test2'

enter image description here

after refresh

enter image description here

component.html

<div>
  <label>Tomato name:
    <input #tomatoName />
  </label>
  <button (click)="add(tomatoName.value); tomatoName.value='';">
    add
  </button>
</div>
<ul>
  <li *ngFor="let tomato of tomatos">
    <p>{{ tomato.name }}</p>
  </li>
</ul>

component.ts

import { Component, OnInit } from '@angular/core';
import { TomatoService } from '../services/tomato.service';

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

  tomatos: Tomato[];

  constructor(private tomatoService: TomatoService) { }

  ngOnInit() {
    this.getTomatos();
  }

  getTomatos(): void {
    this.tomatoService.getTomatos()
      .subscribe(tomatos => this.tomatos = tomatos)
  }

  add(name:string): void {
    if (!name) { return; }
    this.tomatoService.addTomato({name} as Tomato)
    .subscribe(tomato => this.tomatos.push(tomato));
  }

}

export interface Tomato {
  id: number;
  name: string;
  originPostCode: string;
  tastes: string;
}

service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Tomato } from '../tomatos/tomatos.component';
import { Observable, of } from '../../../node_modules/rxjs';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable({
  providedIn: 'root'
})
export class TomatoService {

  private tomatosUrl = 'https://path/tomy/api'    

  constructor(private http: HttpClient) { }

  getTomatos(): Observable<Tomato[]> {
    return this.http.get<Tomato[]>(this.tomatosUrl);
  }

  addTomato (tomato: Tomato): Observable<Tomato> {
    return this.http.post<Tomato>(this.tomatosUrl, tomato);
  }

}

Thanks in advance!

Upvotes: 0

Views: 1159

Answers (2)

Deepender Sharma
Deepender Sharma

Reputation: 490

Use tomato?.name it will work as this property does not have the value the time it is trying to bind

Upvotes: 0

coder
coder

Reputation: 8712

Import ChangeDetectorRef from @angular/core and manually run change detection after this.tomatos.push(tomato) like below:

constructor(private tomatoService: TomatoService, private ref: ChangeDetectorRef) { }

  ngOnInit() {
    this.getTomatos();
  }

  getTomatos(): void {
    this.tomatoService.getTomatos()
      .subscribe(tomatos => {
          this.tomatos = tomatos;
          this.ref.detectChanges(); 
       })
  }

  add(name:string): void {
    if (!name) { return; }
    this.tomatoService.addTomato({name} as Tomato)
    .subscribe(tomato => this.tomatos.push(tomato));
  }

Hope this will helps you!

Upvotes: 1

Related Questions