我有一个父组件(CategoryComponent)、一个子组件(videoListComponent)和一个ApiService。

我的大部分工作都很好,即每个组件都可以访问jsonapi,并通过可观测获取相关数据。

目前,视频列表组件只获取所有视频,我想将其过滤为特定类别中的视频,我通过@Input()将categoryId传递给孩子来实现这一点。

类别组件.html

<video-list *ngIf="category" [categoryId]="category.id"></video-list>

这是有效的,当父CategoryComponent类别发生更改时,categoryId值将通过@Input()传递,但我需要在VideoListComponent中检测到这一点,并通过APIService(使用新的categoryId)重新请求视频数组。

在AngularJS中,我会对变量进行$watch。处理此问题的最佳方法是什么?


当前回答

最安全的选择是使用共享服务而不是@Input参数。此外,@Input参数不会检测复杂嵌套对象类型的更改。

一个简单的服务示例如下:

服务.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class SyncService {

    private thread_id = new Subject<number>();
    thread_id$ = this.thread_id.asObservable();

    set_thread_id(thread_id: number) {
        this.thread_id.next(thread_id);
    }

}

组件.ts

export class ConsumerComponent implements OnInit {

  constructor(
    public sync: SyncService
  ) {
     this.sync.thread_id$.subscribe(thread_id => {
          **Process Value Updates Here**
      }
    }
  
  selectChat(thread_id: number) {  <--- How to update values
    this.sync.set_thread_id(thread_id);
  }
}

您可以在其他组件中使用类似的实现,所有组件将共享相同的共享值。

其他回答

我只想补充一点,如果@Input值不是基元值,还有一个名为DoCheck的Lifecycle钩子很有用。

我有一个数组作为输入,所以当内容发生变化时,这不会触发OnChanges事件(因为Angular所做的检查是“简单”的,而且不深入,所以即使数组上的内容发生了变化,数组仍然是一个数组)。

然后,我实现了一些自定义检查代码,以决定是否要使用更改后的Array更新视图。

@Input() set categoryId(categoryId: number) {
      console.log(categoryId)
}

请尝试使用此方法。希望这有帮助

可以使用ngOnChanges()生命周期方法

@Input() inputValue: string;

ngOnChanges(changes: SimpleChanges) {
    console.log(changes['inputValue'].currentValue);
}

如果不想使用ngOnChange实现og onChange()方法,还可以通过valueChanges事件等订阅特定项的更改。

myForm = new FormGroup({
  first: new FormControl(),
});

this.myForm.valueChanges.subscribe((formValue) => {
  this.changeDetector.markForCheck();
});

markForCheck()writen,因为在这个声明中使用:

changeDetection: ChangeDetectionStrategy.OnPush

我会坚持采用@alan-c-s建议的方法,但需要做一些修改。首先,我反对使用ngOnChanges。相反,我建议将所有需要更改的内容移到一个对象下。并使用BehaviorSubject跟踪其变化:

  private location$: BehaviorSubject<AbxMapLayers.Location> = new BehaviorSubject<AbxMapLayers.Location>(null);

  @Input()
  set location(value: AbxMapLayers.Location) {
    this.location$.next(value);
  }
  get location(): AbxMapLayers.Location {
    return this.location$.value;
  }

<abx-map-layer
    *ngIf="isInteger(unitForm.get('addressId').value)"
    [location]="{
      gpsLatitude: unitForm.get('address.gpsLatitude').value,
      gpsLongitude: unitForm.get('address.gpsLongitude').value,
      country: unitForm.get('address.country').value,
      placeName: unitForm.get('address.placeName').value,
      postalZip: unitForm.get('address.postalZip').value,
      streetName: unitForm.get('address.streetName').value,
      houseNumber: unitForm.get('address.houseNumber').value
    }"
    [inactive]="unitAddressForm.disabled"
    >
</abx-map-layer>