2

I have a login component and a simple method:

login(event) {       
    event.preventDefault();
    this.authService.login(this.user);       
}

This is my AuthService:

export class AuthService {
    constructor(private jsonApiService:JsonApiService) {
    }

    isLoggedIn: boolean = false;

    login(user:User): any {
        this.jsonApiService.post('/token', user)
            .subscribe(
                resp => {
                   check if success,
                   store token to localstorage,
                   set isLoggedIn = true
                   * return new object with data about success/error


                },
                err => {    
                    handle error
                    * return new object with data about success/error
                });
    }

    logout(): void {
        this.isLoggedIn = false;
    }
}

This code works fine. I get response, but I am wondering how to return some data from service to component. I don't want to move subscribe to component, because, I believe, handling must be in the AuthService.

1
  • You could save your data in AuthService, and then ask for the data via a get-method that your component can call. You can also make that method as an Observable, making your component subscribe on it. This will let AuthService finish before the component receives the data. Commented Oct 14, 2016 at 7:24

4 Answers 4

6

Since the http request runs async, you can't return something from inside the lambda, but you could pass a callback like this (which would be essentially like the subscribe):

login(user: User, onSuccess: (data) => void, onError: (data) => void = null): any {
    this.jsonApiService.post('/token', user)
        .subscribe(
            resp => {
               check if success,
               store token to localstorage,
               set isLoggedIn = true

               onSuccess(/*somedata*/);
            },
            err => {    
               handle error

               if (onError)
                   onError(/*somedata*/);
            });
}

And then in your component:

login(event) {       
    event.preventDefault();
    this.authService.login(this.user, (data) => {
        // do something here with the data
    });    

    // or optionally with onError callback
    this.authService.login(this.user, (data) => {
        // do something here with the data
    },
    (errData) => {
        // do something with the error
    });      
}
Sign up to request clarification or add additional context in comments.

Comments

1

You could do something like this where you return a new observable hooked up to another observer in the function scope.

This way your calling component can just subscribe to the returned Observable e.g. with the async pipe and will be notified whenever observer.next is called

I have not tested this so it might need some modification, but I hope it points you in the right direction!

login(user:User): any {
        return new Observable((observer: any) => {
            this.jsonApiService.post('/token', user)
                .subscribe(
                resp => {
                    check if success,
                    store token to localstorage,
                    set isLoggedIn = true
                    obs.next(someResponse);
                    obs.complete();
                },
                err => {
                    handle error
                    obs.next(someResponse);
                    obs.complete();
                });
        }
    }

Comments

0

If you want the subscription to the observable to be contained in the AuthService and want to return a value that is the result of an asynchronous operation, it sounds like what you are looking for is a promise.

You can use the RxJS toPromise operator to do this. It will manage the subscribe (and unsubscribe) for you:

login(user: User): Promise<any> {

    return this.jsonApiService
        .post('/token', user)
        .toPromise()
        .then((result) => {
            // check if success,
            // store token to localstorage,
            // set isLoggedIn = true
            // return new object with data about success/error          
        })
        .catch((error) => {
            // handle error
            // return new object with data about success/error          
        });
}

Comments

-1

Possibly you can do following thing :

//AuthService

export class AuthService {
    constructor(private jsonApiService:JsonApiService) {
    }

    isLoggedIn: boolean = false;

    login(user:User): any {
        this.jsonApiService.post('/token', user)
            .map(
                resp => {
                   /**
                    * check if success,
                    * store token to localstorage
                    */
                    set isLoggedIn = true
                   //return new object with data about success/error
                   return resp.json(); // return response or your new created object

                });
    }

    logout(): void {
        this.isLoggedIn = false;
    }
}

// Component

login(event) {       
  event.preventDefault();
  this.authService.login(this.user).subscribe(res => {
    console.log(res);
  },err => {    
    handle error
    * return new object with data about success/error
  });       
}

3 Comments

He said, he doesn't want to and looks for another possibility.
@user348173 its upto you if you want to move subscribe to component or not, but for some API you need to call same API at multiple place and need to perform different operation on result at that time you will be in trouble if you have used subscribe in services.
No, you can pass lambdas (callback functions) to contain the logic, which then gets called in the subscribe inside the service! :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.