Reputation: 1933
I have a problem and I can not find a solution because I do not know RxJs well.
I created a file
input where the user must choose an XLSX
file (A spreadsheet) to be able to import data into the database.
When the user validates his file, several checks are made on the document before insertion to avoid any problem.
The file is scanned and checked line by line. But one of my verifications is a problem.
I have to use a database procedure to check the existence of the data in the database.
The problem is that my query returns an observer,
and so my for
loop traverses my entire file even before the result of the request is received. The console shows me 'Import finish' before checking.
I would like to know if it's possible to wait for a result of the subscibe before continuing the loop or to complete the loop and once all the results are obtained, complete the import.
Component:
importObjectives(): void {
if (this.file) {
if (["xlsx","xls","csv"].includes(this.file.name.split('.').pop())) {
if (typeof (FileReader) !== 'undefined') {
const reader = new FileReader();
reader.onload = (e: any) => {
let u8 = new Uint8Array(e.target.result);
let wb: XLSX.WorkBook = XLSX.read(u8, { type: 'array' });
let wsname: string = wb.SheetNames[0];
let ws: XLSX.WorkSheet = wb.Sheets[wsname];
let xlsData = XLSX.utils.sheet_to_json(ws, { header: 1 });
xlsData.shift();
for(var row of xlsData) {
var lineError = xlsData.indexOf(row) + 2;
// Other checks...
// --- Problem here ---
this.storeWallets.checkWallets(this.XLSXObjective, lineError).subscribe(wallet => { ... })
}
if(this.errors.length > 0) {
console.error("Errors:");
console.error(this.errors);
} else {
console.log("Import finish");
}
this.dialogRef.close();
};
reader.readAsArrayBuffer(this.file);
}
} else {
console.error("Incompatible file");
this.dialogRef.close();
}
} else {
console.error("No file");
this.dialogRef.close();
}
}
Store Wallet:
checkWallets(xlsx: XLSXObjective, lineError): Observable<any> {
const obs = this.walletService.checkWallets(xlsx).pipe(share());
obs.subscribe(wallets => { ... });
return obs;
}
Service Wallet:
checkWallets(xlsx: XLSXObjective): Observable<any> {
var customError: string = 'ERREUR';
return this.http.put<Wallet[]>('/api/wallet/CheckWallets', xlsx)
.pipe(catchError(this.error.handleError<any>(customError)));
}
Thank you for your help and sorry for my english.
Upvotes: 0
Views: 162
Reputation: 1933
My solution:
private observables$ = [];
importObjectives(): void {
if (this.file) {
if (["xlsx","xls","csv"].includes(this.file.name.split('.').pop())) {
if (typeof (FileReader) !== 'undefined') {
const reader = new FileReader();
reader.onload = (e: any) => {
let u8 = new Uint8Array(e.target.result);
let wb: XLSX.WorkBook = XLSX.read(u8, { type: 'array' });
let wsname: string = wb.SheetNames[0];
let ws: XLSX.WorkSheet = wb.Sheets[wsname];
let xlsData = XLSX.utils.sheet_to_json(ws, { header: 1 });
xlsData.shift();
for(var row of xlsData) {
var lineError = xlsData.indexOf(row) + 2;
// Other checks...
this.observables$.push(this.storeWallets.checkWallets(this.XLSXObjective, lineError))
}
forkJoin(this.observables$).subscribe(results => {
if(this.errors.length > 0) {
console.error("Errors:");
console.error(this.errors);
} else {
console.log("Import finish");
}
}
this.dialogRef.close();
};
reader.readAsArrayBuffer(this.file);
}
} else {
console.error("Incompatible file");
this.dialogRef.close();
}
} else {
console.error("No file");
this.dialogRef.close();
}
}
Upvotes: 0
Reputation: 336
You can use Observable.forkJoin
where you make the loop for observables. That is his purpose.
Observable.forkJoin
allows you to wait for all observables to have received data.
I`m not sure what your HTTP calls are returnig, so here is an simple example:
loadedCharacter: {};
constructor(private http: HttpClient) { }
ngOnInit() {
let character = this.http.get('https://swapi.co/api/people/1');
let characterHomeworld = this.http.get('http://swapi.co/api/planets/1');
forkJoin([character, characterHomeworld]).subscribe(results => {
// results[0] is our character
// results[1] is our character homeworld
results[0].homeworld = results[1];
this.loadedCharacter = results[0];
});
Upvotes: 1