DaRoGa DaRoGa - 2 months ago 21
TypeScript Question

Angular2 Wait for HttpPost response

I have an angular2 app in typescript. I am making a HTTP Post request in order to create a record. This post request happens fine and the record is saved, however, i return the new record from the service and i want to add it to a list in my component and update the DOM with the newly created record. However, it never seems to return in time, is there an accepted way to halt processing until it returns or detect changes in my array and then update the DOM?

My service method is as follows:

public AddComment = (comment: RepackComment): Observable<RepackComment> => {
var json = JSON.stringify({ comment : comment.Comment, rr_id : comment.RepackId, comment_by : comment.CommentBy });
return this.http.post(this.commentUrl + 'Add', json, {headers: this.headers})
.map((response: Response) => <RepackComment>response.json())
.catch(this.handleError);
}


And this is my component method:

saveComment(): void{
console.log(this.newComment);
this.repackService.AddComment(this.newComment)
.subscribe((data: RepackComment) => this.addedComment = data,
error => console.log(error),
() => console.log('Finished creating new comment'));

console.log("added Comment: " + this.addedComment);
this.comments.push(this.addedComment);
this.addNewComment = false;
}


So when,
this.addedComment
has been populated with the return value, i want to add it to the
this.comments
array. i then set a flag called
this.addNewComment
which toggles between input and display fields on the front end to display the data.

Thanks in advance!!!

EDIT

As requested here is the appropriate part of my template for these comments. i use PrimeNG for my components:

<p-dataList [value]="comments" [hidden]="addNewComment">
<header style="height:30px;">
<button pButton type="button" label="Add Comment" (click)="addComment()" class="actionBtn" style="float:left;width:150px;"></button>
<span style="margin-left:-105px;font-size:20px;">Comments</span>
</header>
<template let-comment>
<div class="ui-grid ui-grid-responsive ui-fluid" style="font-size:16px;padding:20px;border-bottom:1px solid #D5D5D5;" >
<div class="ui-grid-row">
<div class="ui-grid-col-12">
<div class="ui-grid ui-grid-responsive ui-fluid comment">
<div class="ui-grid-row row-div">
<div class="ui-grid-col-3 labelFor">ID: </div>
<div class="ui-grid-col-7 displayFor">{{comment.ID}}</div>
</div>
<div class="ui-grid-row row-div">
<div class="ui-grid-col-3 labelFor">Comment: </div>
<div class="ui-grid-col-7 displayFor">{{comment.Comment}}</div>
</div>
<div class="ui-grid-row row-div">
<div class="ui-grid-col-3 labelFor">Author: </div>
<div class="ui-grid-col-7 displayFor">{{comment.CommentBy}}</div>
</div>
</div>
</div>
</div>
</div>
</template>
</p-dataList>
/*INPUT COMPONENTS*/
<div class="ui-grid ui-grid-responsive ui-fluid" style="font-size:16px;padding:20px;border-bottom:1px solid #D5D5D5;" [hidden]="!addNewComment">
<div class="ui-grid-row">
<div class="ui-grid-col-12">
<div class="ui-grid ui-grid-responsive ui-fluid comment">
<div class="ui-grid-row row-div">
<div class="ui-grid-col-3 labelFor">Comment: </div>
<input type="text" pInputText [(ngModel)]="newComment.Comment" class="displayFor"/>
</div>
<div class="ui-grid-row row-div">
<div class="ui-grid-col-3 labelFor">Author: </div>
<input type="text" pInputText [(ngModel)]="newComment.CommentBy" class="displayFor"/>
</div>
</div>
</div>
</div>
<br/>
<div class="div-row" style="margin-left:40%;">
<button pButton type="button" label="Cancel" (click)="cancelComment()" class="actionBtn" style="width:150px;"></button>
<button pButton type="button" label="Save" (click)="saveComment()" class="actionBtn" style="width:150px;"></button>
</div>
</div>


enter image description here

Answer

Like you noticed: Observables work async - so everything after your .subscribe call probably gets called before the code inside the .subscribe callback.

To fix that, you need to put the code, that depends on the results of the subscribe call into its callback:

saveComment(): void{
    console.log(this.newComment);
    this.repackService.AddComment(this.newComment)
                    .subscribe((data: RepackComment) => {
                        this.addedComment = data;

                        // add your code here
                        console.log("added Comment: " + this.addedComment);
                        this.comments.push(this.addedComment);
                        this.addNewComment = false;
                    },
                    error => console.log(error),
                    () => console.log('Finished creating new comment'));
}

Also the object you get back from your post call doesn't match your template. I'd propose this change in your AddComment call with RepackComment having such a constructor:

public AddComment = (comment: RepackComment): Observable<RepackComment> => {
    var json = JSON.stringify({ comment : comment.Comment, rr_id : comment.RepackId, comment_by : comment.CommentBy });
    return this.http.post(this.commentUrl + 'Add', json, {headers: this.headers})
                    .map((response: Response) => response.json())
                    .map(res => new RepackComment(res.id, res.comment, res.comment_by))
                    .catch(this.handleError);
}