我正在开发一个4.4.4角应用程序,商家可以向客户赠送积分;为此,我给了httpclient srevice调用(为此我使用cancateMap
虽然不知道该使用什么)。
我有多个商家,所有人都可以给用户点数,所以我想按顺序为每个商家(一个接一个)调用httpClient req。作为回应我想显示点数增加,如计数器和加载栏,同时添加点数。例如**
如果星巴克增加20分,那么在回应视图中应该显示积分 递增到20,并且将显示行列式加载器直到它 完成100%。我想为每个请求显示此信息
对于装载机我使用材料决定性装载机 **: 以下是我的组件代码
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { SharedService } from '../services/shared.service';
import { CommonService } from '../services/common.service';
import { Observable } from 'rxjs/Rx';
@Component({
selector: 'app-dashboard',
templateUrl: './onboarding.component.html',
styleUrls: ['./onboarding.component.scss']
})
export class DashboardComponent implements OnInit {
public merchantsList: Object[];
public points: number = 0;
public counter: number = 0;
public merchantName: string;
public percentage: number;
constructor(private router: Router, private commonService: CommonService, private sharedService: SharedService) { }
ngOnInit() {
this.merchantsList = this.sharedService.getMerchants();
this.transferPoints();
}
transferPoints() {
let data = {
"points": 20,
"issueToPartyName": "O=User1,L=New York,C=US",
"issuerBankPartyRef": "1"
};
Observable.of(...this.merchantsList)
.concatMap((merchant: Object) => {
return this.commonService.getAllMerchatPoints(merchant, data).map((res) => {
return res
});
}).subscribe((res) => {
let timer = Observable.interval(200).subscribe(() => {
this.merchantName = res.initiator;
this.points++;
this.counter++;
this.percentage = (this.counter / 20) * 100;
if (this.percentage === 100) {
timer.unsubscribe();
this.percentage = 0;
this.counter = 0;
}
});
});
}
}
transferPoints()是我调用的方法,使用concateMap给出顺序http调用,然后在其订阅中我获得积分转移和商家名称:
HTML是:
<div class="mobile-img">
<div class="home-card flex-container flex-col-direction flex-center-center">
<div>
<img class="icon" src="assets/images/user-big.png" />
</div>
<div>
<div class="amount">{{points}}</div>
<div class="subtext">Points</div>
</div>
<div class="state">Fetching your reward points...</div>
<div class="vendor">{{merchantName|| 'Uber'}}</div>
<mat-progress-bar mode="determinate" value="{{percentage}}"></mat-progress-bar>
</div>
</div>
和服务代码是:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHandler, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { LoaderService } from './loader.service';
interface NodeResponse {
name: string;
nodeName: string;
nodeType: string;
port: number;
initiator?:string;
}
@Injectable()
export class CommonService extends HttpClient {
private contextPath = "url";
constructor(private http: HttpClient, public httpHandler: HttpHandler, public loaderService: LoaderService) {
}
getAllNodes(): Observable<NodeResponse[]> {
return this.http.get<NodeResponse[]>(`${this.contextPath}:10007/api/transferpoints/getAllNodesInfo`);
}
getAllMerchatPoints(merchant, data): Observable<NodeResponse> {
return this.http.put<NodeResponse>(`${this.contextPath}:${merchant.port}/api/transferpoints/issueandtransfer`, data);
}
}
getAllMerchatPoints是我正在调用的服务
问题是我无法顺序从每个请求中获取数据。我的意思是当与星巴克相关的http req完成时,我想增加点并显示像其取点一样的加载;在完成星巴克需求之后,优步应该开火并进一步想要增加积分并显示像其取点一样的加载。
我在下面尝试过订阅;使用间隔,因为我想显示加载器移动到结束;但它不能正常工作。
let timer = Observable.interval(200).subscribe(() => {
this.merchantName = res.initiator;
this.points++;
this.counter++;
this.percentage = (this.counter / 20) * 100;
if (this.percentage === 100) {
timer.unsubscribe();
this.percentage = 0;
this.counter = 0;
}
});
我使用正确的操作员吗? concateMap?有没有其他方法可以实现上述目标?
答案 0 :(得分:1)
映射运算符
在您的应用中使用concatMap
vs flatMap
取决于您是否要保留商家的订单。
记住http是异步的,因此有些呼叫可能比其他呼叫响应更快。 concatMap
保留原始排序,而flatMap
会在响应到达后立即发出。
否则,他们都做同样的工作 - 解开内在的观察者。
计时器
虽然技术上定时器代码没有任何问题,但我认为这让图片混乱。基本上,http响应不会顺利到达,所以除非你知道响应总是花费不到200毫秒,否则你不能指望这个定时器以200毫秒的间隔发出。
Observable.of(... this.merchantsList).concatMap(
的结果无法顺序从每个请求中获取数据
您解释了您想要获得的内容,但不是您 获得的内容。我不明白为什么你不会得到顺序结果,特别是使用concatMap
。
尝试注释掉计时器代码并输入console.log(res)
以查看您获得的回复顺序。
..所以两个间隔同时运行,因为它们是异步的! 想知道有没有办法顺序运行间隔
所以,我认为外部订阅中的这个块
let timer = Observable.interval(200).subscribe(() => {
...
}
快速运行并返回下一个商家回复。内部订阅独立运行(正如您所说的异步)。没有那个间隔包装器,内部部件将同步运行,一切都将按顺序进行。但我想你想要一个小的延迟来获得正确的屏幕效果。
也许你需要在订阅之外而不是在内部的时间间隔,比如这个
}).delay(200).subscribe((res) => {
使用combineLatest()
这是我迄今为止采用这种方法的原因。
const merchantPoints$ = Observable.of(...this.merchantsList)
.concatMap((merchant: Object) => {
return this.commonService.getAllMerchatPoints(merchant, data).map((res) => {
return res
});
});
const timer$ = Observable.interval(200);
Observable.combineLatest(merchantPoints$, timer$)
.subscribe(combined => {
const res = combined[0];
this.merchantName = res.initiator;
this.points++;
this.counter++;
this.percentage = (this.counter / 20) * 100;
if (this.percentage === 100) {
// timer.unsubscribe();
this.percentage = 0;
this.counter = 0;
}
});