Mundi Mundi - 3 months ago 23
Javascript Question

How to consume a Promise from a service (native script / firebase)?

I have a

userService
that calls
firebase.login()
which returns a result of type
Promise<User>
. It is called like this:

firebase.login( { config...
})
.then (function (result) { /* use result */},
function (error) { /* use error */ });


Elsewhere in the project, in a UI component, I need to react to the outcome of the login (i.e. success or error). I do not want to put any routing or similar logic into the user service, but rather have the other component control what happens next.

How is that done? How can another component react to it?

The component mentioned above is a class called
LoginPage
. It has a
Login
button which should start the Firebase login. The button is linked to a function (also called
login()
) in the
LoginPage
class.

XML:

<Button [text]="Sign in" class="submit-button" (tap)="login()"></Button>


login.component.ts

login() {
this._userService.login(this.user)
.then(function (data) {
/* go to next screen */
});
}


The above is obviously wrong, as the
then
clause will always be executed, regardless of the success or failure of the login.

Here is the login function in the
userService
:

@Injectable()
export class UserService {


login(user: User) {

firebase.login({
type: firebase.LoginType.PASSWORD,
email: user.email,
password: user.password
})
.then( function (result) {
console.log("Successful Login! " + JSON.stringify(result));
return result;
}, function (error) {
console.log(error);
return error;
});
}

Answer

UserService login method should return a promise to make it available for chaining:

  login(user: User) {
    return firebase.login(...)...
  }

In the original above login error was already caught, this leaves the promise with resolution that can be either a result or an error.

The preferable way to handle errors here is to not catch the error in the service itself. We always want to know if login request was successful or not.

  login(user: User) {

    return firebase.login(...)
    // second callback is optional if we don't need to log errors
    .then( function (result) { ... }, function (error) {
       console.log(error);
       return firebase.Promise.reject(error); 
    });
  }

This way an error can (and also should, Angular 2 will throw an error if there are uncaught promises) be caught and handled:

login() {
   return this._userService.login(this.user)
   .then(function (data) {
      /* go to next screen */
   })
   .catch(function (error) { ... });
}

It is always preferable to return promises, at least for testing purposes.

Comments