链接了两个订阅以进行重构

时间:2018-12-06 00:39:57

标签: angular rxjs

我尝试通过两个订阅(方法中的一个,服务中的一个)重构下面的代码,但我找不到解决方法。

我正在使用akita处理我的状态。因此,建议按照documentation中所述在服务中使用订阅。

此代码用于处理非规范化的情况:MongoDB的Service集合中User集合的language字段。

这是我使用的模型:

用户模型

export interface UserInfo {
  [...]
  services: ID[];
}

export interface User {
  _id: ID;
  [...]
  userInfo: Partial<UserInfo>;
}

服务模型

export interface ServiceInfo {
  [...]
  userFamilyName: string;
  userGivenName: string;
  userLanguages: Language[];
}

export interface Service {
  _id: ID;
  [...]
  serviceInfo: Partial<ServiceInfo>;
}

以我的方式

private addLanguage(languageForm: FormGroup) {

  [...]

  this.usersService.addLanguage(user).pipe(
    takeUntil(this.ngUnsubscribe)
  ).subscribe(
    (entity: User) => {
      if (entity.userInfo.services) {
        entity.userInfo.services.forEach(serviceId => {
          const service = createService({
            _id: serviceId,
            serviceInfo: {
              userLanguages: [language]
            }
          });

          this.servicesService.addLanguage(service); <--- have also a subscribe in its method
        })
      }

      languageForm.reset();
      this.onNavigateBack();
    }
  );
}

在服务中

addLanguage(service: Service) {
  const url = `${this.servicesUrl}/${service._id}/languages`;
  const accessToken = this.authQuery.getSnapshot().accessToken;
  this.http.post<Service>(url, service, {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': accessToken
    })
  }).subscribe(
    (entity: Service) => {
      if (this.servicesQuery.hasEntity(service._id)) {
        this.servicesStore.update(service._id, entity);
      }
    }
  );
}

到目前为止我尝试过的事情:

this.usersService.addLanguage(user).pipe(
  filter((entity: User) => entity.userInfo.services !== undefined),
  switchMap((entity: User) => {
    entity.userInfo.services.forEach(serviceId => {
      const service = createService({
        _id: serviceId,
        serviceInfo: {
          userLanguages: [language]
        }
      });

      return this.servicesService.addLanguage(service);
    })
  }
);

但是我因为entity.userInfo.services.forEach而陷于困境。

有办法吗?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

每当您在服务内部看到订阅时,代码可能就有问题。您将需要使用.tap()进行一些副作用处理。永远不要订阅服务,让组件处理订阅。

在使用中:

addLanguage(service: Service) {
    const url = `${this.servicesUrl}/${service._id}/languages`;
    const accessToken = this.authQuery.getSnapshot().accessToken;
    this.http.post<Service>(url, service, {
        headers: new HttpHeaders({
            'Content-Type': 'application/json',
            'Authorization': accessToken
        })
    })
        .pipe(
            tap((entity: Service) => {
                if (this.servicesQuery.hasEntity(service._id)) {
                    this.servicesStore.update(service._id, entity);
                }
            })
        );
}

不过,在组件中,您可以使用filter()中的switchMap()rxjs轻松实现这一目标。 forEach的窍门是,您使用本机Javascript数组函数中的.map()。创建了此类Observable数组之后,可以使用forkJoin()组合它们并使其并行触发:

在组件中:

private addLanguage(languageForm: FormGroup) {
    this.usersService.addLanguage(user).pipe(
        takeUntil(this.ngUnsubscribe),
        //filter away the conditions  
        filter((entity: User) => entity.userInfo.services),
        switchMap((entity: User) => {
            //use .map() to create an array of services.
            let serviceObs$ = entity.UserInfo.services.map(serviceId =>
                this.servicesService.addLanguage(createService({
                    _id: serviceId,
                    serviceInfo: {
                        userLanguages: [language]
                    }
                })));
            //use forkJoin to combine all of them
            return forkJoin(serviceObs$);
        })
    ).subscribe(() => {
            languageForm.reset();
            this.onNavigateBack();
        }
    );
}