I have the following code:
public upload(): void {
const fileinput = document.getElementById('file');
fileinput.click();
fileinput.addEventListener('change', this.handleFileInput.bind(this));
}
private handleFileInput(event) {
try {
const input = event.target as HTMLInputElement;
const reader = new FileReader();
const { objectId } = this.object;
const file = input.files[0];
reader.onload = () => {
event.target.value = null;
this.objectDetailsService
.upload(file, objectId)
.subscribe(
() => //,
() => //,
);
};
reader.readAsArrayBuffer(file);
} catch (e) {
console.log(e);
}
}
I should allow to load the same file sometimes. When user select another this code create as new stream. How to avoid it?
CodePudding user response:
You're right in asking how to apply switchMap
. One way is to create an observable to handle the async callback onload
. Then you could apply operators like switchMap
to call other async functions.
Also I'd suggest attaching the event handler directly in the template instead of using document.getElementById('file');
in the controller.
Try the following
*.ts
import { Observable, Observer, timer } from 'rxjs';
import { switchMap } from 'rxjs/operators';
public handleFileInput(event) {
const input = event.target as HTMLInputElement;
const file = input.files[0];
this.readFile(file).pipe(
switchMap((file: any) => {
const { objectId } = this.object;
return this.objectDetailsService.upload(file, objectId);
})
).subscribe({
next: () => console.log('File uploaded'),
error: (error: any) => console.log('Error:', error),
});
}
readFile(file): Observable<any> {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
return new Observable((observer: Observer<any>) => {
reader.onload = (ev: ProgressEvent) => {
observer.next(file);
observer.complete();
};
reader.onerror = (error: any) => {
observer.error(error);
};
});
}
*.html
Select file: <input type="file" (change)="handleFileInput($event)" />
Working example: Stackblitz