2

I need help figuring out why my data isn't populating in the HTML. I'm sure it's something dumb but I can't figure it out. And I apologize if I left anything out and will gladly include it.

Below is the console results:

undefined
core.js:13606 Angular is running in the development mode. Call enableProdMode() to enable the production mode.

below is the JSON i'm GETting through postman:

GET: http://localhost:3000/api/posts/

{
    "postName": "Fun in the Sun",
    "postDate": "10/23/1993",
    "caption": "Hear all about my trip to lalaland",
    "mainImage": "https://placeholder.net/20x20",
    "suppementalImage1": "https:// placeholder.net/20x20",
    "suppementalImage2": "https:// placeholder.net/20x20",
    "suppementalImage3": "https:// placeholder.net/20x20",
    "suppementalImage4": "https:// placeholder.net/20x20",
    "suppementalImage5": "https:// placeholder.net/20x20",
    "suppementalImage6": "https:// placeholder.net/20x20",
    "content": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptates deleniti quas dolorem quis nulla debitis praesentium dolores eveniet aliquam! At expedita vel consequatur, sit laboriosam ducimus molestiae recusandae ipsam sunt.Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptates deleniti quas dolorem quis nulla debitis praesentium dolores eveniet aliquam! At expedita vel consequatur, sit laboriosam ducimus molestiae recusandae ipsam sunt.Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptates deleniti quas dolorem quis nulla debitis praesentium dolores eveniet aliquam! At expedita vel consequatur, sit laboriosam ducimus molestiae recusandae ipsam sunt."
}

posts.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable, Subject, asapScheduler, pipe, of, from, interval, merge, fromEvent, SubscriptionLike, PartialObserver } from 'rxjs';
import { Post } from '../models/post'
import { map } from 'rxjs/operators'
@Injectable({
  providedIn: 'root'
})
export class PostsService {

  constructor(private http: Http) { }

  private serverApi = 'http://localhost:3000';

  public getAllPosts(): Observable<Post[]> {
    let URI = `${this.serverApi}/api/posts/`;
    return this.http.get(URI)
      .pipe(map(res => res.json()))
      .pipe(map(res => <Post[]>res.posts));
  }

}

latests-posts.component.ts

import { Component, OnInit } from '@angular/core';
import { PostsService } from '../services/posts.service';
import { Post } from '../models/post';
@Component({
  selector: 'app-latest-posts',
  templateUrl: './latest-posts.component.html',
  styleUrls: ['./latest-posts.component.css']
})
export class LatestPostsComponent implements OnInit {
  private posts: Post[] = []; //creats a private variable of posts with type of model List an creates an empty array
  constructor(private postServ: PostsService) { };

  ngOnInit() {
    this.loadPosts()
    console.log(this.loadPosts()); //loads all lists on init
  };

  public loadPosts() {
    this.postServ.getAllPosts().subscribe(response => this.posts = response)
  };


}

latest-posts.component.html

<table id="table">
    <thead>
      <tr>
        <th>Priority Level</th>
        <th>Title</th>
        <th>Description</th>

      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let post of posts">
        <td>{{post.name}}</td>
        <td>{{post.date}}</td>
        <td>{{posts.caption}}</td>
      </tr>
    </tbody>
  </table>
11
  • 2
    Can you post what you console showing for this.posts after subscribe? Commented Feb 8, 2019 at 5:02
  • 2
    Is response of http://localhost:3000/api/posts/ the object? response look like { posts: [] } based on your code Commented Feb 8, 2019 at 5:06
  • 2
    You should log console.log(this.posts()); //loads all lists on init. Not this.loadPosts(). Commented Feb 8, 2019 at 5:09
  • 2
    Just in order to debug try this in your template file .html {{posts | json}} Commented Feb 8, 2019 at 5:09
  • 2
    Your 'posts' property should not be private. Also, try making your posts property an Observable of posts like your API (posts: Observable<Post[]> = of([]), and then just assign that property to the api call (this.posts = this.postServ.getAllPosts). Change your template ngFor to 'let post of posts | async'. Additionally, make sure the API response is actually an array of posts and not some other structure. Commented Feb 8, 2019 at 5:09

2 Answers 2

2

In your API results there is no property with name "posts", though you have applied pipe to map res.posts, which will give you undefined.

Instead, you should return only json from service.

Example: posts.service.ts

public getAllPosts(): Observable<any> {
    let URI = `${this.serverApi}/api/posts/`;
    return this.http.get(URI)
      .pipe(map(res => res.json()));
  }

If you want to type cast your data at component, you can define its type at the time of subscribing it. like below.

component.ts

public loadPosts() {
    this.postServ.getAllPosts().subscribe((response: Post[]) => {
       if(Array.isArray(response))
          this.posts = response
       else {
          this.posts = [];
          this.posts.push(response);
       }
    })
 }
Sign up to request clarification or add additional context in comments.

8 Comments

This is the closest answer so far. By changing the service and using {{posts | json}} in the html I'm able to see the response in the HTML but it is not being picked up in the ngFor statement and I am seeing the following errors:
LatestPostsComponent.html:11 ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. at NgForOf.push../node_modules/@angular/common/fesm5/common.js.NgForOf.ngDoCheck (common.js:3161)
and type casting in the component highlights Posts[] in red saying "Cannot find name Posts"
You can import import { Post } from '../models/post'; to avoid that
As explained in answer you were trying to return res.posts which was undefined in your case. So this code of posts.service.ts just returns whatever you fetch from API. And on component i have checked if the response is Array then directly assign it to this.posts and if its not array but single object than we are pushing it in this.posts which is array by default
|
1

The API call is an async function and need time to resolve. It's missing an ngif in the HTML, so the DOM is updated, when the data arrives.

Something like

<div *ngIf="posts.length > 0"> Content to render when condition is true.</div>

Comments