blueimp jQuery-File-Upload - How do I submit form without files attached?
Asked Answered
O

4

12

I have found solutions on how to add additional form data when submitting the file upload form. This question is how to upload the additional data if there is no file to upload.

I am using blueimp jquery-file-upload in a task management app in order to drag and drop files and attach them to a task.

The script is initialized and setup to not automatically upload when files are attached. On the fileuploadadd callback I attach data.submit() to my submit event handler. This accomplishes that we submit the task data and the files in one POST request.

Until files are added I'm unable to get access to the file-upload data to use the data.submit() function. I came up with a work around by adding an empty file (and then removing it) on page load which would trigger the binding data.submit() to the submit button. The problem is that the plugin is returning an error while trying to loop through an empty array of files. This problem would also occur if you added a file and then removed it before submitting the form.

I have been looking for a solution to this for a while and have looked high and low but couldn't find anything in the (IMHO) terrible documentation.

Have a look at my code below:

    $('#post_task').fileupload({
        autoUpload: false,
        singleFileUploads: false,
        disableImagePreview: true,
    }).on('fileuploadadd', function (e, data) {
        $.each(data.files, function (index, file) {
            var filename = file.name,
                filesize = bytesToSize(file.size) 
                ext = filename.substr(filename.lastIndexOf('.')+1,5),
                icon = '<i class="sprite_file sprite_file-file_extension_'+ext+'"></i>',
                node = $('<li/>').append($('<span/>').html(icon + filename + ' ' + filesize + '<a href="#">&times</a>')).attr('data-index',index);

            node.find('a').click(function(e){
                e.preventDefault();
                var $self = $(this),
                    $listItem = $self.parents('li'),
                    listIndex = $listItem.attr('data-index');
                $listItem.remove();
                $('#files li').attr('data-index',function(index){return index;});
                data.files.splice(listIndex,listIndex);
                console.log(data);
                vardata = data;
            });
            $('#files').append(node);
        });
        $('#post_task').unbind('submit').submit(function(ev){
            ev.preventDefault();
            data.submit();
        });
    });
Ol answered 13/2, 2014 at 17:5 Comment(1)
I also have the same requirement. The file upload is only an optional part of the form, so the form needs to be able to be submitted without files picked for upload.Hipparchus
D
3

I faced the same problem and I ended up adding an empty file prior to submitting if there is no file.

$("#fileupload").fileupload('add', {
    files: ['']
});

This works perfectly in my situation and the backend receives the POST while the submitted file is null.

With most browsers (tested Chrome and FF) my Backend will receive no file (null) but with IE8 there is one with size 0. I haven't tested it with any other IE.

Desiccator answered 22/7, 2014 at 10:52 Comment(0)
S
1

I just made two separate handlers like so:

$('#avatar').fileupload({
            singleFileUploads: true,
            multipart        : true,
            dataType         : 'json',
            autoUpload       : false,
            url              : config.settings.api + 'services/user/updateByActivationKey',
            type             : 'POST',
            add              : function (e, data) {

                submitbtn.on("click", function () {
                    console.log('submitting with image');
                    data.submit();
                });
            },
            done             : function (result) {

                console.log(result);
                if (!result.error) {
                    $('#modal-account-activated-success').modal('show');
                    $("#submitbtn").removeAttr('disabled');
                    $('#mercname').html('');
                    window.setTimeout(function () {
                        window.location.href = config.settings.user_url;
                    }, 3000);

                } else {
                    //analytics.track('completeProfileError', {
                    //  error        : JSON.parse(result.responseText).error,
                    //  activationKey: sessionStorage.getItem("activationkey")
                    //});
                    $('#modal-account-activated-error').modal('show');
                    $('#submitloader').html('');
                    $("#submitbtn").removeAttr('disabled');
                }
            }
            ,
            fail             : function (e) {
                //analytics.track('completeProfileError', {
                //  error        : e,
                //  activationKey: sessionStorage.getItem("activationkey")
                //});
                $('#errormessage').html(JSON.parse(e.responseText).error.messages[0]);
                $('#modal-account-activated-error').modal('show');
                $('#submitloader').html('');
                $("#submitbtn").removeAttr('disabled');

            }
        });

        //if no image was uploaded
        submitbtn.on("click", function () {
            if ($('#preview').html().length < 1) {
                console.log('submitting without image');

                $.ajax({
                    url       : config.settings.api + 'services/user/updateByActivationKey',
                    type      : 'POST',
                    data      : JSON.stringify({
                        'email'                     : $("#email").val(),
                        'activationKey'             : $("#activationKey").val(),
                        'firstName'                 : $("#firstname").val(),
                        'lastName'                  : $("#name").val(),
                        'password'                  : $("#password").val(),
                        'gender'                    : $("#gender").val(),
                        'birthdate'                 : $("#birthdate").val(),
                        'acceptedTermsAndConditions': $("#checkbox-accept-terms").val(),
                        'allowsDirectMarketing'     : $("#checkbox-allow-marketing").val()

                    }),
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader("Content-Type", "application/json");
                    },
                    success   : function (result) {
                        console.log(result);
                        if (!result.error) {
                            $('#modal-account-activated-success').modal('show');
                            $("#submitbtn").removeAttr('disabled');
                            $('#mercname').html('');
                            window.setTimeout(function () {
                                window.location.href = config.settings.user_url;
                            }, 3000);

                        } else {
                            //analytics.track('completeProfileError', {
                            //  error        : JSON.parse(result.responseText).error,
                            //  activationKey: sessionStorage.getItem("activationkey")
                            //});
                            $('#modal-account-activated-error').modal('show');
                            $('#submitloader').html('');
                            $("#submitbtn").removeAttr('disabled');
                        }
                    },
                    error     : function (e) {
                        //analytics.track('completeProfileError', {
                        //  error        : e,
                        //  activationKey: sessionStorage.getItem("activationkey")
                        //});
                        $('#errormessage').html(JSON.parse(e.responseText).error.messages[0]);
                        $('#modal-account-activated-error').modal('show');
                        $('#submitloader').html('');
                        $("#submitbtn").removeAttr('disabled');
                    }
                })
            }
        });
