1
votes

i'm stuck with image upload to firebase database asynchronous mecanism in my project, here's my problematic:

i have a form where user put some info, the user also need to provide 4 photo to complete the upload process.

i use firebase database & firebase storage to handle this, here's the flow :

  • user fill form1 form2 & form3 with text based info
  • user select img1 img2 img3 img4 image from his computer
  • user clic submit all 4 image upload to firebase and give me 4 download url
  • i append all previously gathered information + 4 download url in a dictionary and ship it to firebase database

so the my deal is to create and ship the dictionary only when and if the 4 photo url are set, i heard about deferred/promise concept but i see a lot of Ajax request and no one with a similar issue, here is what i have for now

$("#submit-bag").click(function () {

    var uploadDfdimg1 = function() {
        var deferred = new $.Deferred();
        var uploadTask = storageRef.child('images/' + $img1.name).put($img1);
        uploadTask.on('state_changed', function(snapshot){
        }, function(error) {
        deferred.reject(error);
        }, function() {
        var downloadURL = uploadTask.snapshot.downloadURL;
        console.log(downloadURL);
        url1 = downloadURL;
        deferred.resolve(downloadURL);

        return deferred.promise();
        });
    }
    var uploadDfdimg2 = function() {
        var deferred = new $.Deferred();
        var uploadTask = storageRef.child('images/' + $img2.name).put($img2);
        uploadTask.on('state_changed', function(snapshot){
        }, function(error) {
        deferred.reject(error);
        }, function() {
        var downloadURL = uploadTask.snapshot.downloadURL;
        console.log(downloadURL);
        url2 = downloadURL;
        deferred.resolve(downloadURL);

        return deferred.promise();
        });
    }
    $.when(uploadDfdimg1,uploadDfdimg2).then(
        function(){console.log('double trouble success')},
        function(){console.log(url1 + " deferred")},
        function(){console.log(url2 + " deferred")});


    var brand = $("#select1 option:selected").text()
    var mail = document.getElementById('form1').value
    var postal_code = document.getElementById('form2').value
    var comment = document.getElementById('comment').value
    //UPLOAD IMG

    //uploadImg(img1,url1);
    //uploadImg(img2,url2);
    uploadImg(img3,url3);
    uploadImg(img4,url4);

    //console.log(url1);
    //console.log(url2);
    console.log(url3);
    console.log(url4);
    //PHOTO LINK VAR
    var postData = {
        marque: brand,
        email: mail,
        code_postal: postal_code,
        commentaire: comment,
        //PHOTO LINK
        validation: 0
    };
    var newPostKey = firebase.database().ref().child('submission').push().key;
    var updates = {};
    updates['/submission/' + newPostKey] = postData;
    firebase.database().ref().update(updates)

like you can see here, img3 & img4 upload themselves using the old non fonctionnal manner (downloadUrl come after the all dictionary PostData is send)

for img1 & img2 i tryed to use Deferred to see if i can get the 2 url at the same time when $.when.().then fired, normally after the success promise of the two uploadDfdimg function

the result is, i instantly get the "double trouble" log message with empty url variable, and normally after a second, the two url returned by firebase for img3 and img4

return log of the above code

how can i be able to asynchronously send 4 image to firebase, get the url, and at the end of this process, put the url in my dictionary to send it to my database ?

1
Your uploadDfdimg functions do not return a promise. In fact they return undefined as they have no return value - Jaromanda X
.then with 3 arguments? Where did you pluck that code from? - Jaromanda X
The code starting at var brand will execute before the .then code above it - Jaromanda X
Your code is no different from all the ajax code on SO. You just haven't grasped how promises work - Jaromanda X
that's a fact, but i don't know where to start from - Mehdi S.

1 Answers

1
votes

The question appears to ask for the following type of approach.

First a utility function, which promisifies the upload process and delivers a promise-wrapped downloadURL.

function uploadImg(img) {
    return $.Deferred(function(dfrd) {
        var uploadTask = storageRef.child('images/' + img.name).put(img);
        uploadTask.on(
            'state_changed', 
            function(snapshot) {}, 
            function(error) { dfrd.reject(error); }, 
            function() { dfrd.resolve(uploadTask.snapshot.downloadURL); }
        );
    }).promise();
}

Now, that utility can be used to create 4 x promises, which can then be aggregated with $.when() :

$("#submit-bag").click(function () {
    var p1 = uploadImg(img1);
    var p2 = uploadImg(img2);
    var p3 = uploadImg(img3);
    var p4 = uploadImg(img4);
    $.when(p1, p2, p3, p4).then(function(downloadUrl1, downloadUrl2, downloadUrl3, downloadUrl4) {
        // Whatever you want to do with downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4, ...
        // ... do it somewhere in this function.
        var updates = {};
        updates['/submission/' + firebase.database().ref().child('submission').push().key] = {
            marque: $("#select1 option:selected").text(),
            email: $('#form1').val(),
            code_postal: $('#form2').val(),
            commentaire: $('#comment').val(),
            validation: 0
        };
        firebase.database().ref().update(updates);
    });
}

More concisely, you would probably write :

$("#submit-bag").click(function () {
    var promises = [img1, img2, img3, img4].map(uploadImg);
    $.when.apply(null, promises).then(function(downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4) {
        // Whatever you want to do with downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4, ...
        // ... do it somewhere in this function.
        // etc, as above
    });
}