Blueimp jQuery-File-Upload - Как отправить форму без прикрепленных файлов?

Я нашел решения о том, как добавлять дополнительные данные формы при отправке формы загрузки файла. Этот вопрос заключается в том, как загрузить дополнительные данные, если нет файла для загрузки.

Я использую blueimp jquery-file-upload в приложении для управления задачами, чтобы перетащить файлы и прикрепить их к задаче.

script инициализируется и настраивается, чтобы автоматически не загружать файлы при подключении файлов. В обратном вызове fileuploadadd я прикрепляю data.submit() к моему обработчику событий submit. Это позволяет отправить данные задачи и файлы в один запрос POST.

Пока файлы не будут добавлены, я не могу получить доступ к файлу-upload data, чтобы использовать функцию data.submit(). Я приступил к работе, добавив пустой файл (а затем удалив его) при загрузке страницы, который вызовет привязку data.submit() к кнопке отправки. Проблема в том, что плагин возвращает ошибку при попытке пропустить пустой массив файлов. Эта проблема также возникнет, если вы добавите файл, а затем удалите его перед отправкой формы.

Я искал какое-то решение для этого и выглядел высоко и низко, но ничего не смог найти в (IMHO) ужасной документации.

Посмотрите мой код ниже:

    $('#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();
        });
    });

Ответ 1

Я столкнулся с той же проблемой, и в итоге я добавил пустой файл перед отправкой, если нет файла.

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

Это отлично работает в моей ситуации, и бэкэнд получает POST, в то время как поданный файл имеет значение null.

В большинстве браузеров (проверенных Chrome и FF) мой Backend не получит никакого файла (null), но с IE8 есть один с размером 0. Я не тестировал его ни с каким другим IE.

Ответ 2

Я просто сделал два отдельных обработчика:

$('#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');
                    }
                })
            }
        });

Ответ 3

@Hirshy и @Luk, ваше решение действительно довольно элегантно и работает как шарм. Поле ввода файлов даже не отправляется на сервер, поэтому легко определить, когда файл находится в полезной нагрузке.

В моем приложении Angular у меня есть одно представление как для добавления нового документа, так и для некоторых сопутствующих данных, а также для редактирования данных и/или загрузки замещающего документа.

Вот мое решение:

/*------------------------------------------------------------------------*/
/* 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: http://stackoverflow.com/q/21760757/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

Оказывается, uploadForm.fileupload('add', { files: [''] }); приведет к тому, что исключение будет выведено в браузере, если сервер вернет состояние с ошибкой. JFU пытается назначить data.files[0].error, а data.files [0] не существует.

Проблема обрабатывается красиво, назначая пустой массив вместо пустой строки: uploadForm.fileupload('add', { files: [[]] });

Я обновил приведенный выше пример.

ОБНОВЛЕНИЕ 2/29/16

Оказалось, что я все-таки хочу ограничить типы файлов, поэтому я изменил свой script, чтобы очистить свойство acceptFileTypes до добавления файла фиктивного файла и reset в обработчик добавления. Также было обнаружено, что я не смог получить доступ к ошибкам процесса в обработчике добавления, поэтому заменил его "fileuploadprocessdone" и обработал ошибку в файле fileuploadprocessfail.

Я обновил приведенный выше пример, но мы все еще используем JFU 5.42.0.

ВАЖНО

Я использую 5.42.0, который является очень старой версией JFU. Я не писал этот код, и моя первая попытка обновления не удалась. Когда я обновляюсь, я обновлю это решение. **

Ответ 4

Попробуйте этот puglin simpleUpload, не нужна форма

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');

  }
});