45

I need to call a method after get the data from the http post request

service: request.service.TS

get_categories(number){
 this.http.post( url, body, {headers: headers, withCredentials:true})
    .subscribe( 
      response => {
        this.total = response.json();

      }, error => {
    }
  ); 

}

component: categories.TS

search_categories() {

this.get_categories(1);
//I need to call a Method here after get the data from response.json() !! e.g.: send_catagories();
}

Only works if I change to:

service: request.service.TS

get_categories(number){
 this.http.post( url, body, {headers: headers, withCredentials:true})
    .subscribe( 
      response => {
        this.total = response.json();
        this.send_catagories(); //here works fine

      }, error => {
    }
  ); 

}

But I need to call the method send_catagories() inside of component after call this.get_categories(1); like this

component: categories.TS

search_categories() {

this.get_categories(1);
this.send_catagories(response);
}

What I doing wrong?

Adrita Sharma
  • 21,581
  • 10
  • 69
  • 79
Louise
  • 563
  • 1
  • 5
  • 10
  • Is `send_catagories()` also using an observable? If yes, you need to chain the observable from get_categories() to the one in send_categories() with the `.mergeMap()` operator. Let me know if you need help with the syntax. – AngularChef Feb 15 '17 at 01:28
  • send_catagories() is not using observable, please show me the syntax: return this.http.post( url, body, {headers: headers, withCredentials:true}) .subscribe( response => { this.total_page = response.json();return this.total_page; }, .share() ); } then this.get_category(1).subscribe(response=> { this.callfunc(); }); – Louise Feb 15 '17 at 01:35
  • 1
    Got it. I have posted an answer with the correct syntax. – AngularChef Feb 15 '17 at 01:50

5 Answers5

59

Update your get_categories() method to return the total (wrapped in an observable):

// Note that .subscribe() is gone and I've added a return.
get_categories(number) {
  return this.http.post( url, body, {headers: headers, withCredentials:true})
    .map(response => response.json());
}

In search_categories(), you can subscribe the observable returned by get_categories() (or you could keep transforming it by chaining more RxJS operators):

// send_categories() is now called after get_categories().
search_categories() {
  this.get_categories(1)
    // The .subscribe() method accepts 3 callbacks
    .subscribe(
      // The 1st callback handles the data emitted by the observable.
      // In your case, it's the JSON data extracted from the response.
      // That's where you'll find your total property.
      (jsonData) => {
        this.send_categories(jsonData.total);
      },
      // The 2nd callback handles errors.
      (err) => console.error(err),
      // The 3rd callback handles the "complete" event.
      () => console.log("observable complete")
    );
}

Note that you only subscribe ONCE, at the end.

Like I said in the comments, the .subscribe() method of any observable accepts 3 callbacks like this:

obs.subscribe(
  nextCallback,
  errorCallback,
  completeCallback
);

They must be passed in this order. You don't have to pass all three. Many times only the nextCallback is implemented:

obs.subscribe(nextCallback);
AngularChef
  • 13,797
  • 8
  • 53
  • 69
  • Thanks, Thanks, Thanks! it is working perfect! just two question,1) inside this.send_categories(total){ this.myNewTotal= total } How I can ectract the data (responde.json) from "total" parameter? 2) i have added "error" to the syntax: .map(response => response.json()), error => { } ); if I need call this.send_categories(total) only in error case, how I can subscribe to error ? – Louise Feb 15 '17 at 03:02
  • Hmm. Based on your previous code, I thought `response.json()` **WAS** the total. What I mean is, I named the variable `total` but it contains whatever is in `response.json()`; you can name this variable whatever you want. I've updated my answer to reflect that better and also to show you how to handle the error. – AngularChef Feb 15 '17 at 09:41
  • I may be missing the point of the third argument in subscribe but I am wondering if you can invoke a method to complete the callback? – Winnemucca Sep 09 '17 at 07:29
  • 1
    Oftentimes the two callbacks are synonymous. Take an HTTP request for instance. When the server returns the data, the `nextCallback` is invoked, and then immediately after the `completeCallback`. But in a different situation (e.g. a chat system), the `nextCallback` could be invoked multiple times (e.g. for each chat notification) and the `completeCallback` could never be invoked. – AngularChef Sep 09 '17 at 14:55
  • If you created an observable with `Observable.create()`, you can complete it with `observer.complete()`. If you have a Subject, you can call `subject.complete()`. Finally, some operators trigger the completion of the observable, like `obs.take(1)` which completes the observable after one value has been emitted. – AngularChef Sep 09 '17 at 14:57
  • 1
    the best explanation ever. – yas Aug 27 '18 at 15:22
10

You can add a callback function to your list of get_category(...) parameters.

Ex:

 get_categories(number, callback){
 this.http.post( url, body, {headers: headers, withCredentials:true})
    .subscribe( 
      response => {
        this.total = response.json();
        callback(); 

      }, error => {
    }
  ); 

}

And then you can just call get_category(...) like this:

this.get_category(1, name_of_function);
Gab
  • 1,007
  • 9
  • 22
  • Thanks I will try. But my idea is use something more proffesional to catch the response. Eg: get_category(1).then or an observable but i dont know how to do that – Louise Feb 15 '17 at 01:07
  • There's nothing unprofessional about using callback functions but suit yourself – Gab Feb 15 '17 at 01:08
  • 4
    In my opinion, passing in a callback to a service when using observables is not a good pattern. As Louis alluded to, it makes additional logic and error handling ugly. – RobM Feb 15 '17 at 01:19
  • 2
    @RobM I just wanted to say that you're right. While rewriting a co-workers application, I went to callback hell and back and I now see the error in my ways! – Gab Aug 22 '17 at 17:34
6

You can code as a lambda expression as the third parameter(on complete) to the subscribe method. Here I re-set the departmentModel variable to the default values.

saveData(data:DepartmentModel){
  return this.ds.sendDepartmentOnSubmit(data).
  subscribe(response=>this.status=response,
   ()=>{},
   ()=>this.departmentModel={DepartmentId:0});
}
Sushrut Kanetkar
  • 363
  • 3
  • 13
2

You can do this be using a new Subject too:

Typescript:

let subject = new Subject();

get_categories(...) {
   this.http.post(...).subscribe( 
      (response) => {
         this.total = response.json();
         subject.next();
      }
   ); 

   return subject; // can be subscribed as well 
}

get_categories(...).subscribe(
   (response) => {
     // ...
   }
);
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
1
get_categories(number){
 return this.http.post( url, body, {headers: headers, withCredentials:true})
      .map(t=>  {
          this.total = t.json();
          return total;
      }).share();
  );     
}

then

this.get_category(1).subscribe(t=> {
      this.callfunc();
});
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
  • Yes!, this is what I want, how I can keep the old syntax without ".map"?, eg : return this.http.post( url, body, {headers: headers, withCredentials:true}) .subscribe( response => { this.total = response.json(); return total; }).share(); – Louise Feb 15 '17 at 01:29
  • (173,69): error TS2339: Property 'subscribe' does not exist on type 'Subscription'. – Louise Feb 15 '17 at 01:40
  • Why do you want the original syntax? FRP is about combining streams to create one meaningful observable that can be subscribed to. – Michael Kang Feb 15 '17 at 03:01
  • @pixelbits I get an error message that `.share does not exist on type Observable` and also should `return total` not be `return this.total`? Just trying to figure this code out seeing that I am struggling with something similar. – Alfa Bravo Sep 30 '17 at 09:57