tors / jquery-fileupload-rails

jQuery File Upload integrated for Rails
669 stars 254 forks source link

Reuse File Input for a second upload #86

Open stefanocdn opened 8 years ago

stefanocdn commented 8 years ago

I am trying to upload 2 different versions of the same file to AWS S3 from a single form: large and thumbnail.

The code for the upload is the following. The upload works fine and in the done callback I would like to start the second upload.

fileInput.fileupload({
        fileInput:       fileInput,
        url:             form.data('url'),
        type:            'POST',
        autoUpload:       true,
        formData:         form.data('form-data'),
        paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
        dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
        replaceFileInput: false,
        disableImageResize: false,
        imageMaxWidth: 800,
        imageMaxHeight: 800,
        imageCrop: true,

        done: function(e, data) {
          console.log('DONE');

          // HERE I WOULD LIKE TO MAKE A SECOND UPLOAD
          startThumbnailUpload();
        },
      });

The code for the startThumbnailUpload() method would be exactly the same except for the width and height:

function startThumbnailUpload(){
  fileInput.fileupload({
        fileInput:       fileInput,
        url:             form.data('url'),
        type:            'POST',
        autoUpload:       true,
        formData:         form.data('form-data'),
        paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
        dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
        replaceFileInput: false,
        disableImageResize: false,
        imageMaxWidth: 200,
        imageMaxHeight: 200,
        imageCrop: true,

        done: function(e, data) {
          console.log('DONE');
        },
   });
}

The second fileInput.fileupload never gets executed. Is there a way to achieve that kind of double upload with the same file reusing the same fileinput?

felixbuenemann commented 8 years ago

This repository is for the gem packaging of the jquery file upload gem.

However, just instantiating the plugin won't trigger a file upload, that's why your current code is doing nothing.

You should look into the Programmatic file upload section in the jQuery-File-Upload Wiki.

stefanocdn commented 8 years ago

Thank you for the link, I checked out the Programmatic file upload section. But there is a main problem I can't solve : I need to upload one file from 2 different widgets (I need these 2 different widgets to upload different sizes.

I tried to keep the code below and add a programmatic upload in the callback.

fileInput.fileupload({
        fileInput:       fileInput,
        url:             form.data('url'),
        type:            'POST',
        autoUpload:       true,
        formData:         form.data('form-data'),
        paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
        dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
        replaceFileInput: false,
        disableImageResize: false,
        imageMaxWidth: 800,
        imageMaxHeight: 800,
        imageCrop: true,

        done: function(e, data) {
          // Trigger a programmatic upload
          fileInput.fileupload('send', {
            fileInput:       fileInput,
            url:             form.data('url-thumbnail'),
            type:            'POST',
            formData:         form.data('form-data-thumbnail'),
            paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
            dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
            replaceFileInput: true,
            disableImageResize: false,
            singleFileUploads: false,
            imageMaxWidth: 100,
            imageMaxHeight: 100,
            imageCrop: true})
          .success(function (result, textStatus, jqXHR) {
            console.log("SUCCESS");
          })
          .error(function (jqXHR, textStatus, errorThrown) {
            console.log("error");
          })
          .complete(function (result, textStatus, jqXHR) {
            console.log("complete");
          });
        },
      });

Which enters a loop of uploads. Not working.

Then I thought about creating 2 different widgets to upload programmatically following the pattern:

//Initialize
$('#file').fileupload({
  url: 'thumbnailURL'
});
$('#form').fileupload({
  url: 'largeURL'
});

//Trigger the submit
$('#file').fileupload({
  fileInput: $('#file')
});
$('#form').fileupload({
  fileInput: $('#file')
});

But the 2 widgets end up referring to the same file input and that doesn't work either.

I thought about an hacky solution, add a second hidden file input, create a second separate widget, and then populate the input field when the file is selected : but it is not possible to populate manually an input field with a file.

Unfortunately I can't think of another way to proceed.. Any suggestion or idea would be of great help!

stefanocdn commented 8 years ago

I am trying another approach for the multiple versions upload.

The following code works fine.

$('#file_upload').find("input:file").each(function(i, elem) {
  var fileInput    = $(elem);
  var form         = $(fileInput.parents('form:first'));
  fileInput.fileupload({
    fileInput:       fileInput,
    url:             form.data('url'),
    type:            'POST',
    autoUpload:       true,
    formData:         form.data('form-data'),
    paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
    dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
    replaceFileInput: false,
    disableImageResize: false,    imageCrop: true,
    processQueue: [
          {
              action: 'loadImage',
              fileTypes: /^image\/(gif|jpeg|png)$/,
              maxFileSize: 20000000 // 20MB
          },
          {
              action: 'resizeImage',
              maxWidth: 400,
              maxHeight: 400
          },
          {action: 'saveImage'}
      ],
      processstart: function (e) {
          console.log('Processing started...');
      },
      process: function (e, data) {
          console.log('Processing ' + data.files[data.index].name + '...');
      },
      processdone: function (e, data) {
          console.log('Processing ' + data.files[data.index].name + ' done.');
      }
  }); //fileupload

I changed the processQueue to upload 2 versions in a row:

processQueue: [
          {
              action: 'loadImage',
              fileTypes: /^image\/(gif|jpeg|png)$/,
              maxFileSize: 20000000 // 20MB
          },
          {
              action: 'resizeImage',
              maxWidth: 400,
              maxHeight: 400
          },
          {action: 'saveImage'},
          {action: 'duplicateImage'},
          {
              action: 'resizeImage',
              maxWidth: 200,
              maxHeight: 200
          },
          {action: 'saveImage'},
      ]

Problem: the first saveImage does not upload the first image before duplicating. Instead there is only one POST request issued for both files, which returns the error => POST requires exactly one file upload per request.

Any idea how to fix this issue? Thx for your help.

felixbuenemann commented 8 years ago

Shouldn't you be able to use fileupload('add', options) or fileupload('send', options) twice to do the upload? You could then set the different image sizes in the options hash. You might need to set replaceFileInput: false for this to work.

stefanocdn commented 8 years ago

@felixbuenemann Thanks again for your reply. fileupload('add', options) does not work for me because I trigger the upload already inside an add callback so then it loops. Using fileupload('send', options) works fine for the upload, and I can trigger it twice which is perfect, but I can't get any resize working : the original is uploaded every time.

fileInput.fileupload('send',
{
  fileInput: fileInput,
  url: form.data('url'),
  disableImageResize: false,
  imageCrop: true,
  imageMaxWidth: 100,
  imageMaxHeight: 100,
  formData: data_thumbnail,
  replaceFileInput: false,
  type:            'POST',
  autoUpload:       false,
  paramName:        'file',
  dataType:         'XML'
  }
);

I could not fine SO threads mentioning resizing with 'send' and I could not find it in the wiki either, so if you have the solution to resize with 'send' that would be extremely helpful. Thanks again