typescript - TypeError: Kan inte läsa egenskapen '_router' av null i NativeScript
Jag arbetar på en Android-app med NativeScript+AngularJS2+TypeScript. Jag följer deras dokumentation - http://docs.nativescript.org/angular/tutorial/ng-chapter-0 .
Körde fast vid en punkt när användaren efter en lyckad inloggning behöver omdirigeras till List-sidan. Följde deras Routing-avsnitt nu - http://docs.nativescript.org/angular/tutorial/ng-chapter-3#35-routing
Gjorde allt enligt deras dokument. Här är mina koder -
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 ',
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;
}
}
Allt fungerar bra förutom vid körning av this._router.navigate(["List"]); från filen login.component.ts får jag följande fel
JS: EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property '_router' of null
Kan inte förstå exakt vad felet är.
Hälsningar
Svar #1
Jag misstänker att detta problem har att göra med kontextomfångsproblem. Jag tror att du bör försöka fånga omfånget innan du dyker in i dina then-block. Jag brukar lagra detta i en variabel som kallas that, se nedan (och se kommentarerna):
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);
}
);
}
Svar #2
Ja, du kan dynamiskt binda this som George Edwards påpekade. Ett annat alternativ är att använda pilfunktioner, vilket skulle göra att du kan behålla anroparens scope inuti funktionen så att du inte alltid behöver komma ihåg att skriva 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);
}
);
}
