如何让 Angular getter 和 setter 工作?

问题描述 投票:0回答:1

尝试应用 angular.io 指南中的“使用 setter 拦截输入属性更改”。孩子的模板显示,但没有对父母的输入进行任何更改..??它之前工作过:-) :-(

这是子组件:ts 和 html:

.ts 文件

import { Component, OnInit, Input } from '@angular/core';
import { BowlingGame } from '../model/bowling-game.model';

@Component({
  selector: 'app-generate-result',
  templateUrl: './generate-result.component.html',
  styleUrls: ['./generate-result.component.css']
})

export class GenerateResultComponent {
  @Input()
  get game(): BowlingGame { return this._game; }
  set game(game: BowlingGame) {
  this._game.rolls[0] = game.rolls[0] + 15;
  this._game = game;
  }
  private _game = { rolls: <number[]>[], player: "", isActive: true };
}

html:

<h2>generate-result.component.html {{game | json}}</h2>

还有父组件,html文件: 我包括所有内容,因为我不知道这位父母有很多孩子是否是一种不好的做法..? app-generate-result 子项位于代码的第一行..

<app-generate-result *ngIf="bowlingGamePlayer1" [game]="bowlingGamePlayer1"></app-generate-result>

<h1>Insert your Roll score (dashboard for 2 players)</h1>
<div class="player1" *ngIf="bowlingGamePlayer1.isActive" >
  <h2>Input Player 1:</h2>
<app-create-roll-item (onRollCreated)="insertRollPlayer1($event)"></app-create-roll-item>
</div>

<div *ngIf="bowlingGamePlayer2.isActive" class="player2">
  <h2>Input Player 2: </h2>
<app-create-roll-item (onRollCreated)="insertRollPlayer2($event)"></app-create-roll-item>
</div>

<h2>bowlingGame1 | json (from parent:app.comp): {{bowlingGamePlayer1 | json}}</h2>

<!-- results are displayed in parent: app.component.html -->
<table>

  <tr>
    <td></td>
    <td colspan="3">frame1</td>
    <td colspan="3">frame2</td>
    <td colspan ="3">frame3</td>
    <td colspan ="3">frame4</td>
    <td colspan ="3">frame5</td>
  </tr>

  <tr class="player1">
    <td>Player:1</td>
    <td *ngFor="let score of bowlingGamePlayer1.rolls">{{score}}</td>
  </tr>

  <tr class="player2">
    <td>Player:2</td>
    <td *ngFor="let score of bowlingGamePlayer2.rolls">{{score}}</td>
  </tr>


</table>


<h1>rollsPlayer1</h1>
<h2>{{rollsPlayer1 | json}}</h2>
<!--
<h1>rollsPerFramePlayer1</h1>
<h2>{{rollsPerFramePlayer1 | json}}</h2>
-->
<h3>indexRollFrame</h3>
<h3>{{indexRollFrame}}</h3><h3>rollsPerFrame: {{rollsPerFrame | json }}</h3>

<h1>totalPins</h1>
<h2>{{totalPins}}</h2>
<h1>rolls player 2 length: {{rollsPlayer2.length}} /// max nr rolls {{maxNumberRollsPlayer2}}</h1>
<h1>rolls player 1 length: {{rollsPlayer1.length}} /// max nr rolls {{maxNumberRollsPlayer1}}</h1>
<h1>index frame player 1/ player2</h1>
<h2>{{indexFramePlayer1 }}/ {{indexFramePlayer2}}</h2> -->

父级的 ts(出于完整性原因):

import { Component, OnInit, Output } from '@angular/core';
import { BowlingGame } from './model/bowling-game.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  bowlingGamePlayer1
  bowlingGamePlayer2
  rollsPlayer1
  rollsPlayer2
  rollsPerFrame
  // total pinns trown !!
  totalPins = 0;
  //  roll index in frame (range: 0 -1- 2)
  indexRollFrame = 0;
  // index frame: 0-4 (5 frames) , frame 5 is special: strike/spare in 5th frame
  indexFramePlayer1 = 0;
  indexFramePlayer2 = 0;
  rollZero = 0;

  maxNumberRollsPlayer1 = 15;
  maxNumberRollsPlayer2 = 15;
  // leave constructor empty of the real work
  constructor() {
    this.bowlingGamePlayer1 = new BowlingGame([], "player1", true);
    this.bowlingGamePlayer2 = new BowlingGame([], "player2", false);
    this.rollsPlayer1 = this.bowlingGamePlayer1.rolls;
    this.rollsPlayer2 = this.bowlingGamePlayer2.rolls;
    this.totalPins = 0;
    this.rollsPerFrame = <number[]>[];
   }

  ngOnInit(): void {
  }

  passToNextPlayer() {
    this.bowlingGamePlayer1.isActive = !this.bowlingGamePlayer1.isActive;
    this.bowlingGamePlayer2.isActive = !this.bowlingGamePlayer2.isActive;
    this.indexRollFrame = 0;
    this.totalPins = 0;
    this.rollsPerFrame = [];
  }

// try to make a function per frame: check! // spare = 15 pins after 2 OR 3 rolls!
  insertRollPlayer1(r:number):void {
    // after execution: length == maxNumberRolls :-)
    if (this.rollsPlayer1.length < (this.maxNumberRollsPlayer1)) {
      this.rollsPlayer1.push(r)
        // put the scores per frame in a rollsPerFrame variable
        this.rollsPerFrame[this.indexRollFrame] = r; // array [0,0,0], starts with indexRollFrame 0

        this.totalPins += this.rollsPerFrame[this.indexRollFrame]; // number, starts with 0
        //  // starting from frame 5 (index is 4 beforehand) apply other logic !!! frame 5 is longer than the other frames!
        if ((this.indexFramePlayer1 == 4) && (this.totalPins < 15) && (this.indexRollFrame == 2)) {
          this.passToNextPlayer();
        } else if ((this.indexFramePlayer1 == 4) && (this.totalPins < 15) && (this.indexRollFrame < 2)) {
          this.indexRollFrame += 1;
        }
        // set max number of rolls, based on 5th frame. Frame 5 is not limited to three rolls!
        if(this.indexFramePlayer1 == 4 && this.totalPins == 15) {
          if(this.indexRollFrame==0) {
            this.maxNumberRollsPlayer1 = 16;
            this.indexRollFrame += 1;
        // case spare in 2 rolls
          } else if (this.indexRollFrame == 1) {
            this.maxNumberRollsPlayer1 = 16;
            this.indexRollFrame += 1;
            // spare in 3 rolls // edge case! this could be the last roll!
          } else if (this.indexRollFrame == 2) {
            this.maxNumberRollsPlayer1 = 17;
            this.indexRollFrame += 1;
            }
          }
        // set the logic for the end of the game, in case of spare or strike in last frame
        if(this.indexFramePlayer1 == 4 && this.totalPins > 15) {
          if(this.rollsPlayer1.length == this.maxNumberRollsPlayer1) {
            this.passToNextPlayer();
          }
        }
        if (this.indexFramePlayer1 < 4) {
          if (this.totalPins == 15) {
            // if strike
            if (this.indexRollFrame == 0) {
              // this.rollsPlayer1.push(this.rollZero);
              // this.rollsPlayer1.push(this.rollZero);
              this.indexFramePlayer1 += 1;
              this.passToNextPlayer();
              // case spare after 2 rolls
            } else if (this.indexRollFrame == 1) {
              // this.rollsPlayer1.push(this.rollZero);
              this.indexFramePlayer1 += 1;
              this.passToNextPlayer();
              // case 15 pins after 3 rolls
            } else {
              this.indexFramePlayer1 += 1;
              this.passToNextPlayer()
            }
            // case not 15 pins in total after 3 rolls
          } else if (this.indexRollFrame == 2) {
            this.indexFramePlayer1 += 1;
            this.passToNextPlayer()
            // case if frame is not over yet
          } else {
            this.indexRollFrame += 1;
          }
        }
    }
  }

// two functions for player 1/ player2 because you don't get the info from the form which player is at turn
  insertRollPlayer2(r:number):void {
    if (this.rollsPlayer2.length < (this.maxNumberRollsPlayer2)) {
      this.rollsPlayer2.push(r)
      this.rollsPerFrame[this.indexRollFrame] = r; // array [0,0,0], starts with indexRollFrame 0
      this.totalPins += this.rollsPerFrame[this.indexRollFrame]; // number, starts with 0
      // start with cases in frame 5
      if (this.indexFramePlayer2 == 4 && this.totalPins < 15 && this.indexRollFrame == 2) {
        this.bowlingGamePlayer2.isActive = false;
      }
      if (this.indexFramePlayer2 == 4 && this.totalPins < 15 && this.indexRollFrame < 2) {
        this.indexRollFrame += 1;
      }
      // set max number of rolls, based on 5th frame. Frame 5 is not limited to three rolls!
      if (this.indexFramePlayer2 == 4 && this.totalPins == 15) {
        if (this.indexRollFrame == 0) {
          this.maxNumberRollsPlayer2 = 16;
          this.indexRollFrame += 1;
          // case spare in 2 rolls
        } else if (this.indexRollFrame == 1) {
          this.maxNumberRollsPlayer2 = 16;
          this.indexRollFrame += 1;
          // spare in 3 rolls // edge case! this could be the last roll!
        } else if (this.indexRollFrame == 2) {
          this.maxNumberRollsPlayer2 = 17;
          this.indexRollFrame += 1;
        }
      }
      // set the logic for the end of the game, in case of spare or strike in last frame
      if (this.indexFramePlayer2 == 4 && this.totalPins > 15) {
        if (this.rollsPlayer2.length == this.maxNumberRollsPlayer2) {
          this.bowlingGamePlayer2.isActive = false;
        }
      }
      if (this.indexFramePlayer2 < 4) {
        if (this.totalPins == 15) {
          // if strike
          if (this.indexRollFrame == 0) {
            // this.rollsPlayer2.push(this.rollZero);
            // this.rollsPlayer2.push(this.rollZero);
            this.indexFramePlayer2 += 1;
            this.passToNextPlayer();
            // case spare
          } else if (this.indexRollFrame == 1) {
            // this.rollsPlayer2.push(this.rollZero);
            this.indexFramePlayer2 += 1;
            this.passToNextPlayer();
            // case 15 pins after 3 rolls
          } else {
            this.indexFramePlayer2 += 1;
            this.passToNextPlayer()
          }
          // case not 15 pins in total
        } else if (this.indexRollFrame == 2) {
          this.indexFramePlayer2 += 1;
          this.passToNextPlayer()
        } else {
          this.indexRollFrame += 1;
        }
      }
    }
  }
}
angular setter
1个回答
1
投票

