1

I have a component which a login form: loginForm which calls my api:

  onLogin(): void {

    let username = this.loginForm.value.username;
    let password = this.loginForm.value.password;

    this.api.login(username, password);

      .map(res => res.json())

      .subscribe(
        this._processData,
      );

  }

There is a service which calls an api: loginService.

login(username: string, password: string): Subscription<any> {

    let headers = new Headers();
    headers.append("Content-Type", "application/json");

    return this.http.put("https://myapi.com", JSON.stringify({ username: username, password: password}), {
      headers: headers
    })

    .map(res => res.json())

    .subscribe(
      data => console.log(data),
      err => console.log(err),
      () => console.log("Done")
    );

}

What I want is the error to be handled inside the loginService. But the result back to the onLogin method.

I tried a variety of mapping handlers (as shown) in the onLogin but could not get it to work. Any thoughts about what I might do wrong?

Bas van Dijk
  • 9,933
  • 10
  • 55
  • 91
  • First, remove the `;` before you call `.map()` in `this.api.login(username, password);` otherwise you are not calling it. Second, don't map twice , you already defined the mapper to the observable in the service. Third the second subscribe you are doing (the one in the controller) is wrong, use the same syntax you used in the service: `.subscribe( data => this.data = data );` – Langley Jan 21 '16 at 17:50

2 Answers2

3

In fact, you define a callback within the subscribe method to handle error in the login method (the second parameter). If you want to let errors to be propagated into your onLogin method you need to remove this callback (and even the call of subscribe).

return this.http.put("https://myapi.com",
  JSON.stringify({ username: username, password: password}), {
    headers: headers
  })
.map(res => res.json());

If you want to log the error and then propagate it you can leverage the Observable.throw method:

return this.http.put("https://myapi.com",
  JSON.stringify({ username: username, password: password}), {
    headers: headers
  })

.map(res => res.json())

.catch(err => {
  console.log(err);
  return Observable.throw(err);
});

In this case you need to add a callback to handle the error in the onLogin method:

onLogin(): void {
  let username = this.loginForm.value.username;
  let password = this.loginForm.value.password;

  this.api.login(username, password)
  .subscribe(
    (data) => {
      // Success
      this._processData(data)
    },
    (err) => {
      // Error
    }
  );
}

You can notice that there is a catch operator on Observable to catch error and in the case of errors, the map operator isn't called.

These answers could give you more details:

Hope it helps you, Thierry

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanks for your answer! On the line with `this.api.login(username, password) .subscribe(` I get an error saying that 'subscribe' does not exist on type `subscription` – Bas van Dijk Jan 22 '16 at 08:49
  • I forgot to say thay it is the subscribe in my login() function. It looks you can not subscribe in both functions or something – Bas van Dijk Jan 22 '16 at 08:55
  • Yes, you're right! I did a mistake in my answer. You need to return `Observable.throw(err);`... I updated my code. It should be better now ;-) – Thierry Templier Jan 22 '16 at 08:57
  • Now I get the error `property 'subscribe' does not exist on type 'void'` – Bas van Dijk Jan 22 '16 at 09:01
  • Weird now I cleaned all my generated .js files it gives the earlier error again of `subscribe` not existing on `Subscription` – Bas van Dijk Jan 22 '16 at 09:34
  • Hum strange! I created a plunkr to see what I have in mind: https://plnkr.co/edit/rsJXelOYshVVBwyUJNIz?p=preview ;-) – Thierry Templier Jan 22 '16 at 09:43
  • It works. In your example above the `catch` is missing around `return Observable.throw(err.json());`. Thanks for you effort! – Bas van Dijk Jan 22 '16 at 10:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101403/discussion-between-osi-and-thierry-templier). – Bas van Dijk Jan 22 '16 at 12:54
0

You can define your error handler in your service, and just pass the error from component where you subscribe.

// component

onLogin(): void {

let username = this.loginForm.value.username;
let password = this.loginForm.value.password;

this.api
  .login(username, password)
  .subscribe(
    this._processData, // success
    this.api.onError   // error
    // if above doesn't work this should:
    // error => this.api.onError(error)
  );

}

_processData(...data) { console.log(data); }

// service

login(username: string, password: string): Subscription<any> {

  let headers = new Headers();
  headers.append("Content-Type", "application/json");

  return this.http
    .put("https://myapi.com", JSON.stringify({ username: username, password: password}), { headers: headers })
    .map(res => res.json())
}

onError(...args) { console.log(args); }
Sasxa
  • 40,334
  • 16
  • 88
  • 102