Suresh
Suresh

Reputation: 5987

TypeError: Cannot read property '_router' of null in NativeScript

I'm working on an android app using NativeScript+AngularJS2+TypeScript. Following their doc - http://docs.nativescript.org/angular/tutorial/ng-chapter-0 .

Got stuck at a point when after successfully login user needs to redirect to List page. Following their Routing section now - http://docs.nativescript.org/angular/tutorial/ng-chapter-3#35-routing

Did everything according to their doc. Here are my codes -

app.component.ts

import {ListPage} from "./pages/list/list.component";
import {Component} from "@angular/core";
import {RouteConfig} from "@angular/router-deprecated";
import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "nativescript-angular/router";
import {LoginPage} from "./pages/login/login.component";

@Component({
  selector: "main",
  directives: [NS_ROUTER_DIRECTIVES],
  providers: [NS_ROUTER_PROVIDERS],
  template: "<page-router-outlet></page-router-outlet>"
})
@RouteConfig([
  { path: "/Login", component: LoginPage, name: "Login", useAsDefault: true },
  { path: "/List", component: ListPage, name: "List" }
])
export class AppComponent {}

user.service.ts

import {Injectable} from "@angular/core";
import {User} from "./user";
import {ConfigService} from "../config";
import firebase = require("nativescript-plugin-firebase");

@Injectable()
export class UserService {

    register(user: User, config: ConfigService) {

        console.log('Email entered : '+user.email);
        console.log('Password entered : '+user.password);
        console.log("API url going to use is : "+config.apiUrl);

        firebase.init(<any>{
            persist: true, // Allow disk persistence. Default false.
            url: config.apiUrl
        }).then(
            function (instance) {
                console.log("firebase.init done");
            },
            function (error) {
                console.log("firebase.init error: " + error);
            }
        );

        return firebase.createUser({
            email: user.email,
            password: user.password
          }).then(
              function (response) {
                console.log(response);
                return response;
              }
          )

    }

    login(user: User, config: ConfigService) {

        firebase.init({
            persist: true, // Allow disk persistence. Default false.
            url: config.apiUrl
        }).then(
            function (instance) {
                console.log("firebase.init done");
            },
            function (error) {
                console.log("firebase.init error: " + error);
            }
        );

        return firebase.login({
            type: firebase.LoginType.PASSWORD,
            email: '[email protected]',
            password: 'firebase'
          }).then(
              function (response) {
                console.log(response);
                return response;
              }
          )

    }

}

login.component.ts

import {Router} from "@angular/router-deprecated";
import {Component} from "@angular/core";
import {User} from "../../shared/user/user";
import {UserService} from "../../shared/user/user.service";
import {ConfigService} from "../../shared/config";
import {HTTP_PROVIDERS} from "@angular/http";
import firebase = require("nativescript-plugin-firebase");

@Component({
    selector: "my-app",
    providers: [UserService, HTTP_PROVIDERS,ConfigService],
    templateUrl: "pages/login/login.html",
    styleUrls: ["pages/login/login-common.css", "pages/login/login.css"]
})

export class LoginPage {
    user: User;
    isLoggingIn = true;
    config:any;

    constructor(private _router: Router, private _userService: UserService) {
        this.user = new User();
        this.config = new ConfigService();
    }

    submit() {
        if (this.isLoggingIn) {
            this.login();
        } else {
            this.signUp();
        }
    }


    login() {

        var result = this._userService.login(this.user,this.config);

        result.then(
            function (result) {
                console.log("Login Successs");
                // the result object has these properties: uid, provider, expiresAtUnixEpochSeconds, profileImageURL, token
                var response = JSON.stringify(result);
                console.log('Login Response : '+response);

                // Route to list page
                this._router.navigate(["List"]);
            },
            function (errorMessage) {
                console.log("Login Error");
                console.log(errorMessage);
            }
        );
    }

    signUp() {
        var result = this._userService.register(this.user,this.config);

        result.then(
            function (result) {
                // dialogs.alert({
                //  title: "User created",
                //  message: "userid: " + result.key,
                //  okButtonText: "Nice!"
                // })
                console.log('User Object Info : '+JSON.stringify(result));
                console.log('User Created with user id - '+result.key);
                alert("Your account was successfully created.");

                this.toggleDisplay();
            },
            function (errorMessage) {
                // dialogs.alert({
                //  title: "No user created",
                //  message: errorMessage,
                //  okButtonText: "OK, got it"
                // })
                console.log('No user created. Got error message insted - '+errorMessage);
                alert("Unfortunately we were unable to create your account.")
            }
        );


    }

    toggleDisplay() {
        this.isLoggingIn = !this.isLoggingIn;
    }
}

Everything workign fine except at the time of executing this._router.navigate(["List"]);from file login.component.ts I'm getting following error

JS: EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property '_router' of null

Can't able to understand what exactly the error is.

Regards

Upvotes: 1

Views: 1283

Answers (2)

Andrew Pham
Andrew Pham

Reputation: 185

Yes you can dynamically bind this as George Edwards pointed out. Another option is to use arrow functions which would allow you to retain the scope of the caller inside the function so that you won't need to always remember to write var that = this.

login() {

    var result = this._userService.login(this.user,this.config);
    result.then(
        // Within the arrow function 'this' now refers to the lexical context rather than changing depending upon how the function is called.
        (result) => {
            console.log("Login Successs");
            // the result object has these properties: uid, provider, expiresAtUnixEpochSeconds, profileImageURL, token
            var response = JSON.stringify(result);
            console.log('Login Response : '+response);

            // Route to list page
            this._router.navigate(["List"]); //reference _router from the original scope
        },
        // Arguably clearer
        (errorMessage) => {
            console.log("Login Error");
            console.log(errorMessage);
        }
    );
}

Upvotes: 2

George Edwards
George Edwards

Reputation: 9229

I expect this issue is to do with context scope issues. I think you should try and capture the scope before you divine into your then's. I usually store this in a variable called that see below ( and see the comments):

login() {

    var result = this._userService.login(this.user,this.config);
    var that = this; //store the current context 
    result.then(
        function (result) { //context (this has changed)
            console.log("Login Successs");
            // the result object has these properties: uid, provider, expiresAtUnixEpochSeconds, profileImageURL, token
            var response = JSON.stringify(result);
            console.log('Login Response : '+response);

            // Route to list page
            that._router.navigate(["List"]); //reference _router from the original scope
        },
        function (errorMessage) {
            console.log("Login Error");
            console.log(errorMessage);
        }
    );
}

Upvotes: 7

Related Questions