0

I was wondering, how can I easily notify a component about the http response (success or error) by using the new HttpClient (angular 4.3+ from @angular/common/http) after the response was processed (token saved) by the service.

Earlier, I was using this code (using @angular/http):

login(username: string, password: string): Observable<any> {    
  let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
  let options = new RequestOptions({ headers: headers });

  let url = this.apiAddr + '/login';
  var body = 'username=' + username + '&password=' + password;

  return this.http.post(url, body, options).map((res) => {
    let body = res.json();

    this.jwtoken = body.token;
    this.username = username;
    this.saveToken();                           
    return "Login successful!";
  })
  .catch(this.handleError);
 }

By using the new module, I'm not sure how to return the Observable and at the same time access it from the service. This is what I have at the moment (auth.service.ts):

login(username: string, password: string) {
  const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
  const url = apiAddr + '/login';
  const body = 'username=' + username + '&password=' + password;
  const options = {
    headers: headers,
  };


  this.http.post<LoginResponse>(url, body, options).subscribe(
    data => {
      this.jwtoken = data.token;
      this.username = username;
      this.lastTokenRefreshAt = new Date();
      this.saveUserToken();
    }, err => {
      console.log('Error occured');
      console.log(err);
    });
}

Now after that, I would like to notify the LoginComponent, where I could navigate to a different page.

Sonicd300
  • 1,950
  • 1
  • 16
  • 22
phev8
  • 3,493
  • 2
  • 13
  • 23

2 Answers2

2

Use the do operator of observable to access the response from the service when a component invokes it like this:

import 'rxjs/add/operator/do';

login(username: string, password: string) {
  const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
  const url = apiAddr + '/login';
  const body = 'username=' + username + '&password=' + password;
  const options = {
    headers: headers,
  };

  return this.http.post<LoginResponse>(url, body, options).do(
    data => {
      this.jwtoken = data.token;
      this.username = username;
      this.lastTokenRefreshAt = new Date();
      this.saveUserToken();
  });
}

you can catch the error in the component that calls login.

Sonicd300
  • 1,950
  • 1
  • 16
  • 22
2

After updating to angular 6 and using the new version of RxJs, I had to change the do method, since it was renamed/deprecated. To achieve similar results like with the answer of Sonicd300, I have to use the tap method with pipe so:

import { tap } from 'rxjs/operators';

login(username: string, password: string) {
  const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
  const url = this.apiAddr + '/login';
  const body = 'username=' + username + '&password=' + password;
  const options = {
    headers: headers,
  };
  return this.http.post<LoginResponse>(url, body, options).pipe(
    tap(
      data => {
        this.jwtoken = data.token;
        this.username = username;
        this.lastTokenRefreshAt = new Date();
        this.saveUserToken();
        return 'Login successful';
      })
  );
}
phev8
  • 3,493
  • 2
  • 13
  • 23