javascript - Typescript Forelder/Barn


Angular2/Typescript - Forelder/Barn-direktiv(?)

Jeg er ny på, og holder fortsatt på å lære, Angular2/Typescript/javascript. Som et resultat er jeg ikke helt sikker på hvordan jeg skal titulerer spørsmålet mitt. Grunnlaget for appen min er et kortspill. Premisset (relativt til min utfordring) er at spillet har 2 spillere og hver spiller har en hånd med 5 kort. Jeg har API-kall for å bygge/returnere hånden med kort.

I malfilen til app.component har jeg 2 div-blokker; en for hver spillers hånd med kort. For øyeblikket har jeg fått det til å fungere ved å lage to separate arrays med kort (kalt p1cards og p2cards). Her er den relative koden for det:

<div class="player1Cards" id="player1Cards">
  <ul class="list-group">
    <div draggable *ngFor="let card of p1cards" [dragData]="card" 
class="list-group-item">
      <img src="{{cardBluePath + card.fileName}}">
    </div>
  </ul>
</div>

<div class="player2Cards" id="player2Cards">
  <ul class="list-group">
    <div draggable *ngFor="let card of p2cards" [dragData]="card" 
class="list-group-item">
      <img src="{{cardBluePath + card.fileName}}">
    </div>
  </ul>
</div>

Og her er den faktiske eksportklassen for hele AppComponent:

@Injectable()
export class AppComponent implements OnInit
{
  @ViewChild(ModalComponent) errorMsg: ModalComponent;

  errorMessage: string;
  gameBoard: GameBoard[];
  name: {};
  mode = 'Observable';

  //we need a gameboard (maybe not)

  //we need an array of players
  player:Player;
  players:Player[] = [];

  p1cards:Card[] = [];
  p2cards:Card[] = [];
  droppedItems = [];

  //This tells us where the card images can be found
  cardBluePath = "/assets/deck/Blue/";
  cardRedPath = "/assets/deck/Red/";

  //The boardService will handle our API calls
  boardService;

  //Initialize the API service
  constructor(boardService:BoardService) {
    this.boardService = boardService;
  }


  //On load...
  ngOnInit()
  {
    //Create the game
    this.boardService.createGame()
        .subscribe(
         error =>  this.errorMessage = <any>error);

   //Create the players
   this.createPlayer(0);
   this.createPlayer(1);
 }


  createPlayer(player: number)
  {
    var playerName;
    if (player == 0) {playerName = "Player1"} else {playerName = "Player2"};

    //We'll make a call to the API to build the hand of cards
    this.boardService.buildHand(player)
        .subscribe(
         cardList =>
         {
           var cardData = [];
           cardData = JSON.parse(cardList.toString());

           var i, itemLength, card
           itemLength = cardData.length;
           for(i=0;i<itemLength;i++)
           {
             let card = new Card();
             Object.assign(card,
             {
               "cardNum":i,
               "id": cardData[i].id,
               "displayName": cardData[i].displayName,
               "fileName": cardData[i].fileName,
               "left": cardData[i].left,
               "top": cardData[i].top,
               "right": cardData[i].right,
               "bottom": cardData[i].bottom,
               "level": cardData[i].level,
               "native": cardData[i].native
             });

             if (player == 0) {this.p1cards.push(card)} else {this.p2cards.push(card)};
             ////this.cards.push(card);
           }

           //Now we will create the player and feed it the hand
           this.player = new Player(playerName);
           if (player ==0) {this.player.cardHand = this.p1cards} else {this.player.cardHand = this.p2cards};
           this.players.push(this.player);
         }
       );
  }


  //When a card is dropped...
  onItemDrop(e: any, slot: any)
  {
      e.dragData.slot = slot;

      //Update the object
      this.boardService.playCard(slot, e.dragData.card)
          .subscribe(result => {
            //If the slot is open and the card is played, physically move the item
            if (result == "true" )
            {
              this.droppedItems.push(e.dragData);
              this.removeItem(e.dragData, this.p1cards);
            }
            else{
              window.alert("Slot already occupied.");
              //this.modalWindow.show()
              //this.errorMsg.showErrorMessage("Slot already occupied.");
              //this.errorMsg.show();
            }
          });
  }


  //Remove the card from the hand
  removeItem(item: any, list: Array<any>)
  {
      let index = list.map((e) => {
          return e.cardNum
      }).indexOf(item.cardNum);
      list.splice(index, 1);
  }
}

createPlayer-funksjonen er virkelig der spørsmålet begynner. For øyeblikket vil den gjøre API-kallet og analysere JSON tilbake til et array av kort. Akkurat nå lever arrayet av kort lokalt i AppComponent (som p1cards eller p2cards).

