2

I am sure the problem is about asynchronization but I could not find the solution. I have created a service which gets an array of JSON data. In my component, I would like to show this data when the page is loaded. I don't get any data when the page is loaded, but I created a button and put the same function on its onclick event. I get the data on on click event. What am I doing wrong?

my component

import { Component } from '@angular/core';
import {PostService} from './post.service';

@Component({
  selector: 'app-root',
  template: `

  {{test}}
  <ul>
    <li *ngFor="let item of jsonArray">
    {{item.title}} a
    </li>

  </ul>
  <button on-click="onClick()">button</button>
  `


})
export class AppComponent {
  test;
  jsonArray : any[];
  constructor(private _postService : PostService){


  }

  onClick(){
    this.jsonArray = this._postService.getPosts();
    this.test = "clicked";
  }

  ngOnInit(){
     this.jsonArray = this._postService.getPosts();
     this.test = "init";

   }

}

and my service class

import {Http} from '@angular/http'
import 'rxjs/add/operator/map';
import {Injectable} from '@angular/core';


@Injectable()
export class PostService {

    private _url = "https://jsonplaceholder.typicode.com/posts";

    jsonArray: any[];
    getPosts():any[]{
        //return this._http.get(this._url).map(res =>res.json());
         this._http.get(this._url).subscribe(response => {
           this.jsonArray = response.json();
           console.log(response.json());
           console.log("jsonArray",this.jsonArray);
        });

        return this.jsonArray;
    }

    createPost(post){
        return this._http.post(this._url,JSON.stringify(post)).map(res =>res.json());
    }
    constructor(private _http:Http ){

    }




}
muetzerich
  • 5,600
  • 7
  • 37
  • 52
rematnarab
  • 1,277
  • 4
  • 22
  • 42

1 Answers1

2

You have two problems in your service:

  1. Your return is outside the callback, so the initial empty array will be returned
  2. Even if it wasn't outside, you cannot return data from subscribe.

I suggest you read up on asynchronicity: How do I return the response from an asynchronous call?

Also this How do I return the response from an Observable/http/async call in angular2? explains this behavior in more Angular scenario.

Also read up on on the official tuto of http.

That being said, very shortly said - you need to map in service and subscribe in component.

As to your question:

I don't get any data when the page is loaded, but I created a button and put the same function on its onclick event. I get the data on on click event.

So let's dive in your service method and see what is going on:

getPosts():any[]{
     this._http.get(this._url).subscribe(response => {
       // hey, I'm doing this request now, but I don't know how long it will take
       this.jsonArray = response.json();
       console.log(response.json());
       console.log("jsonArray",this.jsonArray);
    });
    /* okay, so I fired the above request, I won't wait until it is complete, 
       I'll just execute the below while I am waiting!*/
    return this.jsonArray;
}

So, when you fire the request on OnInit it performs the http-request, and while it is executing it returns this.jsonArray before the http request has finished executing.

So now when you click the button, it refires the http-requests and before it has finished completing it again returns you this.jsonArray before that. But hey, now we actually have values there from the previous request, so that is why you get the data just fine!

As earlier mentioned, you cannot return data from subscribe anyway, even if it was inside callback like so:

getPosts():any[]{
     return this._http.get(this._url).subscribe(response => {
        ....
        return this.jsonArray; // WON'T WORK!
    });
}

So what you can do, is return data from map, so do:

Service:

getPosts():any[]{
     this._http.get(this._url)
       .map(res => res.json())
    });
}

Component:

ngOnInit(){
  this._postService.getPosts()
    .subscribe(data => this.jsonArray = data)
}

I really recommend to read the provided links carefully and with thought :)

AT82
  • 71,416
  • 24
  • 140
  • 167