我尝试通过两个订阅(方法中的一个,服务中的一个)重构下面的代码,但我找不到解决方法。
我正在使用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
而陷于困境。
有办法吗?
感谢您的帮助。
答案 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();
}
);
}