1

I am trying to download multiple files sequentially / with interleave. When a file has been downloaded, I would like to show a success icon next to it based on the id of the file. Since the files are big, this would allow for a simple download management and retry specific files in case of error.

I am doing something resembling this :

var finalObservable: Observable<any> = null;

for (var i = 0; i < this.files.length; i++) {
    var currentFileId = this.files[i].fileId;
    var currentObservable = this.service.getResourceObservable(this.files[i].downloadLink)
                            .map(data => {return {fileId: currentFileId, result:data}});
    if (finalObservable == null) {
        finalObservable = currentObservable;
    } else {
        finalObservable = finalObservable.merge(currentObservable);
    }
}

finalObservable.subscribe(resp => {
    this.downloadService.download(resp.result);
    for (var i = 0; i < this.files.length; i++) {
        if (this.files[i].fileId == resp.fileId)  {
            this.files[i].downloaded = true ;
        }
    }
});

What happens is that the fileId sent is always this.files[this.files.length-1].fileId. So basically, only the last file gets the downloaded = true.

I don't understand why... can you help ?

Note : I based myself on this question/answer here RxJS Observable.concat: How to know where next result came from?

Adrien Gorrell
  • 1,291
  • 3
  • 14
  • 28

1 Answers1

2

TL;DR

Try defining currentFileId with let keyword instead of var:

let currentFileId = this.files[i].fileId;

Explanation

currentFileId is defined in loop with var keyword (which defines a variable at entire function scope, regardless of block scope)

for (var i = 0; i < this.files.length; i++) {
    var currentFileId = this.files[i].fileId;
    var currentObservable = this.service.getResourceObservable(this.files[i].downloadLink)
                            .map(data => {return {fileId: currentFileId, result:data}});

On the second line of the loop body closures are created and every closure gets a reference to the same variable currentFileId. And after the loop, fileId of the last file is stored in currentFileId, and every closure uses the same value, when function is called.

A detailed explanation can be found in this answer https://stackoverflow.com/a/750506/921141

xtx
  • 4,306
  • 4
  • 28
  • 30