ngOnInit(): void {
this.store.dispatch(new patients.Load([]));
this.patients$ = this.store.select(fromPatients.getAll);
this.patients$.map(p =>{ // patients$: Observable<Patient[]>;
this.rows = p.map(pat => { //I use this on the front end
return {
username: pat.username,
id: pat.id,
hasAlert: this.hasAlerts(pat), //made this an observable for the async pipe in view
settings: "Settings"
};
});
this.table.recalculatePages();
console.log(this.rows);
console.log("This happens first");
}).subscribe();
}
hasAlerts(pat: Patient): Observable<boolean> {
var shouldAlert$ = Observable.of(false);//this value is always taken
this.observations2$ = this.dataService.fetchItems<Observation>(
"Observation",
null,
pat.id// How would i pass this in with mergeMap()?
);
this.observations2$.subscribe(curObservation => {
if (curObservation.category.coding[0].code == "GlucoseEvent"){
shouldAlert$ = Observable.of(true);
console.log("should alert$", shouldAlert$);
}
});
console.log("this happens second");
return shouldAlert$;
}
在上面的代码中,我解析了一个名为patient $的观察者,其中包含一系列患者。然后我将这些患者映射到我在客户端显示的名为this.rows的对象数组。
我的问题涉及hasAlert属性,该属性在对hasAlerts()的方法调用中处理另一个observable本身。此方法调用hasAlerts()不会同步发生,因此console.log(&#34;这首先发生&#34;);在我的hasAlerts方法可以在If语句中执行逻辑以确定它是应该设置为true还是false之前发生,而只是使用它在hasAlerts()的第一行中初始化的值。由console.log确认(&#34;这发生在第二个&#34;);显示第二。
hasAlerts()可以返回一个布尔值而不是一个可观察的,我试图看看是否可以在前端使用asycn管道来解决我的问题(它没有)。
我相信解决这个问题的方法涉及使用mergemap但是我不知道我将如何传递hasAlerts方法需要的pat.id?或者这可能不是解决当前问题的正确方法,即异步执行此代码。
我目前正在尝试使用这个this question about mergemap来解决我的问题,但是传递了第二个observable在hasAlerts中的pat.id我还没有想到。 1
按照Piccis的想法更新了代码。
this.patients$.map(p =>{ // patients$: Observable<Patient[]>;
this.rows = p.map(pat => { //I use this on the front end
return {
username: pat.username,
id: pat.id,
hasAlert: false, //set the default value
settings: "Settings"
};
})
}).do(data => console.log("data1",data))
// .switchMap(p => Observable.from(p))
// .do(data => console.log("data2",data)) // creates a stream of Observable<Patient>
// .mergeMap(patient => this.dataService.fetchItems<Observation>(
// "Observation",
// null,
// "pat..frank"//patient[0].id//"pat..frank"//patient.id// patient should be your guy
// )
// .map(curObservation => {
// console.log("currOBS",curObservation);
// if (curObservation.category.coding[0].code == "GlucoseEvent"){
// var shouldAlert$ = true;
// console.log("should alert$", shouldAlert$);
// }
// })
// ).do(data => console.log(data))
// .toArray()
.subscribe(
patients => {
this.table.recalculatePages();
console.log(this.rows);
}
)
Data1返回一组患者。我需要在中间注释掉,因为switchmap行有一个语法错误说&#34;类型的论证&#39; void&#39;不能分配给类型参数&#39; ArrayLike&lt; {}&gt;&#39;&#39;&#34;
答案 0 :(得分:1)
您正在使用mergeMap
查找正确的方向,但您需要重新编写代码。
您从this.patients$
开始,这是一个Observable。
从这里你需要创建一个Observable流。这可以使用Observable的静态方法from
来完成。
现在,您可以管理每位患者并通过服务curObservation
获取他/她fetchItems
。
最终重新创建数组,然后订阅。
最终结果可能看起来像这些行
ngOnInit(): void {
this.store.dispatch(new patients.Load([]));
this.patients$ = this.store.select(fromPatients.getAll);
this.patients$.map(p =>{ // patients$: Observable<Patient[]>;
this.rows = p.map(pat => { //I use this on the front end
return {
username: pat.username,
id: pat.id,
hasAlert: false, //set the default value
settings: "Settings"
};
});
})
.do(data => consoel.log(data)) // check whether data is an array of Patients as it is supposed to be
.switchMap(p => Observable.from(p)) // creates a stream of Observable<Patient>
.do(data => console.log(data)) // check whether data is a single Patient
.mergeMap(patient => this.dataService.fetchItems<Observation>(
"Observation",
null,
patient.id// patient should be your guy
)
.map(curObservation => {
if (curObservation.category.coding[0].code == "GlucoseEvent"){
shouldAlert$ = true;
console.log("should alert$", shouldAlert$);
}
})
)
.toArray()
.subscribe(
patients => {
this.table.recalculatePages();
console.log(this.rows);
}
)
}
更新 - 基本机制
如果我们删除您案例的所有细节,上面代码段中实现的基本机制如下
import {Observable} from 'rxjs';
const obs1 = Observable.of([1, 2, 3, 4, 5, 6]);
obs1
.switchMap(n => Observable.from(n))
.mergeMap(n => Observable.of(n*2))
.toArray()
.subscribe(console.log)
答案 1 :(得分:1)
基本问题是组合两个异步调用,可以使用zip()
完成。
(注意,我最初使用forkJoin()
发布了一个解决方案,但这不适用于ngrx select(),因为select永远不会完成 - 因此forkJoin永远不会触发)。
将第一次获取返回的Observable<Patient[]>
转换为Observable<Patient>
,因为它对zip运算符更方便。
下一个问题是第二个异步依赖于第一个异步(pat.id)的结果 - 使用concatMap()
构建一个异步。
(注意,我最初建议mergeMap()
,但concatMap()
保证hasAlert $与患者$的排序相同。这很重要,因为this.dataService.fetchItems()
可能会无序返回个别提取物)。
import { zip } from 'rxjs/observable/zip';
...
ngOnInit(): void {
this.store.dispatch(new patients.Load([]));
const patient$ = this.store.select(fromPatients.getAll)
.mergeMap(value => value); // convert from Observable<patients[]> to Observable<patient>
const hasAlert$ = patient$.concatMap(patient => {
return this.dataService.fetchItems<Observation>('Observation' null, patient.id)
.map(curObservation => curObservation.category.coding[0].code === 'GlucoseEvent')
);
})
zip(patient$, hasAlert$) // combine values from both asyncs
.map(([patient, hasAlert]) => {
return {
username: patient.username,
id: patient.id,
hasAlert,
settings: "Settings"
};
})
.toArray()
.subscribe(rows => {
this.rows = rows;
this.table.recalculatePages();
});
}
测试答案片段的Rx逻辑。
console.clear();
const { zip, from, of } = Rx.Observable;
/* in Angular with Rxjs v5.5, use
import { zip } from 'rxjs/observable/zip';
import { from } from 'rxjs/observable/of';
import { of } from 'rxjs/observable/from';
*/
// Simulate other observables
const storeSelectFromPatientsGetAll$ = () =>
of([{id: 1, username: 'Fred'}, {id: 2, username: 'Joan'}]);
const dataServiceFetchItems$ = (type, something, id) =>
of({ category: { coding: [{code: 'GlucoseEvent'}] }})
// Testing the ngOnInit code
const patient$ = storeSelectFromPatientsGetAll$()
.mergeMap(value => value);
const hasAlert$ = patient$.concatMap(patient => {
return dataServiceFetchItems$('Observation', null, patient.id)
.map(curObservation => curObservation.category.coding[0].code === 'GlucoseEvent');
});
zip(patient$, hasAlert$) // wait for resolution of both asyncs
.map(([patient, hasAlert]) => {
return {
username: patient.username,
id: patient.id,
hasAlert,
settings: 'Settings'
};
})
.toArray()
.subscribe(rows => {
console.log(rows);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>
答案 2 :(得分:0)
这就是我能够通过不同的方法让这个逻辑为我工作的方式。我需要通过最终的角度ngrx视频和一些rxjs教程来更好地理解我在其他两个答案中出错的地方,因为提供的示例运作良好。
适用于我的方法
在hasAlerts方法中处理来自数据服务的观察值时使用过滤器,并将符合条件的任何观察值添加到该值并返回它。
将hasAlerts属性设置为false,然后为该给定患者调用hasAlerts()方法并修改该行上的该属性,然后返回该行。
ngOnInit(): void {
this.store.dispatch(new patients.Load([]));
this.patients$ = this.store.select(fromPatients.getAll);
this.patients$.map(p =>{ // patients$: Observable<Patient[]>;
this.rows = p.map(pat => { //I use this on the front end
var rowx= {
username: pat.username,
id: pat.id,
hasAlert: false, //made this an observable for the async pipe in view
settings: "Settings"
};
this.hasAlerts(pat).do(x => {
observations++;
if (observations>0)
{
rowX.hasAlert=true;
}
}).subscribe();
return rowX;
});
}).subscribe(
()=>{
},
()=>{
this.table.recalculatePages();
});
}
hasAlerts(pat: Patient): Observable<Observation> {
var obs$ = this.dataService.fetchItems<Observation>(
"Observation",
null,
pat.id
).filer(function(curObservation){
if (curObservation.category.coding[0].code == "GlucoseEvent"){
return true;
}
else{
return false;
}
});
return obs$;
}