2

I have app in which a user can add a comment , and the comment is displayed , my problem is comments are not displayed untill I refresh the page.

I want a comment to be displayed after the user click just enter or submit button

Here is what I have so far:

  1. Getting data service.ts

    this.activeRouter.params.subscribe((params) => {
      let id = params['id'];
      this.moviesService.getComments(id)
        .then(comments => {
          console.log(comments);
          this.comments = comments;
        });
    });
    

2.Then display to the front end: html

   <div *ngFor="let comment of comments" class="col-md-7">
          <ul class="list-group">
            <li class="list-group-item">Author: {{comment.author}}</li>
            <li class="list-group-item">Comments: {{comment.description}}</li>
          </ul>
          <br>
        </div>

Unfortunately when my server updates the JSON, the html does not update at all until I refresh the page then I can see the added comments wrong

what am I missing in my code to accomplish what I want? newbie though

The Dead Man
  • 6,258
  • 28
  • 111
  • 193

2 Answers2

2

Your code is good but unfortunately a Promise only resolves to one value.

However, observables can provide you with a real time stream of data!

Make the moviesService.getComments() method return an observable which returns comments.

It should look a little something like this (assume you are using the angular HttpClient to fetch the comments):

// movieService.service.ts

import { HttpClient } from '@angular/common/http'

...

constructor(
  private http: HttpClient
)

getComments() {
  return this.http.get<Comments>(url)
}

...

You can consume the observable like so:

// comment.component.ts

...

comments: Observable<Comments>

...

ngOnInit() {
  this.comments = this.movieService.getComments()
}

...

And finally in the template:

// comments.component.html

 <div *ngFor="let comment of comments | async" class="col-md-7">
  <ul class="list-group">
    <li class="list-group-item">Author: {{comment.author}}</li>
    <li class="list-group-item">Comments: {{comment.description}}</li>
  </ul>
  <br>
</div>
Mateja Petrovic
  • 3,799
  • 4
  • 25
  • 40
  • 1
    Hii @mateja so in which scenario we should consider using promise ? – The Dead Man Jun 23 '18 at 09:43
  • The cool thing about observables is that they are so versatile. You can use them to work with streams of data or a single value, be it synchronous or asynchronous. That's why I tend to use observables and rxjs all the time. But if you – Mateja Petrovic Jun 23 '18 at 22:12
  • 1
    Alas, but if you just want to get a single value and not a stream it's just fine to use a promise. There are so any great resources on this topic like https://stackoverflow.com/questions/37364973/promise-vs-observable and a side by side comparison https://www.youtube.com/watch?v=jgWnccjXR4I – Mateja Petrovic Jun 23 '18 at 22:36
0

Using Async Pipe & Observables Pipes in Angular work just as pipes work in Linux. They accept an input and produce an output. What the output is going to be is determined by the pipe's functionality. This pipe accepts a promise or an observable as an input, and it can update the template whenever the promise is resolved or when the observable emits some new value. As with all pipes, we need to apply the pipe in the template.

Let's assume that we have a list of products returned by an API and that we have the following service available:

// api.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ApiService {

  constructor(private http: HttpClient) { }

  getProducts() {
    return this.http.get('http://localhost:3000/api/products');
  }

}

The code above is straightforward - we specify the getProducts() method that returns the HTTP GET call.

It's time to consume this service in the component. And what we'll do here is create an Observable and assign the result of the getProducts() method to it. Furthermore, we'll make that call every 1 second, so if there's an update at the API level, we can refresh the template:

// some.component.ts

import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { ApiService } from './../api.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/switchMap';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})

export class ProductsComponent implements OnInit {
  @Input() products$: Observable<any>;
  constructor(private api: ApiService) { }

  ngOnInit() {
    this.products$ = Observable
      .interval(1000)
      .startWith(0).switchMap(() => this.api.getProducts());
  }

}

And last but not least, we need to apply the async pipe in our template:

<ul>
  <li *ngFor="let product of products$ | async">{{ product.prod_name }} for {{ product.price | currency:'£'}}</li>
</ul>

This way, if we push a new item to the API (or remove one or multiple item(s)) the updates are going to be visible in the component in 1 second.

Naddy
  • 1