簡體   English   中英

Angular @Input getter / setter和非原始值

[英]Angular @Input getter/setter and non-primitive values

問題:我想每次綁定子組件的對象中的屬性發生變化時都能調用一個函數。 但是,即使可以看到綁定的輸入屬性更新,setter也只被調用一次。

這一切都來自於需要將子組件綁定到其父組件屬性,該屬性恰好是具有深層嵌套屬性的復雜對象。 我已經了解到,當對象中的嵌套屬性發生更改時,Angular onChange事件不會觸發。 因此決定使用getter / setter。 然而,正如這個問題所見,使用getter / setter也無效。 我已經改變了我的子組件以訂閱父組件訂閱的相同Observable,從而直接從服務接收更新並繞過父組件。 我已經對Angulars綁定和TypeScript getter / setter進行了大量研究,並且從各方面來看,它看起來像我的代碼顯示工作,但事實並非如此。

目標:了解為什么使用帶有getter / setter的@Input綁定到子組件中的父組件屬性不能像非主要類型那樣工作。 是否存在我缺少的基本概念或我的代碼中是否存在實現錯誤?

我將在這里展示一些源代碼,並為任何希望看到它實時運行的人附加StackBlitz。 StackBlitz現場演示

模擬data.service.ts

@Injectable()
export class MockDataService {
  public updateSubject: Subject<any> = new Subject();
  public numObj = {
    'prop1': 'stuff',
    'prop2': 'stuff',
    'prop3': 'stuff',
    'prop4': 'stuff',
    'level1': {
      'level2': {
        'target': 0 //target is the prop that will be getting updated
      }
    }
  }
  constructor() {
    this.startDemo();
  }
  private startDemo(): void {
    //This is simulating the server sending updates
    //to the numObj
    setInterval(() => {
      this.numObj.level1.level2.target += 1;
      this.update();
    }, 4000);
  }
  private update(): void {
    try {
      this.updateSubject.next(this.numObj);
    } catch (err) {
      this.updateSubject.error(err);
    }
  }
}

app.component.ts(父cmp)

app.component.html <child-cmp [targetNumber]="targetNumber"></child-cmp>

export class AppComponent implements OnInit {
  public targetNumber: any;
  public displayCurrentNumber: number;
  constructor(private mockDataService: MockDataService){}
  ngOnInit(){
    this.mockDataService.updateSubject.subscribe({
      next:(data) => this.onUpdate(data),
      error: (error) => alert(error),
    });
  }
  private onUpdate(data: any): void{
    if(data){
      this.targetNumber = data;
      this.displayCurrentNumber = data.level1.level2.target;
    }
  }
}

兒童cmp.component.ts

export class ChildCmpComponent {
  private _targetNum: any;
  public displayNumberObj: any;
  public displayNumber: number;
  public changeArray: string[] = [];
  @Input() 
  set targetNumber(target: any){
    this.changeArray.push('Setter(),');
    this._targetNum = target;
    this.setDisplay(this._targetNum);
  }
  get targetNumber(): any{
    this.changeArray.push('Getter(),');
    return this._targetNum;
  }
  private setDisplay(target: any): void{
    this.changeArray.push('setDisplay(),');
    this.displayNumberObj = target;
    this.displayNumber = target.level1.level2.target;
  }
}

這有兩個部分:

  1. 認識到@Input裝飾器僅在更改檢測期間更新 ,因此分配給綁定數據的setter僅在更改檢測期間觸發。 在Angular源代碼的前兩個注釋行中明確說明了這一事實。

export interface InputDecorator { /** * Declares a data-bound input property. * * Angular automatically updates data-bound properties during change detection. *

  1. 從1開始,我們需要了解Angulars變化檢測如何應用於非原始性

為了幫助解釋這一點,我將使用以下對象ObjA:

public ObjA = {
    'prop1': 'value1',
    'prop2': 'value2'
  }

當數據綁定屬性的值發生更改時,Angulars會更改檢測觸發器 但是,當綁定的屬性是ObjA類的對象時,它是ObjA的引用,而不是對象本身。 因此,當ObjA的屬性值發生變化(狀態變化)時,角度變化檢測不會觸發。 角度是不知道的狀態ObjA ,而是參考ObjA

感謝@JBNizet和@ Jota.Toledo向我提供的信息(在上面的評論中)我需要理解這個主題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM