我订阅了异步step-api调用。当api调用正在进行时,我想显示加载动画。通过访问UI创建流时,它可以很容易done:
Rx.Observable
.combineLatest(page$, sorting$)
.switchMap(function(args) {
var page = args[0];
var sorting = args[1];
$('.overlay').show();
return loadData(page, sorting);
})
.subscribe(function(data) {
renderData(data);
$('.overlay').hide();
});
但是当我将流管理代码移动到service时(例如代码重用),跟踪异步操作的能力就会丢失,我无法显示加载动画。
有什么想法可以做到吗?从服务中返回两个流?
提前致谢。
答案 0 :(得分:2)
为什么不创建包含多个“事件”的流 - started
和finished
,如下所示:
function loadDataWithStartEvent($page, sorting$) {
return Rx.Observable
.combineLatest(page$, sorting$)
.flatMap(args => {
var page = args[0];
var sorting = args[1];
return Rx.Observable.just({ event : 'started' })
.concat(
// given that loadData returns an Observable<data> which only emits data one time
loadData(pageSortingTuple.page, pageSortingTuple.sorting))
.map(data => ({ event: 'finished', data: data}))
);
});
}
现在订阅如下:
loadDataWithStartEvent(page$, sorting$)
.doOnNext(evt => {
if(evt.type == 'started') {
$('overlay').show();
} else {
$('overlay').hide();
}
})
.filter(evt => evt.type === 'finished')
.map(evt => evt.data);
.subscribe(data => renderData(data));
答案 1 :(得分:1)
您可以将额外的通知对象传递给setupLoading
:
setupLoading: function(page$, sorting$, notify$) {
return Rx.Observable
.combineLatest(page$, sorting$)
.switchMap(function(args) {
notify$.next(true); // here we go...
var page = args[0];
var sorting = args[1];
return loadData(page, sorting);
});
}
然后创建,除了page$
和sorting$
以及loadStarted$
可观察的。
loadStarted$.subscribe(() => $('.overlay').hide();
你的装载机创建将是:
service.setupLoading(page$, sorting$, loadStarted$)
.subscribe(function(data) {
renderData(data);
});
});
顺便说一句,因为你很好地使用rxjs,为什么不将它用于show / hide - angular2方式 - 并放弃jquery:
<div class="overlay" [style.display]="(showOverlay ? 'block' : 'none')>your overlay content here</div>
答案 2 :(得分:0)
最终我最终使用了自定义运算符:
class RequestState {
loading: boolean;
}
Observable.prototype.captureState = function captureState<T>(this: Observable<T>, state: RequestState): Observable<T> {
state.loading = true;
let onLoadingEnd = () => {
state.loading = false;
};
obs = obs.do(onLoadingEnd, onLoadingEnd, onLoadingEnd);
return obs;
};
class Component {
requestState = new RequestState();
ngOnInit() {
this.api.endpoint(query)
.captureState(this.requestState)
.subscribe(...);
}
}