angular - Ejecutar código después de ejecutar todo el bucle for
Por favor, avísame si tengo que proporcionar más código o explicaciones.
Estoy intentando ejecutar validate, si la validación no es exitosa, confirm(Yes/No), y luego guardar el método para todas las filas seleccionadas en un bucle for.
Requisito: Debo mostrar un mensaje de éxito/fracaso después de recorrer todas las filas seleccionadas. Eso significa:
Si se seleccionan 5 filas (2 son válidas y 3 no son válidas) - obtenido de myService.validate
Preguntará si aún deseas continuar con 3 registros no válidos - myConfirmService.confirm
Debería guardar esos 2 registros válidos
Si el usuario selecciona 'Sí' en la ventana de confirmación (digamos para 2 registros), entonces también debería guardar estos 2.
Al final, mostrará un mensaje de éxito/fracaso - alertService.success
Lo que quiero:
Para cumplir con lo que describí en el requisito
y el mensaje de éxito/fracaso debería mostrarse solo una vez después de que se guarden todos los registros
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);
}
Respuesta #1
Aquí tienes.
//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++;
}
}
Aunque esta solución funciona, no es una buena práctica hacerlo de esta manera.
En su lugar, modifique la API para aceptar múltiples ids para validación y muestre una tabla de registros (éxitos y fallos) junto con botones para confirmar la continuación.
Respuesta #2
Podrías usar fork join en este caso, así realiza todas las llamadas y obtiene la respuesta en un arreglo de booleanos
save() {
let obsArray = this.selectRowData.map(s=>this.myService.validate(s.id));
forkJoin(obsArray).subscribe(
(arrayBoolean)=>{
// do your logic here
}
)
}
Consulta https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin para más información
//EDITAR: escrito incorrectamente
