Observable to watch an array of observables and perform an action when done?


#1

Overview:
Basically I’m trying to read all the image files from a directory and get the meta data for each file to create a thumbnail name. Once all the meta data has been grabbed I want to run another function. The catch is the function requires all the observables for file operations and metadata be complete.

My original way of getting around this problem was to check if this was the last item in the array to be processed for meta data and assuming that each observable will be finishing in the exact order they are called. Which will not always be true with Asynchronous communication, hense I need help :grinning:

I had the idea of putting the file.getMetadata operations into an array of observables and using forkjoin to check the observables array and only run the function when its done. I cant get it to work though due to my limited understanding of observables. Any help would be great!

Original code:

this.fileAccess.listDir(this.OSRootPath, this.directoryPath).then(
        (files)=>{

          for(let i = 0; i < files.length; i++){

            let fileName:string =  files[i].name.toLowerCase();

            // check if folder, if so copy its path and name
            if (files[i].isDirectory){

              this.directorySubDirectories.push({'path': files[i].nativeURL, "name": files[i].name});

            } // check if file is a image type, by checking the extensions
            else if (fileName.includes(this.jpgExtension) || fileName.includes(this.gifExtension) ||
                      fileName.includes(this.pngExtension) || fileName.includes(this.tifExtension)) {

                files[i].getMetadata((metaData)=>{

                let thumbnailName:string = this.generateThumbnailName(files[i].name, 
                  metaData);

                this.directoryImages.push({ 'name': files[i].name, 
                'path': files[i].nativeURL, 
                'thumbnailName': thumbnailName,
                'thumbnailPath': ''});

                // Here I'm checking to see if this is the last file in the array that needs to have it's meta data proccessed,
                // if so I run a fuction that will check if the thumbnails already exists or it will create a new one
                if (i == (files.length - 1)){

                  // run next function
                  this.processAllThumbnailsImages(); 
                }
              });
            }
          }
        }
      ).catch(
        (error) =>{
          console.log("ERROR Reading the directory, code below:");
          console.log(error);
        }
      );
    });
 }

Attempt at putting observables into an array:

this.fileAccess.listDir(this.OSRootPath, this.directoryPath).then(
	(files)=>{

	  // loop through each file and directory
	  for(let i = 0; i < files.length; i++){

		let fileName:string =  files[i].name.toLowerCase(); // make lowercase for extension check


		if (files[i].isDirectory ){
		  this.directorySubDirectories.push({'path': files[i].nativeURL, "name": files[i].name});

		}
		else if (fileName.includes(this.jpgExtension) || fileName.includes(this.gifExtension) ||
				  fileName.includes(this.pngExtension) || fileName.includes(this.tifExtension)) {

		  observables.push(
			Observable.of(
			 files[i].getMetadata((metaData)=>{
			  
			  let thumbnailName:string = this.generateThumbnailName(files[i].name, 
				metaData);

			  this.directoryImages.push({ 'name': files[i].name, 
			  'path': files[i].nativeURL, 
			  'thumbnailName': thumbnailName,
			  'thumbnailPath': ''});
			})));
		}
	  }
	  Observable.forkJoin(observables).subscribe(
		()=> { },
		(error)=> { console.log(error) },
		()=> this.proccessImages()
	  );
}