0

I am using the jQuery File Upload to upload product images. There are different "types" of images for each product (different size/dimensions).

I have altered the upload template so that a dropdown of possible image types is shown for each file added. Before clicking upload, the user must pick from the dropdown to indicate what image type the file being uploaded is.

Some image types are an exact size, some just have a minimum width. What I want to do is compare the actual image size to the type chosen to validate they are indicating the correct type.

I'm attempting to do this via the "fileuploadsubmit" callback where I have already added a check to make sure an option is selected in the dropdown.

$('#fileupload').bind('fileuploadsubmit', function (e, data) {
    $('#uploading_note').removeClass("alert-danger").html("");
    var inputs = data.context.find(':input');
    if (inputs.filter(function () {
        return !this.value && $(this).prop('required');
    }).first().focus().length) {
        data.context.addClass("alert-danger");
        data.context.find('.file_msg').html("Image Type is required!"); 
    data.context.find('button').prop('disabled', false);
    return false;
}
    var fixed_dimension = 0;
    var wt = 0;
    var ht = 0;
    var image_size = getImageSize(data,function(width, height) {
        wt = width;
        ht = height;
        console.log (wt+'x'+ht);
        return [wt,ht];
    }); 
   ........... 

This is the getImageSize function.

    function getImageSize(data,callback){
    var img = new Image();
    img.src = _URL.createObjectURL(data.files[0]);
            img.onload = function () {
                var w = this.width;
                var h = this.height;
                console.log(w+'-getImageSize-'+h);
                callback (w,h);
            }; 

}

The console.log() in both output correctly but I can't get these numbers outside the functions to use them. I understand it has to do with the functions be asynchronous but I can't figure out how to get around it. Or maybe there is a better jQuery File Upload built in option I'm missing.

I understand the asynchronous function issue, this one was attempt at finding a solution to validating the image size. I have also attempted to do this in the PHP script. It works in that I can prevent the upload of an image but the user experience is poor. So I am still looking for a solution as to how to do image size validation using jQuery File Upload.

Below is an update version of the code.

$('#fileupload').bind('fileuploadsubmit', function (e, data) {
    console.log(data);

    $('#uploading_note').removeClass("alert-danger").html("");
    var inputs = data.context.find(':input');
    if (inputs.filter(function () {
        return !this.value && $(this).prop('required');
    }).first().focus().length) {
        console.log(data.context);
        data.context.addClass("alert-danger");
        data.context.find('.file_msg').html("Image Type is required!"); 
        //$('#uploading_note').addClass("alert-danger").html("Image Type is required!");
    data.context.find('button').prop('disabled', false);
    return false;
}

    var fixed_dimension = 0;
    var wt = 0;
    var ht = 0;
    var image_size = getImageSize(data,function(width, height) {
        wt = width;
        ht = height;
        console.log(wt+'-getImageSize-function'+ht);
       switch (inputs[0].value){
        case "16x9_background":
        case "16x9":
            var req_width = 1920;
            var req_height = 1080;
            fixed_dimension = 1;
            break;
        case "3x4":
            var req_width = 1600;
            var req_height = 1200;
            fixed_dimension = 1;
            break;
        case "hires":
            var req_width = 1400;
            var req_height = 0;
            break;
        case "lowres":
            var req_width = 200;
            var req_height = 0;
            break;
    }
    if (fixed_dimension){
        if (wt != req_width || ht != req_height){
            data.context.addClass("alert-danger");
            data.context.find('.file_msg').html("Image dimensions must be exactly "+req_width+"x"+req_height+". This image is "+wt+"x"+ht+". Image not uploaded.");
            return false;
        } 
    } else {
        if (wt < req_width){
           data.context.addClass("alert-danger"); 
           data.context.find('.file_msg').html("Image dimensions wrong!! Width must be "+req_width+", not "+wt+". Image not uploaded.");
            console.log(wt+'x'+ht);
            return false;
        }
    }    
    d = inputs.serializeArray();
    d.push({ name: "folder", value: $('#barcode').val() });
    d.push({ name: "stock_num", value: $('#stock_num').val() });
    data.formData = d;
    console.log(wt+"xxxx"+ht);
    data.submit();  // SUMBIT THE FORM
    }); 

    console.log(wt+"xxxx"+ht);
    console.log("imagesize:"+image_size);
    return false;  //STOP THE DEFAULT SUBMIT
}); 
Ryzone
  • 13
  • 4
  • Possible duplicate of *How to return value from an asynchronous callback function*: https://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function – kmoser Jul 25 '17 at 03:58
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Kaiido Jul 25 '17 at 04:39
  • 1
    Agreed with @kmoser, the root cause of your problem is that you're not handling asynchronous code correctly, but you might be interested in [this Q/A](https://stackoverflow.com/questions/42540903/sort-by-image-resolution-in-gallery/) too. – Kaiido Jul 25 '17 at 04:40
  • Yes I get that the problem is related to asynchronous code, I haven't figured out how to code correctly yet, I will read these links.. But also I was really hoping there was a jQuery File Upload specific solution that I was overlooking. – Ryzone Jul 25 '17 at 15:02
  • Also to be clear, I just need to get the size of an uploaded image. I don't want it to be asynchronous but it seems this img.onload function is done asynchronously. How do I force it to be not asynchronous? – Ryzone Jul 25 '17 at 15:58
  • You don't need to force it to be synchronous. You should be doing your validation within the callback which determines the image width and height, – kmoser Jul 25 '17 at 17:22
  • I tried that. Where I am attempting to "return [wt,ht]", I got rid of that and put all the validation in there. When I did that, no errors or anything but it did not actually stop when the validation failed. I tried just "return false". It still seems I'm the same issue, I can't get data out of the function and back to the rest of the script. What am I missing? – Ryzone Jul 25 '17 at 17:53
  • What does "it did not actually stop" mean? And why does the rest of the script need the data, when you've told us you've already created a function that has just determined whether the data is valid. At the point you've determined the data is invalid, why not just do this: ``data.context.addClass("alert-danger"); data.context.find('.file_msg').html("Image Type is required!"); `` – kmoser Jul 27 '17 at 03:52
  • "It does not actual stop" meaning the script continues on and uploads the file. The first bit of code which checks that the required field is populated, that "return false" stops the script from uploading the file. So the error msg is displayed to the user and the file is not uploaded. I can't get that to work with my size validation though. If I do as you are suggesting, the class will change and the msg displayed BUT it will continue on, upload the file and those on screen changes will go away because the file upload process returns that it was successful. I appreciate your help! – Ryzone Jul 27 '17 at 04:45
  • In that case, your first bit of code should check for required fields and set a global variable indicating the results, e.g. ``$OK = true;`` or ``$OK = false;``. Regardless of whether it finds errors it should ``return false;`` to stop the form from submitting. When the size validation function runs, it should determine if the file is valid; if so, *and* if ``$OK == true``, then it should submit the form, e.g. ``$( "form" ).submit();`` – kmoser Jul 27 '17 at 05:52
  • @kmoser I added the full code to my post so it is more clear. I thought I could move the submit logic into the function, basically move the rest of the fileuploadsubmit into the function but it is not working. I always fails since i'm doing return fail. – Ryzone Jul 27 '17 at 21:23
  • You might also need to use https://api.jquery.com/event.preventdefault/ to prevent the form from submitting. – kmoser Jul 28 '17 at 05:34

1 Answers1

0

What I ended up doing was removing the actual form submit button and replace it with a button (not type submit) that calls the validation code. If it passes, the form is then submitted normally (via data.submit()), if not it returns the error. I had to remove the file level submit buttons (or I found it easier to do that).

    $('#fileupload').fileupload({
    url: 'process.php',
    previewThumbnail: true,
    sequentialUploads: true,
    acceptFileTypes: /(\.|\/)(jpe?g|pdf|zip)$/i,
    maxChunkSize: 10000000,
    add: function (e, data) {
        $('#start_upload_button').click(function () {
          getImageSize3(data).then(function(dimensions) {
        image validation... return false if any errors

    data.submit() // submit the form
    }); 
Ryzone
  • 13
  • 4