I have an array of objects of the following type.
processing-details.model.ts
export class ProcessingDetails{
id: string;
isProcessingOccured: boolean;
isProcessingSuccessful:boolean;
constructor(id,isProcessingOccured,isProcessingSuccessful) {
this.id = id;
this.isProcessingOccured = isProcessingOccured;
this.isProcessingSuccessful = isProcessingSuccessful;
}
}
The array is dynamically generated based on certain inputs. Once the array is generated, it looks as follows.
processingArray = [{id:1, isProcessingOccured: false, isProcessingSuccessful: false},
{id:2, isProcessingOccured: false, isProcessingSuccessful: false},
.....
{id:k, isProcessingOccured: false, isProcessingSuccessful: false}]
I have a REST end point which takes an object of type ProcessingDetails. The following is my service code.
automated-batch.service.ts
@Injectable()
export class AutomatedBatchService {
constructor(@Inject('baseUrl') private baseUrl: string, private httpClient: HttpClient) {}
public triggerProcessing(batchDetails:ProcessingDetails) {
return this.httpClient.post(`${this.baseUrl}`,batchDetails);
}
}
My goal is to call triggerProcessing
for each element of processingArray
in a synchronous manner. If triggerProcessing
is called on one object of processingArray
we set isProcessingOccured
on that particular object as true
. If the back end returns a success for the triggerProcessing
call we made on the object, then we set isProcessingSuccessful
to true
. For example, let us assume processing was successful for id = 1 and id = 2. The array must look like follows:
processingArray = [{id:1, isProcessingOccured: true, isProcessingSuccessful: true},
{id:2, isProcessingOccured: true, isProcessingSuccessful: true},
{id: 3, isProcessingOccured: false, isProcessingSuccessful:false }
.....
{id:k, isProcessingOccured: false, isProcessingSuccessful: false}]
If the processing for one object fails, we must not process the remainder of the array. For example, if processing fails for object {id: 3, isProcessingOccured: false, isProcessingSuccessful:false }
, we must not trigger the service call from {id: 4, isProcessingOccured: false, isProcessingSuccessful:false }
onwards.
I am currently using async/await
to achieve this. Following is my code
processing-test.component.ts
import { Component } from "@angular/core";
@Component({
selector: 'processing-test',
templateUrl: './processing-test.component.html',
styleUrls:['./processing-test.component.css'],
providers: [AutomatedBatchService]
})
export class ProcessingTestComponent {
constructor(private automatedBatchService: AutomatedBatchService) { }
public isSuccess:boolean = true;
public processingArray: Array<ProcessingDetails>= [];
async startBatchRun() {
for( var i = 0; i < this.processingArray.length; i++ ) {
if(this.isSuccess){
await this.automatedBatchService.triggerProcessing(this.processingArray[i])
.toPromise()
.then(res => {
this.processingArray[i].isProcessingOccured = true
this.processingArray[i].isProcessingSuccessful = true
})
.catch(rej => {
this.isSuccess = false
this.processingArray[i].isProcessingOccured = true
this.processingArray[i].isProcessingSuccessful = false
});
}else {
break;
}
}
}
}
Is this the best way to achieve this? Is there any way where I can completely avoid using Promises
, async/await
and achieve the same synchronous call using Observables
?
You could use a combination of concat
, catchError
and finalize
to process your requests in order and stop as soon as an error occurs:
public process(batch: ProcessingDetails[]) {
const processes = batch.map(details => this.httpClient.post(`${this.baseUrl}`, batchDetails).pipe(
map(() => {
details.isProcessingSuccessful = true;
return batch;
}),
catchError(() => {
details.isProcessingSuccessful = false;
return throwError(false);
}),
finalize(() => {
details.isProcessingOccured = true;
}),
));
return concat(...processes);
}