Squama answered 4/6, 2015 at 12:58 Comment(0)
C
1

@Hirshy and @Luk, your solution is really quite elegant and works like a charm. The files input field does not even get sent to the server so it's easy to determine when a file is in the payload.

In my Angular app, I have a single view for both adding a new document and some attendant data and for editing the data and/or uploading a replacement document.

Here is my solution:

/*------------------------------------------------------------------------*/
/* Prepare file uploader.                                                 */
/*                                                                        */
/* jQuery-File-Upload does not submit a form unless a file has been       */
/* selected. To allow this, we manually add an empty file to be uploaded, */
/* which makes the submit handler available, and we replace the submit    */
/* handler with one that will submit the form without a selected file.    */
/*                                                                        */
/* see: https://mcmap.net/q/950183/-blueimp-jquery-file-upload-how-do-i-submit-form-without-files-attached/2245849.                      */
/*------------------------------------------------------------------------*/
var uploadForm = $('#DocumentForm');
var fileInput  = $('#DocumentForm input:file');

$scope.uploadOptions = 
  {
  url:              Services.Documents.uploadRoute,
  autoUpload:       false,
  dropZone:         uploadForm,
  fileInput:        fileInput,
  replaceFileInput: false
  };

/*---------------------------------------------------------------*/
/* Initialize the uploader. This must be done with the options   */
/* or an error will be thrown when an empty file is added below. */
/* It is also necessary to initialize with the options here as   */
/* well as in the element html or the results are unpredictable. */
/*---------------------------------------------------------------*/
uploadForm.fileupload($scope.uploadOptions);

/*--------------------------------------------------------------------*/
/* File processing is called in the default add handler and this      */
/* handler is called after a successful add. It displays the file     */
/* name in the drop zone, sets the document name for a new document,  */
/* and sets the submit handler to submit the form with file and data. */
/*                                                                    */
/* If editing a document, a dummy empty file object is manually       */
/* added to make the submit handler available so the user can make    */
/* data changes without uploading a new document.                     */
/*--------------------------------------------------------------------*/
uploadForm.bind("fileuploadprocessdone", function(e, data) 
  {
  /*------------------------------------------------------------*/
  /* Get the user selected file object and display the name.    */
  /* Set the document name to the file name if not already set. */
  /*------------------------------------------------------------*/
  if (data.files[0].name)
    {
    $scope.document.file = data.files[0];
    if (!$scope.document.name)
      $scope.document.name = $scope.document.file.name;
    MessageService.clear();
    }

  /*--------------------------------------*/
  /* If this is the dummy file add, reset */
  /* 'acceptFileTypes' to global config.  */
  /*--------------------------------------*/
  else  
    delete $scope.uploadOptions.acceptFileTypes;

  /*------------------------------------------------------------*/
  /* Set the submit handler. We have to do this every time a    */
  /* file is added because 'data' is not passed to the handler. */
  /*------------------------------------------------------------*/
  uploadForm.unbind('submit').submit(function(e)
    {
    e.preventDefault();
    data.submit();
    });
  });

/*---------------------------------------------------------------------------*/
/* If we get here, the file could not be added to the process queue most     */
/* likely because it is too large or not an allowed type. This is dispatched */
/* after the add event so clear the current file and show the error message. */
/*---------------------------------------------------------------------------*/
uploadForm.bind("fileuploadprocessfail", function(e, data) 
  { 
  $scope.document.file = null;
  MessageService.notice(data.files[data.index].error);
  });

/*-----------------------------------------------------------------*/
/* Add a dummy empty file if not a new document so the submit      */
/* handler is set and the user does not have to upload a document. */
/*-----------------------------------------------------------------*/
if (!$scope.new_document)
  {
  $scope.uploadOptions.acceptFileTypes = null;
  uploadForm.fileupload('add', { files: [{}] });
  }

UPDATE

It turns out uploadForm.fileupload('add', { files: [''] }); will result in an exception being thrown in the browser if the server returns a failed status. JFU tries to assign data.files[0].error and data.files[0] doesn't exist.

The problem is handled nicely by assigning an empty array instead of an empty string: uploadForm.fileupload('add', { files: [[]] });

I have updated the example above.

UPDATE 2/29/16

It turned out I did want to restrict the file types after all so I modified my script to clear 'acceptFileTypes' property before the dummy file add and reset it in the add handler. Also discovered I could not access the process errors in the add handler so replaced it with 'fileuploadprocessdone' and handled the error in 'fileuploadprocessfail'.

I have updated the example above but we're still using JFU 5.42.0.

IMPORTANT

I am using 5.42.0 which is a very old version of JFU. I did not write this code and my first attempt to upgrade failed. When I do upgrade, I'll update this solution.**

Cushing answered 23/9, 2015 at 19:21 Comment(0)
T
-1

Try this puglin simpleUpload, no need form

Html:

<input type="file" name="arquivo" id="simpleUpload" multiple >
<button type="button" id="enviar">Enviar</button>

Javascript:

$('#simpleUpload').simpleUpload({
  url: 'upload.php',
  trigger: '#enviar',
  success: function(data){
    alert('Envio com sucesso');

  }
});
Telling answered 13/4, 2014 at 2:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.