基本的获取/设置设置如下:

用于存储值的后备属性、setter 方法(通常作为

@Input()
的一部分)和 getter 方法。

private _someValue: string;

@Input() public set someValue(value: string) {
    this._someValue = value;
    // this.nowDoSomethingElse();
}

public get someValue(): string { return this._value; }

每次该组件的输入值发生变化时,它都会在该 set 方法中触发,这样您就可以做任何您需要做的事情。

getter 确实是可选的,但是拥有 getter 意味着模板可以随时访问要使用的值(模板只能访问公共成员,不能访问私有成员)。

需要警惕的一件事是变化检测。如果它是字符串或其他值/基元类型,则对其进行的更改将被识别为新值并进入您所使用的 set 方法。

如果您有一个对象/引用类型,那么对该对象中的 properties 的更改不会导致您进入快乐的 setter 领域。为此,您需要设置自己的更改检测或实际为其提供新的对象引用。

快速简单的对象引用更改:

this.myThing = {...this.myThing};

一旦你的对象引用发生了这样的变化,你就进入了 setter 方法的世界。


现在有空了,更有针对性的回答。

您可以通过一种浪费的方式来做到这一点,不断地重新创建游戏对象,或者您可以只将最少量的数据传递到结果组件中。

它真的需要了解整个游戏,还是只了解一些关键值?我怀疑是后者。在这种情况下,您只需要最少的参与,并且您可以在父母中更严格地控制它。

分数组成部分:

@Input() public data: ScoringDataDto;

父组件:

private _scoreDetails: ScoringDataDto;
public get scoreDetails(): ScoringDataDto { return this._scoreDetails; }

private updateGame(...): void {
    // update the game or something
    // ...

    this.updateScoring(...);
}

private updateScoring(...): void {
    this._scoreDetails = {rolls: this._game.rolls, active: true, whatever: 'else'};
}

每当更新时创建一个新的评分对象,更改将自动注册到评分组件中。

不要害怕复制出您需要的数据位。它并不像看起来那么混乱,并且很快就成为第二天性。它还变得更易于阅读和管理,并通过将所有内容的大小减少到“需要了解的基础”来帮助您更好地构建解决方案。

Angular 毕竟是一个基于组件的系统,而不是一个整体。 父模板:

<app-score-display [data]="scoreDetails"></app-score-display>
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.