1

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

2 Answers 2

7

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);
        }
    );
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this quick reply. It worked. I was also thinking about scope issue. But, as new to both nativescript & typescript couldn't able to figure out how to resolve it.
2

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);
        }
    );
}

1 Comment

Thanks for this new technique. I'd heard about this arrow function of ES6 couple of time back but never used it. In your given code can you change that._router.navigate(["List"]); to this._router.navigate(["List"]); . I think that's a typo.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.