我有一个父组件(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);
}
}
您可以在其他组件中使用类似的实现,所有组件将共享相同的共享值。
我会坚持采用@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>
如果不想使用ngOnChange实现og onChange()方法,还可以通过valueChanges事件等订阅特定项的更改。
myForm = new FormGroup({
first: new FormControl(),
});
this.myForm.valueChanges.subscribe((formValue) => {
this.changeDetector.markForCheck();
});
markForCheck()writen,因为在这个声明中使用:
changeDetection: ChangeDetectionStrategy.OnPush
此解决方案使用代理类并提供以下优点:
允许消费者利用RXJS的力量比目前提出的其他解决方案更紧凑比使用ngOnChanges()更安全您可以通过这种方式观察任何类字段。
示例用法:
@Input()
num: number;
@Input()
str: number;
fields = observeFields(this); // <- call our utility function
constructor() {
this.fields.str.subscribe(s => console.log(s));
}
实用程序功能:
import { BehaviorSubject, Observable, shareReplay } from 'rxjs';
const observeField = <T, K extends keyof T>(target: T, key: K) => {
const subject = new BehaviorSubject<T[K]>(target[key]);
Object.defineProperty(target, key, {
get: () => subject.getValue() as T[K],
set: (newValue: T[K]) => {
if (newValue !== subject.getValue()) {
subject.next(newValue);
}
}
});
return subject;
};
export const observeFields = <T extends object>(target: T) => {
const subjects = {} as { [key: string]: Observable<any> };
return new Proxy(target, {
get: (t, prop: string) => {
if (subjects[prop]) { return subjects[prop]; }
return subjects[prop] = observeField(t, prop as keyof T).pipe(
shareReplay({refCount: true, buffer:1}),
);
}
}) as Required<{ [key in keyof T]: Observable<NonNullable<T[key]>> }>;
};
Demo