无法读取未定义的Angular 2的属性

时间:2016-05-15 01:48:21

标签: angularjs typescript angular

我正在尝试进行简单的导入,但我遇到了大量stack trace问题。

我尝试到处寻找与此相关的问题,但对我来说,堆栈跟踪并没有提供太多信息。

编辑:我尝试将其设置为一个不从Firebase获取的变量,它运行正常。我想现在的问题是如何处理来自Firebase的这些信息,以便它在准备就绪时加载。

以下是相关文件:

main.ts:

import { bootstrap }    from '@angular/platform-browser-dynamic';
import {AppComponent} from './app.component';
import { HTTP_PROVIDERS } from '@angular/http';

bootstrap(AppComponent, [HTTP_PROVIDERS]);

player.services.ts:

import { Injectable } from '@angular/core';
import {Player} from "../classes/player";


@Injectable()
export class PlayerService {

    player: Player;

    getPlayer()
    {
        return Promise.resolve(this.player);
    }

    createPlayer(uid: string, name: string, firebaseRef: Firebase)
    {
        this.player = {
            'uid': uid,
            'name': name,
            'level': 1,
            'maxHealth': 100,
            'health': 100,
            'maxEnergy': 50,
            'energy': 50,
            'fun': 1,
            'skill': 1,
            'knowledge': 1
        }

        firebaseRef.child('players').child(uid).set(this.player);
    }

    setPlayer(player: Player)
    {
        this.player = player;
    }
}

app.component.ts

import { Component, OnInit } from '@angular/core'
import { PlayerDetailComponent } from './components/player-detail.component';
import {PlayerService} from "./services/player.service";
import {FirebaseEventPipe} from "./firebasepipe";
import {Player} from "./classes/player";

@Component({
    selector: "my-app",
    templateUrl: 'app/views/app.component.html',
    directives: [PlayerDetailComponent],
    providers: [PlayerService],
    pipes: [FirebaseEventPipe]
})

export class AppComponent implements OnInit{
    title = "title";

    authData: any;

    private firebaseUrl: string;
    private firebaseRef: Firebase;

    private loggedIn = false;
    player: Player;

    constructor(private playerService: PlayerService) {
        this.firebaseUrl = "https://!.firebaseio.com/";
        this.firebaseRef = new Firebase(this.firebaseUrl);
        this.firebaseRef.onAuth((user) => {
            if (user) {
                this.authData = user;
                this.loggedIn = true;
            }
        });
    }

    getPlayer() {
        this.firebaseRef.once("value", (dataSnapshot) => {
            if (dataSnapshot.child('players').child(this.authData.uid).exists()) {
                this.firebaseRef.child('players').child(this.authData.uid).once("value", (data) => {
                    this.player = data.val();
                    this.playerService.setPlayer(this.player);
                    console.log(this.player);
                });
            } else {
                this.playerService.createPlayer(this.authData.uid, this.getName(this.authData), this.firebaseRef);
                this.playerService.getPlayer().then(player => this.player);
                console.log(this.player);
            }

        });




    }

    ngOnInit() {
        this.getPlayer();
    }

    authWithGithub() {
        this.firebaseRef.authWithOAuthPopup("github", (error) =>
        {
            if (error) {
                console.log(error);
            }
        });
    }

    authWithGoogle() {
        this.firebaseRef.authWithOAuthPopup("google",(error) =>
        {
            if (error) {
                console.log(error);
            }
        });

    }

    getName(authData: any) {
        switch (authData.provider) {
            case 'github':
                return authData.github.displayName;
            case 'google':
                return authData.google.displayName;
        }
    }
}

玩家detail.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { Player } from '../classes/player';


@Component({
    selector: "player-details",
    templateUrl: "app/views/player-detail.component.html",
    styleUrls: ['app/style/player-detail.component.css'],
})

export class PlayerDetailComponent implements OnInit{
    @Input() player: Player;

    ngOnInit() { console.log(this.player)}
}

app.component.html

<nav class="navbar navbar-default">
    <div class="container">
        <ul class="nav navbar-nav">
            <li class="navbar-link"><a href="#">Home</a></li>
        </ul>
    </div>
</nav>

<div class="jumbotron" [hidden]="loggedIn">
    <div class="container">
        <h1>Angular Attack Project</h1>
        <p>This is a project for the <a href="https://www.angularattack.com/">Angular Attack 2016</a> hackathon. This is a small project where set goals
            in order to gain experience as a player and person. In order to begin, please register with on of the following services</p>
        <button class="btn btn-social btn-github" (click)="authWithGithub()"><span class="fa fa-github"></span>Sign Up With Github </button>
        <button class="btn btn-social btn-google" (click)="authWithGoogle()"><span class="fa fa-google"></span>Sign Up With Github </button>
    </div>
</div>


<player-details [player]="player" [hidden]="!loggedIn"></player-details>

玩家detail.component.html

<div id="player" class="panel panel-default">
    <div id="player-stats" class="panel-body">
        <img id="player-image" class="img-responsive" src="../app/assets/images/boy.png"/>
        <div class="health-bars">
            <div class="health-bar">HEALTH:<br/><progress value="{{ player.health }}" max="{{ player.maxHealth }}"></progress></div>
            <div class="energy-bar">ENERGY:<br/><progress value="{{ player.energy }}" max="{{ player.maxEnergy }}"></progress></div>
            <div class="player-attributes"><span class="fa fa-futbol-o player-attr fun">: {{ player.fun }} </span><span class="fa fa-cubes player-attr skill">: {{ player.skill }}</span> <span class="fa fa-graduation-cap player-attr knowledge">: {{ player.knowledge }}</span></div>
        </div>
    </div>
</div>

2 个答案:

答案 0 :(得分:1)

在您的服务中,您不必返回承诺。你可以使用一个getter

private player: Player;

get CurrentPlayer()
{
    return this.player;
}

然后在你的组件中:

    getPlayer() {

            this.firebaseRef.once("value", (dataSnapshot) => {
                if (dataSnapshot.child('players').child(this.authData.uid).exists()) {
                    this.firebaseRef.child('players').child(this.authData.uid).once("value", (data) => {
this.playerService.setPlayer(this.player);                        
                        console.log(this.player);
                    });
                } else {
                    this.playerService.createPlayer(this.authData.uid, this.getName(this.authData), this.firebaseRef);
                    console.log(this.player);
                }

            });

       ngOnInit() {
    this.player = this.playerService.CurrentPlayer();
            this.getPlayer();
        }

如果先设置参考,则应自动更新。您还可以在DOM中抛出* ngIf播放器详细信息组件定义,并且只有在播放器对象未定义时才显示它。

修改 刚看到其他人在我之前发布了关于* ngIf的信息,所以如果这是解决方案,请标记他们的。

答案 1 :(得分:0)

加载PlayerDetailComponent时,播放器变量未定义,因此没有播放器这样的对象。

要解决此问题,OnChanges可以像这样实现:

import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
import { Player } from '../classes/player';
import {HealthBarComponent} from "./health-bar.component";
import {ChecklistComponent} from "./checklist.component";


@Component({
    selector: "player-details",
    templateUrl: "app/views/player-detail.component.html",
    styleUrls: ['app/style/player-detail.component.css'],
    directives: [HealthBarComponent, ChecklistComponent],
})

export class PlayerDetailComponent implements OnChanges{

    @Input()
    player: Player;

    ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    }


}

然后我们可以在模板中添加*nfIf="player"以确保在加载元素之前播放器对象不为空。