Search code examples
angulartypescriptpromiseresolve

data passed with resolve(x) is received as undefined


I am trying to pass a url that I get from the function getDownloadURL() below, it is near the bottom of the code. Everything on this side of the problem seems to be working - except it seems that the resolve might not be working correctly:

// Return a promise to catch errors while loading image
  getMediaFormulas(options, square): Promise<any> {

    // Get Image from ionic-native's built in camera plugin
    return this.camera.getPicture(options)
      .then((fileUri) => {

        // op Image, on android this returns something like, '/storage/emulated/0/Android/...'
        // Only giving an android example as ionic-native camera has built in cropping ability
        if (this.platform.is('ios')) {

          return this.crop.crop(fileUri, { quality: 2 });
        } else if (this.platform.is('android')) {
          // Modify fileUri format, may not always be necessary
          fileUri = 'file://' + fileUri;

          /* Using cordova-plugin-crop starts here */
          return this.crop.crop(fileUri, { quality: 2 });
        }
      })
      .then(newPath => {
        console.log(newPath);
        if(newPath) {
        let fileName = newPath.substring(newPath.lastIndexOf("/") + 1, newPath.length);
        let filePath = newPath.substring(0, newPath.lastIndexOf("/"));
        this.file.readAsDataURL(filePath, fileName).then(data =>{
          console.log("IN READASDATAURL GETMEDIAFORMULAS");
          //let strImage = data.replace(/^data:image\/[a-z]+;base64,/, "");
          //this.file.writeFile(this.file.tempDirectory, "image.jpg", strImage);
          //let blob = dataURItoBlob(data);

          //let file

          //this.getFileEntryRead(this.file.tempDirectory + '/image.jpg', square);
          var dataURL = data;

          let image       : string  = 'formula_' + this.username + '_' + new Date() + '.png',
            storageRef  : any,
            parseUpload : any,
            thisUrl: any;

          return new Promise((resolve, reject) => {
            storageRef       = firebase.storage().ref('/formulas/' + this.username + '/' + image);
            parseUpload      = storageRef.putString(dataURL, 'data_url');

            parseUpload.on('state_changed', (_snapshot) => {
                // We could log the progress here IF necessary
                console.log('snapshot progess ' + _snapshot);
              },
              (_err) => {
                 reject(_err);
                 console.log(_err.messsage);
              },
              (success) => {
                storageRef.getDownloadURL().then(url => {
                  console.log(url);
                  thisUrl = url;
                  console.log("IN READASDATAURL GETMEDIAFORMULAS UERLRLRLR");

                });

                resolve(thisUrl); 
              })
            }).catch(function(error) {
              console.log(error.message);
            });


        })
        }


      });


  }

I say the resolve might not be working because on the side where the getMediaFormula is called, nothing comes back in the then function - url is undefined. It is returned in one of the selections for an actionsheet:

presentActionSheet3() {
    let actionSheet = this.actionSheetCtrl.create({
      title: 'Choose source',
      buttons: [
        {
          text: 'Camera',
          handler: () => {
            let itemArrayTwo = this.profComponents.toArray();
            this.cameraService.getMediaFormulas(this.optionsGetCamera, this.square).then((url) => {
              actionSheet.dismiss();
              this.navCtrl.push(FormulapostPage, { path: url });
            }); //pass in square choice
            //this.myrenderer.setElementAttribute(this.itemArrayTwo[this.square - 1].nativeElement, 'src', 'block');
            console.log('camera clicked');
            //actionSheet.dismiss();
          }
        },{
          text: 'Photo Library',
          handler: () => {
            let itemArrayTwo = this.profComponents.toArray();

            this.cameraService.getMediaFormulas(this.optionsGetMedia, this.square).then((url) => {
              setTimeout(() => {
                console.log(url + " url url url url")
                actionSheet.dismiss();
                this.navCtrl.push(FormulapostPage, { path: url });
              },3000);

            }); //pass in square choice
            //this.myrenderer.setElementAttribute(this.itemArrayTwo[this.square - 1].nativeElement, 'src', 'block');
            console.log('camera clicked');
            //actionSheet.dismiss();
          }
        },{
          text: 'Cancel',
          role: 'cancel',
          handler: () => {
            console.log('Cancel clicked');
          }
        }
      ]
    });
    actionSheet.present();
  }

So the problem is the then of the call to getMediaFormulas is returning and undefined url, but in the code where is retrieved, in the promise, it is created correctly and used in resolve like this resolve(thisUrl). Why is url undefined in actionsheet?


Solution

  • There are two problems with this code:

    As pointed out in my comment, you need to return the readAsDataUrl promise, eg:

    ...
    let fileName = newPath.substring(newPath.lastIndexOf("/") + 1, newPath.length);
    let filePath = newPath.substring(0, newPath.lastIndexOf("/"));
    return this.file.readAsDataURL(filePath, fileName).then(data =>{
          console.log("IN READASDATAURL GETMEDIAFORMULAS");
          ...
    

    And additionally as pointed out by @trincot, the resolve is in the wrong scope, and should be one level higher, eg:

    ...
    (success) => {
        storageRef.getDownloadURL().then(url => {
        console.log(url);
        thisUrl = url;
        console.log("IN READASDATAURL GETMEDIAFORMULAS UERLRLRLR");
    
        // Should be here, not outside of this then. Though as you mentioned it my have only been outside due to your testing
        resolve(thisUrl);
    });
    ...