如果我必须提供更多代码或解释,请告诉我。
我正在尝试执行验证,如果验证不成功,请确认(是/否),然后在 for 循环中为所有选定行保存方法。
要求:我在遍历所有选定行后显示成功/失败消息。这意味着:
如果选择了 5 行(2 行有效,3 行无效) - 从 myService.validate 获取
它会询问您是否仍要继续处理 3 个无效的记录 - myConfirmService.confirm
它应该保存那 2 条有效记录
如果用户在确认窗口中选择“是”(假设有 2 条记录),那么它也应该保存这 2 条记录。
最后 - 它将显示成功/失败消息 - alertService.success
我想要的:
为了满足我在需求中描述的内容
并且成功/失败消息应在所有记录保存后仅显示一次
component.ts:
save() {
this.selectRowData.forEach(async s => {
this.myService.validate(s.id).subscribe(data => {
console.log(data);
if(data == false) {
this.myConfirmService
.confirm('Please confirm..', 'Selected Part do not match expected part data. \n Do you still want to continue? ', 'Yes', 'No')
.then((confirmed) => {
if(confirmed) {
console.log("User selected: Yes");
this.myService.savePart();
} else {
console.log("User selected: No");
}
})
.catch(() => {
console.log("Error...");
});
} else {
console.log("Selected Rule matches expected rules for: " + s.designChangeClass);
this.saveModelPart(s);
}
}, (error: any) => {
alert("Error Linking Lot");
});
});
console.log('1st After for loop');
this.alertService.success('Part saved successfully.')
}
service.ts
validate(id: string): Observable < boolean > {
return this.httpClient.get < boolean > ('/RestWeb/validate?id=' + id);
}
validate1(id: string) {
return this.httpClient.get < boolean > ('/RestWeb/validate?id=' + id).toPromise();
}
savePart(item: Part): Observable<any> {
return this.httpClient.post('/RestService/savePart', item);
}
答案 0 :(得分:3)
给你。
//Change method to async
async save() {
//Create custom index variable, since for of loop doesn't have one
let ind = 0;
//Use for of instead of forEach
for (const eachRow of this.selectRowData) {
//await until API validated
const isValid = await this.myService.validate(eachRow.id).toPromise();
if (!isValid) {
//await again if it is not valid and until user confirmed
const isConfirmed = await this.myConfirmService.confirm('Please confirm..', 'Selected Part do not match expected part data. \n Do you still want to continue? ', 'Yes', 'No').toPromise();
if (isConfirmed) {
//await again until record saved as user selected yes in confirm
console.log('User selected: Yes');
await this.myService.savePart().toPromise();
} else {
console.log('User selected: No');
}
} else {
console.log(
'Selected Rule matches expected rules for: ' +
eachRow.designChangeClass
);
this.saveModelPart(eachRow);
}
//Finally display message after loop is finished
if (ind === this.selectRowData.length - 1) {
this.alertService.success('Part saved successfully.');
}
ind++;
}
}
尽管此解决方案有效,但以这种方式进行操作并不是一个好习惯,
相反,修改 API 以接受多个 ids
进行验证,并显示一个记录表(成功和失败)以及用于确认继续的按钮。
答案 1 :(得分:1)
在这种情况下,您可以使用 fork join,因此它会进行所有调用并获得对布尔数组的响应
save() {
let obsArray = this.selectRowData.map(s=>this.myService.validate(s.id));
forkJoin(obsArray).subscribe(
(arrayBoolean)=>{
// do your logic here
}
)
}
查看https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin了解更多信息
//编辑:拼写错误
答案 2 :(得分:0)
据我所知,您试图仅保存有效数据并额外进行用户确认。 One Part 有点令人困惑,因为您正在尝试确认与预期规则不匹配的有效数据,但除此之外,我会做这样的事情。
组件方法:
IAmazonSecurityTokenService stsClient = new AmazonSecurityTokenServiceClient();
string accountId=stsClient.GetCallerIdentityAsync(new GetCallerIdentityRequest()).Result.Account;
确认服务方式:
rowValidation() {
this.selectRowData.forEach( rowElement => {
this.myService.validate(rowElement.id).subscribe( data => {
//call comfirm service method.
})
})
}
答案 3 :(得分:0)
好吧朋友……你的逻辑实际上有点复杂,所以如果我们把它分解成更小的部分会更容易理解。
如果我正确理解您的要求,您需要:
从终点开始,我们可以这样做:
save() {
of(this.selectRowData).pipe(
switchMap(this.validateRows),
switchMap(rows => this.promptUserIfSomeInvalid(rows).pipe(
switchMap(saveInvalidRows => {
const rowsToSave = saveInvalidRows ? rows : rows.filter(r => r.isValid);
return forkJoin(rowsToSave.map(this.myService.savePart));
})
))
).subscribe();
}
这里我们以 of
开始 observable 链。
您可能已经注意到所有的switchMap
!!!如果您不熟悉,switchMap
是一个漂亮的操作符,它会为您订阅一个 observable,并发出它的排放。它还负责自动取消订阅这个“内部可观察对象”。
您需要了解的有关 switchMap
的信息:
在 switchMap
中,您传递一个返回 observable 的函数。
第一个 switchMap
接收行数据并订阅一个调用验证 observable 的 observable。 this.validateRows
返回一个发出行数组的 observable,每个行都有一个额外的布尔属性,指示该行的验证是否通过。
switchMap
#2 订阅一个 observable,它发出一个布尔值,指示是否应该保存无效行。
switchMap
#3 订阅一个 observable,它使您的所有 api 调用都保存适当的行。
forkJoin
创建一个 observable,当它的源 observable 数组全部完成时发出。因此,我们只是将行map
ping 到可观察对象 (this.myService.savePart()
)。
以下是上述方法的实现:
private validateRows(rows: Row[]) {
return forkJoin(rows.map(row => this.myService.validate(row.id))).pipe(
map(this.appendIsValidFieldToRows(rows)),
);
}
private promptUserIfSomeInvalid(rows: ValidatedRow[]) {
const invalidCount = rows.filter(r => !r.isValid).length;
const message = `Would you like to save ${invalidCount} rows?`;
return rows.some(r => !r.isValid)
? from(this.myConfirmService.confirm(message))
: of(true);
}
private appendIsValidFieldToRows(rows: Row[]) {
return (isValidArray: boolean[]) => rows.map((r, i) => ({...r, isValid: isValidArray[i]})) as ValidatedRow[];
}
这是一个 Non-Functional StackBlitz,我用它作为便笺簿来避免打字错误。它可能有助于查看类型甚至将一些虚假数据放入测试中。
我不能 100% 确定我理解您的确切意图,但我希望这能让您朝着正确的方向前进。
主要内容是:
switchMap
避免嵌套订阅。forEach
循环,而是使用 Array.prototype.map
将行数组转换为 Observable 数组,然后您可以将其传递给 forkJoin
注意:我忽略了您的错误捕获,因为这个答案很长而且问题并没有真正关注这一方面。但是,由于逻辑分解为单独的函数,因此可以轻松地在必要的位置添加 catchError
。