Ionic2 Error using AngularFire and Firebase: Uncaught (in promisse): This is null

I'm currently learning Ionic2 and Angular and I'm trying to use Firebase as database for the application. The first thing I'm trying to do is to use AngularFire to login using Firebase Email authentication. Code below:

login.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Home } from '../../home/home';
import { SignUp } from '../signup/signup'
import { AngularFire, AuthProviders, AuthMethods } from 'angularfire2'
@Component({
  selector: 'page-login',
  templateUrl: 'login.html'
})
export class Login {
  constructor(public navCtrl: NavController, public af: AngularFire) {
  }
  public loginWithEmail(username: string, password: string) {
    this.af.auth.login({
      email: username,
      password: password,
    },
    {
      provider: AuthProviders.Password,
      method: AuthMethods.Password,
    }).then(function() {
      this.navCtrl.setRoot(Home);
    })
  }
}

login.html

...
    <ion-list>
        <ion-item>
            <ion-label floating>Email</ion-label>
            <ion-input type="text" [(ngModel)]="userName"></ion-input>
        </ion-item>
        <ion-item>
            <ion-label floating>Senha</ion-label>
            <ion-input type="password" [(ngModel)]="password"></ion-input>
        </ion-item>
        <ion-item>
            <button ion-button block (click)="loginWithEmail(userName, password)">Login</button>
        </ion-item>
    </ion-list>
...

But then, when I click on the button, and call loginWithEmail() method, I got the following error:

Uncaught (in promise): TypeError: this is null
Login.prototype.loginWithEmail/<@http://localhost:8100/build/main.js:83566:13
O</g</t.prototype.invoke@http://localhost:8100/build/polyfills.js:3:9653
NgZone.prototype.forkInnerZoneWithAngularBehavior/this.inner<.onInvoke@http://localhost:8100/build/main.js:37511:28
O</g</t.prototype.invoke@http://localhost:8100/build/polyfills.js:3:9591
O</d</e.prototype.run@http://localhost:8100/build/polyfills.js:3:7000
h/<@http://localhost:8100/build/polyfills.js:3:4659
O</g</t.prototype.invokeTask@http://localhost:8100/build/polyfills.js:3:10273
NgZone.prototype.forkInnerZoneWithAngularBehavior/this.inner<.onInvokeTask@http://localhost:8100/build/main.js:37502:28
O</g</t.prototype.invokeTask@http://localhost:8100/build/polyfills.js:3:10201
O</d</e.prototype.runTask@http://localhost:8100/build/polyfills.js:3:7618
i@http://localhost:8100/build/polyfills.js:3:3700

What am I doing wrong?

Upvotes: 1

Views: 85

Answers (2)

sebaferreras
sebaferreras

Reputation: 44659

But I still don't know why it works that way and not in the other... could someone explain me?

The answer is because of Arrow functions. When using the this keyword inside a function like function(){...}, the this keyword references the function itself (and the navCtrl is not defined in that function).

One of the most important aspects of the arrow functions is that

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target.

So when using the this keyword inside of () => {...}, it will still reference the component instance (which has a navCtrl property defined), so everything works as expected.

Upvotes: 1

Well, I have just found a way to get it working: I have just changed:

(on login.ts)

this:

.then(function() {
  this.navCtrl.setRoot(Home);
})

to this:

.then(() => this.navCtrl.setRoot(Home))

But I still don't know why it works that way and not in the other... could someone explain me?

Upvotes: 0

Related Questions