1

I'm trying to create a service.ts file which will handle all of my Http requests in TypeScript (AngularJs2).

Now I do get the right response, but I cannot access the properties outside of the subscribe() function. Let me show you what I mean.

APICaller.service.ts:

import { Injectable, Inject } from '@angular/core';
import { Http } from '@angular/http';

import { Evenement } from './models/evenement.model';
import { Deelnemer } from './models/deelnemer.model';
import { Comment } from './models/comment.model';

@Injectable()
export class APICaller {
    http : Http
    baseUrl:string = "http://10.0.4.161:8080";

    constructor(@Inject(Http) httpService) {
        this.http = httpService;
    }

    addNewComment(deelnemerId:number, eventId:number, content:string) : Comment{
        let results:Comment = {id: 0, content:"", user: "", status: "", date: ""};

        this.http.post(this.baseUrl+"/evenementen/"
        +eventId +"/deelnemers/"+deelnemerId+"/addComment"
        ,{
            user: 'developer',
            content: content
        }).subscribe((response) => {
            results = response.json();
            console.log("results id: "+ results.id);
        });

        return results;
    }
}

component.ts: (minimized - still needs cleaning)

import { APICaller } from '../../apicaller.service';
import { Comment } from '../../models/comment.model';

@Component({    
    templateUrl: 'build/pages/deelnemer-details/deelnemer-details.html',
    providers: [APICaller]
})

export class DeelnemerDetails {   
    public deelnemer:any;
    public http:Http;
    public eventObj;
    public newComment;
    public comments;
    public editComment:any;


    constructor(private apiCaller : APICaller, private navCtrl: NavController, navParams : NavParams,  public toastCtrl : ToastController, public alertCtrl:AlertController, @Inject(Http) httpService) {
        this.eventObj = navParams.get("event");
        this.http = httpService;
        this.newComment = "";
        this.deelnemer={};
        this.editComment={
        id: -1,
        edit: false,
        content: ""
    }

        this.getDeelnemer(navParams.get("deelnemer"));
    }

    addNewComment(){
        let test:Comment = {id: 0, content:"", user: "", status: "", date: ""};

        console.log("deelnemer id "+this.deelnemer.id);
        console.log("eventObj id "+ this.eventObj.id);
        console.log("new comment : "+this.newComment);

        test = this.apiCaller.addNewComment(this.deelnemer.id, this.eventObj.id, this.newComment);

        console.log("new comment id: "+ test.id);

        this.comments.push(
           test
        );
        this.newComment="";

    }

Responses and console.log()

enter image description here

So it seems like within the .subscribe() it doesn't set the value of results.

2 Answers 2

3

The callback you pass to subscribe(...) is called much later when the response from the server arrives. return results; is called immediately after the call to the server was initiated.

If you change the code to

@Injectable()
export class APICaller {
    http : Http
    baseUrl:string = "http://10.0.4.161:8080";

    constructor(@Inject(Http) httpService) {
        this.http = httpService;
    }

    addNewComment(deelnemerId:number, eventId:number, content:string) : Observable<Comment>{
        let results:Comment = {id: 0, content:"", user: "", status: "", date: ""};

        return this.http.post(this.baseUrl+"/evenementen/"
        +eventId +"/deelnemers/"+deelnemerId+"/addComment"
        ,{
            user: 'developer',
            content: content
        }).map((response) => {
            console.log("results id: "+ results.id);
            return response.json();
        });
    }
}

You can get the result by calling

addNewComment(){
    let test:Comment = {id: 0, content:"", user: "", status: "", date: ""};

    console.log("deelnemer id "+this.deelnemer.id);
    console.log("eventObj id "+ this.eventObj.id);
    console.log("new comment : "+this.newComment);

    this.apiCaller.addNewComment(this.deelnemer.id, this.eventObj.id, this.newComment).subscribe(test => {

      console.log("new comment id: "+ test.id);

      this.comments.push(
         test
      );
      this.newComment="";
    });

   // code here (outside the callback passed to `subscribe(...)`) is again
   // executed before `result` arrives

}

Async execution is contagious and there is no way to return to sync execution once an async execution was initiated.

I changed subscribe() to map() because .map() returns an Observable which can be subscribed to by the caller. .subscribe() returns a Subscription and is worthless in this case to the caller.

Sign up to request clarification or add additional context in comments.

5 Comments

I had to edit my return to Observable<Comment> but how do I retrieve the data from the return statement? Since test has te be an Observable as well?
Sorry, I forgot the return type. I also added more code from the call site. You need to move all code that depends on the result into the `subscribe(...)´ callback.
The line let test:Comment = {i... confuses me. It doesn't seem to do anything.
I got a previous error that 'id' was not a property for 'undefined' so I defined it to see what was going on. Maybe could've been my REST service
Glad to hear :) Thanks for the feedback.
2

As the http request is asynchronous you can't return the result, as it's not yet received when the return statement is reached.

You can use a callback:

addNewComment(deelnemerId: number, eventId: number, content: string, callback: (comment: Comment) => void): void {
    let results:Comment = {id: 0, content:"", user: "", status: "", date: ""};

    this.http.post(`${ this.baseUrl }/evenementen/"${ eventId }/deelnemers/${ deelnemerId }/addComment`, {
        user: 'developer',
        content: content
    }).subscribe((response) => {
        console.log("results id: " + results.id);
        callback(response.json());
    });
}

And then:

this.apiCaller.addNewComment(this.deelnemer.id, this.eventObj.id, this.newComment, (comment: Comment) => {
    console.log("new comment id: " + comment.id);

    this.comments.push(
       comment
    );

    this.newComment = "";
});

Or a promise:

addNewComment(deelnemerId:number, eventId:number, content:string): Promise<Comment> {
    let results:Comment = {id: 0, content:"", user: "", status: "", date: ""};

    this.http.post(`${ this.baseUrl }/evenementen/"${ eventId }/deelnemers/${ deelnemerId }/addComment`, {
        user: 'developer',
        content: content
    }).map((response) => {
        console.log("results id: " + results.id);
        return response.json();
    }).toPromise();
}

And then:

this.apiCaller.addNewComment(this.deelnemer.id, this.eventObj.id, this.newComment).then((comment: Comment) => {
    console.log("new comment id: " + comment.id);

    this.comments.push(
       comment
    );

    this.newComment = "";
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.