我开始了一个新的Angular 7项目,我需要在其中调用一个API以获取结果列表。然后,如果列表中有特定结果,则选择它,否则,我将调用另一个API端点来创建它。所有这些内容都应放入ngOnInit()
方法中。
为简化问题,我有以下代码:
const subject = new BehaviorSubject(null);
subject.next(6);
const res$ = subject.pipe(
mergeMap(() => getValues()),
tap((res) => {
const exists = res.find(x => subject.value === x) || null;
if (exists === null) {
// TODO: call the getNew() function, but I don't want nested call
} else {
// Do nothing
}
})
);
// res$ should contains [1, 2, 3, 4, 5, 6]
res$.subscribe(x => console.log(x));
function getValues() {
// Mocking the API call
return of([1, 2, 3, 4, 5]);
}
function getNew() {
// Mocking the API call
return of(6);
}
最后,可观察的res$
应该包含所有数组(具有增加的值),并且我想避免嵌套订阅。
非常感谢!
答案 0 :(得分:2)
两件事:
不要指望可以访问主题的值。相反,您可以使用mergeMap
的替代形式,该形式允许您从源流和新流中创建选择值。在这种情况下,我使用它从内部可观察对象的源和值中返回一个新项目。
通过将原始结果包装在mergeMap
中以创建新的内部可观察对象,您可以仅使用另一个of
来返回原始结果或新api调用的结果。
const res$ = subject.pipe(
mergeMap(x => getValues(), (orig, res) => ({ orig, res })),
mergeMap(({ orig, res }) => {
const exists = res.find(x => x === orig) || null;
return (exists)
? of(res)
: getNew().pipe(map(x => [... res, x]))
})
);
答案 1 :(得分:0)
解决此问题的一种方法是将其分为两个可观察对象,然后再将它们与CombineLatest合并。我们将使用可观察到的resFirst $两次,并根据是否为null对其进行过滤。
import { combineLatest } from 'rxjs';
---
const subject = new BehaviorSubject(null);
subject.next(6);
const resFirst$ = subject.pipe(
mergeMap(() => getValues()),
map((res) => res.find(x => subject.value === x) || null)
);
const resSecond$ = resFirst$.pipe(
filter(exists => exists === null), <--- FILTERING FOR IS NULL
mergeMap(() => getNew()) <--- SWITCHMAP COULD ALSO BE USED HERE DEPENDING ON WHAT YOU WANT
);
const final$ = combineLatest(resFirst$, resSecond$)
.pipe(filter(exists => exists !== null)) <--- FILTERING FOR NOT NULL
.subscribe(x => console.log(x));
function getValues() {
// Mocking the API call
return of([1, 2, 3, 4, 5]);
}
function getNew() {
// Mocking the API call
return of(6);
}
答案 2 :(得分:0)
const res$ = subject.pipe(
mergeMap(x => getValues().pipe(
mergeMap(values => values.find(v => v === x)
? of(values)
: getNew().pipe(map(n => [...values, n]))
)
))
);