2

I am creating an app in which you can upload a photo, with some other data, to Firebase. The uploading part worked perfect with one picture. However I have now added a multiple-image picture (select 1 to 5 pictures) and would like my image upload function to upload the 5 pictures in stead of the 1. The image upload works with 1 image provided, so how can I rearrange my code to upload the x-amount of photos in the array?

The pictures are added in the photos array with the following data (output shown below is a console.log from the images fetched);

Array [
  Object {
    "exists": true,
    "file": "ph://8905951D-1D94-483A-8864-BBFDC4FAD202/L0/001",
    "isDirectory": false,
    "md5": "f9ebcab5aa0706847235887c1a7e4740",
    "modificationTime": 1574493667.505371,
    "size": 104533,
    "uri": "ph://8905951D-1D94-483A-8864-BBFDC4FAD202/L0/001",
  },

With this didFocus I check if the fethedImages param is set and set the photos array to the fetched images (So all the data that is shown above)

 const didFocusSubscription = props.navigation.addListener(
        'didFocus', () => {
            let fetchedImages = props.navigation.getParam('fetchedImages')
            console.log(fetchedImages)
            setPhotos(fetchedImages)
            setImageValid(true)
            calculateImageDimensions()
        }
    );

When I save the page and start dispatching the data I run the following command the uploadImage function is ran and returns an uploadurl, this is then saved later on in the dispatch function to the Firebase Database to be fetched later;

 uploadurl = await uploadImageAsync(photos)

SO the uploadImageAsync starts with the photos array forwarded. How can I make sure the function below is started for every photo.uri in the array? Can I use .map of for each for this, and in what context should I be using this? Also I am not quite sure how I can send back an array of URLs to be saved together with the rest of the information.

  async function uploadImageAsync(photos) {
        console.log('uploadImage is gestart')
        // Why are we using XMLHttpRequest? See:
        // https://github.com/expo/expo/issues/2402#issuecomment-443726662
        const blob = await new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.onload = function () {
                resolve(xhr.response);
            };
            xhr.onerror = function (e) {
                console.log(e);
                reject(new TypeError('Network request failed'));
            };
            xhr.responseType = 'blob';
            xhr.open('GET', photos, true);
            xhr.send(null);
        });

        const ref = firebase
            .storage()
            .ref()
            .child(uuid.v4());
        const snapshot = await ref.put(blob);

        // We're done with the blob, close and release it
        blob.close();

        return await snapshot.ref.getDownloadURL();

    }

==============edited because of progress with uploading====================

Once again I am a little bit further. However the image upload function is now running, and because of is being multiple images I would like to await the response of all the images before continuing.

    try {
        uploadurl = await uploadImageAsync()
        address = await getAddress(selectedLocation)
        console.log(uploadurl)
        if (!uploadurl.lenght) {
            Alert.alert('Upload error', 'Something went wrong uploading the photo, plase try again', [
                { text: 'Okay' }
            ]);
            return;
        }

        dispatch(

At this moment when I start the uploadImageAsync function. With he help of console.log I see it uploading the images, they also show up online. But while the pictures are uploading the upload url already returns with 0 and shows the Alert and stops the function.

uploadImageAsync = async () => {
    const provider = firebase.database().ref(`providers/${uid}`);
    let imagesArray = [];
    try {
        await photos.map(img => {
            let file = img.data;
            const path = "Img_" + uuid.v4();
            const ref = firebase
                .storage()
                .ref(`/${uid}/${path}`);
            ref.putString(file).then(() => {
                ref
                    .getDownloadURL()
                    .then(images => {
                        imagesArray.push({
                            uri: images
                        });
                        console.log("Out-imgArray", imagesArray);
                    })
        return imagesArray   <== this return imagesArray is fired to early and starts the rest of my upload function. 
    } catch (e) {
        console.error(e);
    }
};
MarkT
  • 97
  • 1
  • 11
  • I misunderstood u, u want to save a multi-image to firebase storage then get downloaded uri for every single one? – DevAS Nov 30 '19 at 15:58
  • The async function uploadImageAsync takes the local image file and uploads this to firestore and eventually returns the URL of the image. This URL is then stored together with the other image information into the Firebase Database. This information is used on a different page to show the image and information about the picture This works for the one picture. Now I would like to change this function to upload 5 pictures, and then return 5 image URL's to save into the database and use for viewing the images with the rest of the information. I hope this is clear for you now? – MarkT Nov 30 '19 at 21:55
  • 1
    can u check [this](https://stackoverflow.com/questions/57392582/how-to-prevent-duplicate-images-when-uploaded-to-firebase) – DevAS Nov 30 '19 at 22:55
  • Thank you DevAS, it looks like sort of the same problem I am having. Looking into this topic and trying to include the relevant parts in my code. – MarkT Dec 01 '19 at 08:35
  • Good luck, if u solve it don't forget to upvote my question there and share ur answer here – DevAS Dec 01 '19 at 09:00
  • Thank you @DevAS, I am once again a step in the right direction. The last thing I now have is that, while my images array is uploading my upload function for the rest of the data continues! So I am checking the uploadURL array (which at first is empty, so the rest stops), however over time when images are upload the array is filled. How can I overcome this? I start the image upload proces like this; uploadurl = await uploadImageAsync() Then the code; uploadImageAsync = async () => { ... try { await photos.map(img => { ... return imagesArray – MarkT Dec 07 '19 at 06:28

1 Answers1

0

So a Discord chat pointed me in the way of a promise.all function for this to work. I tried that, but opened another stack overflow topic for getting this to work.

await response of image upload before continue function

The solution for my image upload function is in the topic above;

uploadImages = () => {
    const provider = firebase.database().ref(`providers/${uid}`);
    // CHANGED: removed 'let imagesArray = [];', no longer needed

    return Promise.all(photos) // CHANGED: return the promise chain
        .then(photoarray => {
            console.log('all responses are resolved successfully');
            // take each photo, upload it and then return it's download URL
            return Promise.all(photoarray.map((photo) => { // CHANGED: used Promise.all(someArray.map(...)) idiom
              let file = photo.data;
              const path = "Img_" + uuid.v4();
              const storageRef = firebase // CHANGED: renamed 'ref' to 'storageRef'
                    .storage()
                    .ref(`/${uid}/${path}`);
              let metadata = {
                  contentType: 'image/jpeg',
              };

              // upload current photo and get it's download URL
              return storageRef.putString(file, 'base64', metadata) // CHANGED: return the promise chain
                .then(() => {
                  console.log(`${path} was uploaded successfully.`);
                  return storageRef.getDownloadURL() // CHANGED: return the promise chain
                    .then(fileUrl => ({uri: fileUrl}));
                });
            }));
        })
        .then((imagesArray) => {                       // These lines can
          console.log("Out-imgArray: ", imagesArray)   // safely be removed.
          return imagesArray;                          // They are just
        })                                             // for logging.
        .catch((err) => {
          console.error(err);
        });
};
MarkT
  • 97
  • 1
  • 11