我有一个复杂的场景,我需要几个可观察的对象来获取一些数据。
我有一个类似以下的方法:
private collectData(): Observable<any> {
const defaultValues = {
prop3: 'textsdfsdf',
prop4: 122323,
};
let result: Observable<any>;
if (this.withDialog) {
result = this._dialog.open(MyDialogComponent).afterClosed();
} else {
result = of({});
}
return result.pipe(map((next) => ({ ...next, ...defaultValues })));
}
此方法返回带有某种数据的可观察值。一些数据可以在对话框中输入。但输入数据是可选的,因此如果不需要,则只会将一些默认数据返回给下标。
此方法由不同的方法调用,例如添加更多数据或与后端通信,如下所示:
private doSth(): Observable<any> {
const sub = new Subject<any>();
const data = this.collectData();
data.subscribe((next) => {
// Get some data from the backend or do some other stuff
console.log(['Collected data', next]);
const newData = {...next, anotherProp: true};
sub.next(newData);
});
return sub.asObservable();
}
此方法应该使用 Observable 返回数据和所有其他内容,并由第三种方法调用:
public click() {
this.doSth().subscribe((next) => {
console.log(['Got some data', next]);
});
}
问题就在这里。只要我使用该对话框,一切都会正常。但是,当我不使用对话框时,因此不是
afterClosed()
可观察的,而是 of({})
可观察的,最后一个订阅永远不会获取数据。
您可以在这里找到完整的示例: https://stackblitz.com/edit/stackblitz-starters-qcayhz?file=src%2Fapp.component.ts
无需通过从订阅处理程序发出值来链接可观察量,只需使用
pipe
如果您打算使用另一个可观察对象(例如http调用)来改变
doSth()
中的原始结果,那么您将使用switchMap
而不是地图等。
public click() {
this.doSth().subscribe((next) => {
console.log(`Got some data. With dialog? ${this.withDialog}`, next);
});
}
private doSth(): Observable<any> {
return this.collectData().pipe(
map(next=>({ ...next, anotherProp: true }))
)
}
private collectData(): Observable<any> {
const defaultValues = {
prop3: 'defaultProp3',
prop4: 9999999999,
};
const result= this.withDialog ? this._dialog.open(MyDialogComponent).afterClosed() : of({});
return result.pipe(map((next) => ({ ...defaultValues,...next })));
}
https://stackblitz.com/edit/stackblitz-starters-1vd2z5?file=src%2Fapp.component.ts
此外,您正在使用默认值覆盖实际数据,而您应该反过来做,因此应该是
return result.pipe(map((next) => ({ ...defaultValues,...next })));
不是相反
示例输出:
Got some data. With dialog? true
{prop3: "defaultProp3", prop4: 9999999999, prop1: "text", prop2: 123, …}
Got some data. With dialog? false
{prop3: "defaultProp3", prop4: 9999999999, anotherProp: true}