2

Context: I am using an input type file to upload multiple images. Then I create a new object for each image to retrieve data: size, name, base64Url. Then I use Ajax to send list of object to controller, then I handle each image file in a loop to save image info to database(name, image path, Size). My problem is I couldn’t get all base64 value of list images. Before I can get base64 value of single image through a callback but come to a loop it didn’t fire event reader.onload for all item in loop, only the last item fire event.

2) I used blob url for preview images, but in Controller I tried Webclient.DownloadFile(url,path) it cannot download data from blob url, so I have to turn back to base64 value.

3) I also tried FormData, it can send all images data to IFromFile in controller, but for each image I want to add more information before sending to controller like ( productId, color, quantity,size).

That is all ways I tried, hope somebody help me solve my issues or give me another solution for sending multiple image to controller.

When i run my code below value of base64Val always = ' '. The callback below work fine for a single image but come to array of images, reader.onload will not fire.

$('#btn-start-upload').on('click', function () {
    var listImgs = [];

    for (var i = 0; i < image.imgData.length; i++) {
            readImg(image.imgData[i], function (e) {
                listImgs.push(e.target.result);
            });
    }
});

callback :

 function readImg(file, onLoadCallback) {
            var reader = new FileReader();
            reader.onload = onLoadCallback;
            reader.readAsDataURL(file);
        },

I have tried debugging and see that reader is not completed before base64Val get value from reader.result or e.target.result, then 'listImgs' was empty or contained list of base64Val = ' '.

Update 2:

$('#btn-start-upload').on('click', function () {
               let productId = $('#productId').val();
            let listImgs = [];
            image.readFileList(image.imgData).then((value) => {
                listImgs.push(value);
            });
    });

    function readFileList(files) {
            return Promise.all(files.map(file => this.readFile(file))).then(contents => {
                return contents;
            });
        },

        function readFile(file) {
            return new Promise(resolve => {
                const fileReader = new FileReader();
                fileReader.onload = () => resolve(fileReader.result);
                fileReader.readAsText(file);
            });
        },
J.Tran
  • 115
  • 1
  • 8
  • `reader.onload` is asynchronous - it doesn't get called immediately. Check the dupe. – Adam Jenkins Mar 04 '19 at 00:29
  • 1
    And while there is no context here, 99% of the time you don't want a b64 dataURI of your files, a simple blobURL created from [URL.createObjectURL()](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL), which not only uses no memory for files stored on the user's disk, but is also generated synchronously, i.e no callback nightmare. – Kaiido Mar 04 '19 at 00:39
  • Kaiido, yes blob can, but how do I save blob to directory? I tried using Webclient.DowloadFile(url,path) but blob url unable to save ! – J.Tran Mar 04 '19 at 01:45
  • Adam, yes, I also used callback for reader.onload from an other function like this getBase64(file,callback) but through loop I only get the last base64 value of item in loop – J.Tran Mar 04 '19 at 01:47
  • I have edited my question by adding context Kaiido, thank you ! – J.Tran Mar 04 '19 at 02:07
  • You can [send your files as binary data through AJAX directly](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data). I would not recommend storing it in database, but if you really have to, then you could do the b64 conversion from server. – Kaiido Mar 04 '19 at 02:29
  • And for your closure problem, simply remove this `base64Val` var, you don't need it: `reader.onload = e => listImgs.push(e.target.result)` – Kaiido Mar 04 '19 at 02:31
  • Kaiido, thank you for your reccomendation, actually I would not save base64 value to database, in Controller I will use System.IO.File to write base64 value to an image, then I will save these information to database: image path, image size, name, productId. For each of my product it has multiple images, so that is reason I came into this issue. Thanks ! – J.Tran Mar 04 '19 at 02:39
  • I will follow your solution by tomorrow morning and response you ASAP. Thanks so much ! If you have another way of retrieving image data and send it by Ajax , please suggest me. Thank you! – J.Tran Mar 04 '19 at 02:42
  • @Adam I have edited my question, even i used callback, it will not fire reader.onload event, Hope you guys check my code !! it worked fine for a single image but come to array it doesn't work or only work for the last item in array. I think i have to change my code but i dont know how , thanks ! – J.Tran Mar 04 '19 at 15:47
  • @Kaiido it doesnt work for array of images. I have edited my questions with a callback i have used with single image, it works file for a single image. – J.Tran Mar 04 '19 at 15:48
  • What doesn't work now? You can't upload your images until all callbacks have completed, but your code doesn't show anywhere where you are waiting for all callbacks to complete. – Adam Jenkins Mar 04 '19 at 16:27
  • I mean readImg(file, onLoadCallback) doesnt work exactly when i use it inside an array, the reader.onload doesnt get fire, then listImgs is empty. – J.Tran Mar 04 '19 at 16:41
  • "but your code doesn't show anywhere where you are waiting for all callbacks to complete" . I will search for this, if you have an example please post it here. Thanks ! – J.Tran Mar 04 '19 at 16:43
  • @Adam I have updated code, but when i use array.push(reader.result), array always contain object = ' '. Can you help me check my code ? – J.Tran Mar 04 '19 at 22:50

0 Answers0