合并 4 个可观察到的条件
Merging 4 observable with conditions
我需要创建一个 Observable 来收集来自某些 http 请求的其他 observable。新的可观察对象必须是相同对象类型的集合,但每个项目都必须是唯一的。你能帮我写出正确的方法来实现这个目标吗?
// The result observable that I need
topicCollection$ = BehaviorSubject<Topic[]> = new BehaviorSubject<Topic[]>(null);
// Boolean observable of authentication
isAuthenticated: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);
// Return default topic
get defaultTopics$(): Observable<Topic[]>{
return this.defaultTopic.asObservable();
}
// Return topics selected by Admin
get TopTopics$(): Observable<Topic[]>{
return this.topTopic.asObservable();
}
//Return topics selected by User
get userTopics$: Observable<Topic[]>{
return this.userTopic.asObservable();
}
//Return user settings
get userSettings$(): Observable<any[]>{
return this.userSettings.asObservable();
}
所以约束是:
- 如果用户未登录,则集合必须按以下顺序排列:defaultTopic、topTopic
- 如果用户登录集合必须在此order:defaultTopic、topTopic、userTopic
- 如果用户已登录,我将读取过滤默认主题的 UserSettings$(如果它们将被隐藏或显示)
- 主题必须是唯一的(重复的主题只会在默认和用户主题可见)
我尝试使用 combineLatest 和 forkJoin,但我不知道如何将运算符与身份验证观察器区分开来。
我非常感谢一些提示!
谢谢
你可以尝试这样的事情。当然,既然你的问题不完整,这个答案也不完整。
您必须自己实现一些部分。尽管如此,以下应该是开始修补的好地方。
get topicCollection$(): Observable<Topic[]> {
return this.isAuthenticated.pipe(
take(1),
switchMap(isLogged => {
// The easy part, merge arrays emitted from two separate streams
const mergeDefaultTop$ = forkJoin([
this.defaultTopics$.pipe(take(1)),
this.topTopics$.pipe(take(1))
]).pipe(
map((v: Topic[][]) => v.flat())
);
// If the user is logged in, merge then filter the merged topics.
return !isLogged ? mergeDefaultTop$ : mergeDefaultTop$.pipe(
switchMap(topics => this.userTopics$.pipe(
map(userTopics => [...topics, ...userTopics])
)),
switchMap(topics => this.userSettings$.pipe(
map(settings => topics
// You'll want to update this filter. I can't define it for you
// as I dont know what a topic is/ how it's labled, etc.
.filter(topic => topic !in settings)
// Filter to remove duplicats. You may want to better define
// equality depending on your use case (again, I can't do
// that for you with what you've provided)
.filter((value, index, self) =>
self.indexOf(value) === index
)
)
))
);
})
);
}
我需要创建一个 Observable 来收集来自某些 http 请求的其他 observable。新的可观察对象必须是相同对象类型的集合,但每个项目都必须是唯一的。你能帮我写出正确的方法来实现这个目标吗?
// The result observable that I need
topicCollection$ = BehaviorSubject<Topic[]> = new BehaviorSubject<Topic[]>(null);
// Boolean observable of authentication
isAuthenticated: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);
// Return default topic
get defaultTopics$(): Observable<Topic[]>{
return this.defaultTopic.asObservable();
}
// Return topics selected by Admin
get TopTopics$(): Observable<Topic[]>{
return this.topTopic.asObservable();
}
//Return topics selected by User
get userTopics$: Observable<Topic[]>{
return this.userTopic.asObservable();
}
//Return user settings
get userSettings$(): Observable<any[]>{
return this.userSettings.asObservable();
}
所以约束是:
- 如果用户未登录,则集合必须按以下顺序排列:defaultTopic、topTopic
- 如果用户登录集合必须在此order:defaultTopic、topTopic、userTopic
- 如果用户已登录,我将读取过滤默认主题的 UserSettings$(如果它们将被隐藏或显示)
- 主题必须是唯一的(重复的主题只会在默认和用户主题可见)
我尝试使用 combineLatest 和 forkJoin,但我不知道如何将运算符与身份验证观察器区分开来。
我非常感谢一些提示! 谢谢
你可以尝试这样的事情。当然,既然你的问题不完整,这个答案也不完整。
您必须自己实现一些部分。尽管如此,以下应该是开始修补的好地方。
get topicCollection$(): Observable<Topic[]> {
return this.isAuthenticated.pipe(
take(1),
switchMap(isLogged => {
// The easy part, merge arrays emitted from two separate streams
const mergeDefaultTop$ = forkJoin([
this.defaultTopics$.pipe(take(1)),
this.topTopics$.pipe(take(1))
]).pipe(
map((v: Topic[][]) => v.flat())
);
// If the user is logged in, merge then filter the merged topics.
return !isLogged ? mergeDefaultTop$ : mergeDefaultTop$.pipe(
switchMap(topics => this.userTopics$.pipe(
map(userTopics => [...topics, ...userTopics])
)),
switchMap(topics => this.userSettings$.pipe(
map(settings => topics
// You'll want to update this filter. I can't define it for you
// as I dont know what a topic is/ how it's labled, etc.
.filter(topic => topic !in settings)
// Filter to remove duplicats. You may want to better define
// equality depending on your use case (again, I can't do
// that for you with what you've provided)
.filter((value, index, self) =>
self.indexOf(value) === index
)
)
))
);
})
);
}