Det jeg i stedet vil gjøre, er å lage et spillertilstand-objekt (komponent) for hver spiller, tildele deres respektive kortstokk, og deretter legge disse spillerne i et array. Jeg hadde den delen til å fungere (biter av koden eksisterer fortsatt over, men ikke alt), men jeg støtte på et problem i min *ngFor for å vise kortene. I pseudokode forsto jeg hva jeg måtte gjøre, men i praksis klarte jeg det ikke å finne ut av det.

Jeg visste at div-klassen player1Cards trengte å være noe som "let player of Players hvor name=player1", og deretter trengte jeg å iterere over player.cardHand[]-arrayen for å vise hver av kortene. Jeg prøvde ganske mange ting, men ingenting fungerte.

Så etter noen timer med Google-søk kom jeg til den konklusjonen at jeg trengte en barnevisning for spilleren for å håndtere det. Jeg har for øyeblikket følgende for det:

Min player.html er:

<div draggable *ngFor="let card of cardHand" [dragData]="card" class="list-group-item">
  <img src="{{cardBluePath + card.fileName}}">
</div>

Og min player.ts er:

import { Component, Input, OnInit } from '@angular/core';
import { Card } from './card';


@Component({
    selector: 'player',
    templateUrl: './player.html',
})

export class Player implements OnInit
{
  public cardHand: Card[];
  cardBluePath = "/assets/deck/Blue/";

  constructor
  (
    public name: string
  )
  {}

  ngOnInit()
  {

  }
}

Deretter i min AppComponent-mal, la jeg til blokken (og importerte player.ts)

Jeg får en feilmelding på App.Component "inline template:69:16 forårsaket av: Ingen leverandør for String!". Av all Googling jeg gjorde og alle endringene jeg prøvde (ViewChild, Input/Output, Referanse), kunne jeg ikke få det til å fungere. Jeg husker ikke nøyaktig hva jeg gjorde, men på et tidspunkt klarte jeg å fjerne feilen, men kort-arrayen ble ikke sendt til spilleren (jeg skulle ønske jeg hadde committed eller stashet den koden).

I hodet mitt forstår jeg oppgaven som skal gjøres, jeg klarer bare ikke å få det til. Jeg vet at jeg trenger å opprette Player-objektet og gi det den respektive cardHand for at spillerens HTML skal kunne tolke det. Jeg kan gjøre det fint i AppComponent, men når jeg prøver å gjøre det som en forelder/barn, setter jeg fast.

Kan noen hjelpe meg med å komme i riktig retning?

Svar #1

Jeg vet at jeg må lage Player-objektet og gi det respektive cardHand for at spillerens HTML skal kunne tolke det. Jeg kan gjøre det fint i AppComponent, men når jeg prøver å gjøre det som en forelder/barn, stopper jeg opp.

Jeg er enig i at det gir mening å lage et array av spillerobjekter, hver med et array av kortene i hånden. Noe sånt som dette:

let player1 = {name:'Player 1',hand:[]} 
let player2 = {name:'Player 2',hand:[]}
this.players = [player1, player2]

player1.hand.push(this.dealCard())
...

player2.hand.push(this.dealCard())
...

Du kan deretter lage en spillerkomponent for å vise spillerne (og til og med en kortkomponent for å vise hånden deres). I rotmalen din vil du løkke gjennom spillerne, opprette spillerkomponenten din og sende inn spillerdataene, inkludert hånden deres.

<player-component *ngFor="let player of players" [player]="player"></player-component>

Sørg for at spillerkomponenten din har en inngang for å motta spillerdataene:

export class PlayerComponent implements OnInit {
 @Input() player: Player;
  constructor() { }

  ngOnInit() { }
}

Deretter, i <player-component>-malen, gå gjennom spillerens hånd og gjengi kortene:

<p>I am {{player.name}}. My hand is:</p>
<ul>
  <li *ngFor="let card of player.hand">{{card}}</li>
</ul>

Her er en plunker som viser en fungerende demo som er en forenklet versjon av dette oppsettet: https://plnkr.co/edit/5Hz8P7poCb9Ju5IR6MWs?p=preview Du bør kunne konfigurere det til det spesifikke oppsettet for spillet ditt. Lykke til!

Svar #2

i din spillerkomponent, hvis du vil få tilgang til en annen komponent: 1. den komponenten trenger en import-setning øverst 2. i @component-delen må du inkludere den i Providers 3. inkluder den også i konstruktøren

For mer informasjon, besøk her: https://angular.io/guide/dependency-injection