2016-05-15 2 views
0

Я пытаюсь сделать простой импорт, но я получаю массивный вопрос stack trace.Не могу прочитать свойство undefined Angular 2

Я пробовал искать везде по вопросам, связанным с этим, но для меня трассировка стека не дает много информации.

EDIT: Я попытался установить переменную, которая не извлекается из 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; 
     } 
    } 
} 

player-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> 
+0

трассировка стека указывает на то, что ошибка исходит от игрока-detail.component.html ... можете ли вы включить этот код, пожалуйста? – sourdoughdetzel

+0

Извините, я подумал, что добавил. – ReallyGoodPie

ответ

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" в шаблоне, чтобы гарантировать, что объект игрока не пустой перед загрузкой элемента.

1

В вашей службы вы не должны возвращаться с обещанием. Вы можете использовать поглотитель

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

Если вы настроите ссылка первой, она должна автоматически обновлять. Вы также можете бросить определение компонента компонента ngIf игрока в DOM и показать его только после того, как объект игрока не будет определен.

Редактировать Просто видел, кто-то разместил о * ngIf до меня, так что если это решение, пожалуйста, отметьте их.

+0

Из моего понимания, которое очень ограничено, это всего лишь способ обработки асинхронного вызова. Это определенно не нужно в моем приложении, и я изменил его на 'this.player = this.playerService.getPlayer()', и ошибка по-прежнему сохраняется. – ReallyGoodPie

+0

Что я предлагаю сделать, это ... 'this.playerService.getPlayer().then ((player) => {this.player = player;}); ' – sourdoughdetzel

+0

Это имеет больше смысла, но я думаю, что метод, который я использовал, работал, поскольку я все еще получал значения в своем console.log. Внедрение вашего метода, похоже, не решает проблему. – ReallyGoodPie

Смежные вопросы