簡體   English   中英

如何訪問 Angular 中 ngOnChanges 上的 @Input 參數以外的變量?

[英]How to access variables other than @Input params on ngOnChanges in Angular?

我遇到了一個場景,我需要對 ngOnchanges 上的數據進行一些處理(因為數據來自父組件的 @Input 數據綁定屬性)。 在此轉換期間,我需要使用在 ngOnInit 中初始化的屬性。 我嘗試直接使用它,但值未定義。 有人可以讓我知道我該如何實現這一目標。 下面是我的場景的示例代碼。

ParentComp HTML
<myParent [data]="list$ | async"></myParent>

ChildComp TS
export class {
  @Input() data : any ; //data from parent
  breakPoint$: Observable<number>

  constructor(){}
  ngOnInit(){
   this.breakPoint$ = fromEvent(this.window, 'resize').pipe(
      map(() => this.numOfCols())
    );
  }

ngOnChanges(changes: SimpleChanges) {
    if (changes['data']) {
       // need to do some data processing here based on numOfColumns value, so trying to access
       this.breakPoint$.pipe(

       ) // Here i get cannot read property pipe of undefined error
      );

 numOfCols(): number {
    return this.breakpointObserver.isMatched(`(max-width: 1008px)`) ? 4 : 5;
  }

我建議在這里使用withLatestFrom rxjs 運算符。 我將為numOfColumns創建一個 Observable ,只要它更新,最終訂閱就會觸發。 但是:它不會觸發,直到您擁有來自ngOnInit()的數據(第二個 Observable),並且僅在之后更新numOfColumns時才會觸發,即BreakPoint的后續更改不會觸發訂閱,如果您希望它是兩者都觸發,然后您可以使用zip代替。

我在setter中執行此操作,您也可以使用ngOnChanges

_numOfColumns;
numOfColumnsObs$ = new BehaviorSubject(false);

set numOfColumns(val) {
    this._numOfColumns = val;
    this.numOfColumnsObs$.next(val);
}

get numOfColumns() {
    return this._numOfColumns
}

ngOnInit() {
    this.breakPoint$ = fromEvent(this.window, 'resize').pipe(
        map(() => this.numOfCols())
        );

        // new code here.
        this.numOfColumnsObs$.pipe(withLatestFrom(this.breakPoint$))
        .pipe(filter(([columns]) => columns !== false))
        .subscribe(([columns, breakPoint]) => {
            // do the changes you wanted in `ngOnChanges`;
        })
}

你在這里需要一個 BehaviorSubject,因為 observable 會在訂閱之前發出。 因為有一個 BehaviorSubject,所以有一個 hack,我用false初始化了它。 假設 numOfColumns 永遠不會出現false 如果可以,您可以使用任何不可能的值對其進行初始化,然后通過管道對其進行過濾。

您可以添加另一個輸入屬性並將 numOfCols$ 移動到父組件中。

ParentComp HTML

<myParent [data]="list$ | async"
          [numOfCols]="numOfCols$ | async>
</myParent>

家長委員會 TS

numOfCols$: Observable<number>;

constructor(private breakpointObserver: BreakpointObserver) {
   this.numOfCols$ = breakpointObserver.observe('(max-width: 1008px)').pipe(
      map(({matches}) => matches ? 4 : 5)
   );
}

ChildComp TS

@Input() data: any;
@Input() numOfCols: number;

ngOnChanges(changes: SimpleChanges) {
    if (changes['data']) {
        // You can use this.numOfCols here
    }
}

ngOnChanges 在 ngOnInit 之前首先觸發。 因為 Inputs 在 ngOnInit 之前填充。
如果您需要來自 ngOnInit 的值,您可以在 ngOnChanges 中使用 boolean "isInitDone"。 並且不要忘記在您的 ngOnInit 中將此 boolean 設置為 true。

但是,您還應該觸發 ngOnChanges 方法中所做的事情。 所以也許把它放在一個方法中,ngOnChanges 和 ngOnInit 都會調用......

另一種解決方案是將 ngOnInit 代碼移動到 ngOnChanges,在if (this.breakpoint$)

Angular 的組件生命周期鈎子按以下順序觸發:

  1. ngOnChanges
  2. ngOnInit
  3. ngDoCheck
  4. ngAfterContentInit
  5. ngAfterContentChecked
  6. ngAfterViewInit
  7. ngAfterViewChecked
  8. ngOnDestroy

如您所見,您正在嘗試訪問未在第一個 ngOnChanges 中定義的屬性。 您可以像這樣在 if 語句中簡單地添加一個檢查:

ngOnChanges(changes: SimpleChanges) {
    if (changes['data'] && !!this.breakPoint$) {
....

或者您甚至可以在 ngOnInit 之外定義 breakPoint$,如下所示:

   @Input() data : any ; //data from parent
   breakPoint$: Observable<number> = fromEvent(this.window, 'resize').pipe(
      map(() => this.numOfCols())
    );

暫無
暫無

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

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