【问题标题】:Merging 4 observable with conditions将 4 个 observable 与条件合并
【发布时间】:2022-06-22 17:58:20
【问题描述】:

我需要创建一个 Observable 来收集来自一些 http 请求的其他 observable。新的 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();
}

所以约束是:

  1. 如果用户未登录,集合必须按此顺序:defaultTopic、topTopic
  2. 如果用户登录,集合必须按以下顺序:defaultTopic、topTopic、userTopic
  3. 如果用户已登录,我将读取过滤默认主题的 UserSettings$(如果它们将被隐藏或显示)
  4. 主题必须是唯一的(重复的主题仅在默认情况下且用户主题可观察)

我尝试使用 combineLatest 和 forkJoin,但我不知道如何区分操作员和身份验证观察者。

【问题讨论】:

  • 尝试使用forkjoin?
  • 一切都是BehaviourSubject 有什么原因吗?默认的null 案例有语义吗? Null 不是“相同对象类型的集合” - 所以我不确定在您当前的设置下您想要什么是可能的。如何知道用户是否登录?那是用户设置的一部分吗? userSettings 可以是任何东西的列表,任何东西列表上的过滤器应该如何工作? defaultTopictopTopicuserTopic 都是列表,当你说 order 时是什么意思?连接它们?如果您发现重复,您如何在删除它们的同时保留您的订单(删除哪一个)?
  • 我使用 BehaviourSubject 是因为我想要最后一个值,null 因为我写错了:) 如果 isAuthenticated 发出 true,我知道用户是否已登录。 UserSettings 是 {key: value} 的列表,例如 {topicOfTheDay: 'off'} 所以如果 Topic == 'topicOfTheDay' 的标签是关闭的,我想隐藏它。对于订单,我的意思是连接它们如果我发现重复项,我想删除 userTopic 之一。感谢您的宝贵时间

标签: angular rxjs observable


【解决方案1】:

你可以试试这样的。当然,由于您的问题不完整,所以这个答案也不完整。

您必须自己实现一些部分。不过,下面应该是一个不错的开始修补的地方。

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
            )
          )
        ))
      );

    })
  );

}

【讨论】:

  • 是的|有史以来最好的工作示例 :) v.flat() 是一个发现,我不得不更改编译器选项,但它可以工作!非常感谢!
  • @onlygio 很高兴为您提供帮助,如果是解决方案,请记住将答案标记为正确
猜你喜欢
  • 1970-01-01
  • 2018-12-14
  • 1970-01-01
  • 2021-02-23
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多