【问题标题】:Fine Uploader with form option questions带有表单选项问题的精细上传器
【发布时间】:2014-12-05 22:05:43
【问题描述】:

我正在使用带有 jQ​​uery、jQuery.validate 和 jQuery.form 插件的 Fine Uploader (v5.0.1) 用于新事件的多字段表单,可以有零到两个文件附件。

我已经成功了,但在继续之前我有几个问题。

  1. 我的客户端代码为每个文件(包括其他表单元素)生成一个 POST 请求,以及仅针对其他表单元素的一个额外 POST 请求。所以,如果我的表单有两个文件附件,我会收到三个 POST 请求。这是正常行为吗?我可以在一个 POST 请求中获取所有内容吗?
  2. 如果多个 POST 请求是正常行为,我将不得不在第一个 POST 请求之前在客户端生成某种唯一标识符,这样我可以避免数据库中的事件记录重复并将每个文件上传与正确的事件。如果这是我需要走的方向,我可以看看这种类型的实现示例吗?
  3. 如果没有附加文件,我会收到一个警告对话框:“没有要上传的文件。”表单可以不带文件附件提交,所以我不想暗示用户他/她必须附加文件。我怎样才能摆脱这个对话框?
  4. 我目前收到一个针对表单数据的 POST 响应,以及针对每个上传的文件的一个 POST 响应。有没有办法只处理最终的 POST 响应(例如 form.onAllComplete)?如果表单没有文件附件怎么办?
  5. 我正在为表单使用一个服务器端点,包括文件上传。我是否应该使用两个单独的端点,一个用于其他表单字段,一个用于文件上传?

这是我的表格:http://www.paulrachal.com/test/fineuploader-test.htm

这是我的代码: 客户:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>New Event</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.css" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.js"></script>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.13.0/jquery.validate.min.js"></script>
    <script src="http://malsup.github.com/jquery.form.js"></script>
    <!-- Fine Uploader -->
    <link rel="stylesheet" href="../css/custom.fineuploader-5.0.1.min.css" />
    <script src="../js/custom.fineuploader-5.0.1.min.js"></script>
    <!-- document.ready -->
    <script type="text/javascript" charset="utf-8">
    $(document).ready(function(){
    <!-- event handlers -->
    // hide the file upload button when the page loads
    $( '#manual-fine-uploader' ).hide();
    // show the file upload button on change in attachments checkbox
    $("#hasattachments").change(function() {
        if ($('#hasattachments:checked').length) {
            $('#manual-fine-uploader').show();
        }
        else {
            $('#manual-fine-uploader').hide();
        }
    })
    <!-- Fine Uploader setup -->
    var manualuploader = $('#manual-fine-uploader').fineUploader({
      request: {
        endpoint: 'fineuploader-test.php'
      },
      form: {
          element: 'new-event'
      },
      template: "qq-template-manual-noedit",
      validation: {
        allowedExtensions: ['txt', 'pdf'],
        itemLimit: 2,
        sizeLimit: 256000 // 250 kB = 250 * 1024 bytes
      },
      autoUpload: false
    });
    <!-- form validation -->
    // setup form validation on the form element
    $("#new-event").validate({
    // validation rules
    rules: {
        description: {
            required: {
                depends: function(element) {
                  if ( $("input[name='eventtype']:checked").val() == "3" || $("input[name='eventtype']:checked").val() == "4" || $("input[name='eventtype']:checked").val() == "5" )
                  return true;
                }
            }
        },
    },
    // validation error messages
    messages: {
        description: "Please enter a description"
    },
    // submit handler
    submitHandler: function(form) {
      $("#send").attr("value", "Sending...");
      $(form).ajaxSubmit({
        target: "#response",
        dataType: "json",
        success: function processJson(response) {
            if (response.success)
            {
                $(form).slideUp("fast");
                $("#response").html("<span class='success'>" + response.success + "</span>").hide().slideDown("fast");
            } // end if
            else if (response.failure)
            {
                $("#response").empty();
                $(".error").removeClass("error");
                $errors = response.failure;
                for ($i = 0; $i < $errors.length; $i++) {
                    $error = $errors[$i];
                    $.each($error, function(key, value) {
                        // append error text to div#response
                        $("#response").append("<li class='failure'>" + value + "</li>").hide();
                        // set form elements based on the error
                        switch(key) {
                            case "description-isempty":
                                $("#description").addClass("error");
                                break;
                            case "eventname-isempty":
                                $("#eventname").addClass("error");
                                break;
                            case "eventtype-isinvalid":
                                $("#eventtype-input").addClass("error");
                                break;
                            default:
                                // default statements if no cases are true
                        } // end switch
                    }); // end $.each
                } // end for
                $("#response").addClass("failure");
                $("#response").slideDown("fast");
                $("html, body").animate({ scrollTop: 0 }, "fast");
            } // end else if
        } // end processJson
      });
      return false;
    }
    }); // end #new-event.validate
    <!-- validate individual fields on change -->
    // #description
    $('#description').on('change', function() {
        $('#new-event').validate().element('#description');
    });
    }); // end document.ready
    </script>
    <!-- Fine Uploader Template -->
    <script type="text/template" id="qq-template-manual-noedit">
    <div class="qq-uploader-selector qq-uploader">
        <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
            <span>Drop files here to upload</span>
        </div>
        <div class="qq-upload-button-selector qq-upload-button">
            <div>Browse...</div>
        </div>
        <span class="qq-drop-processing-selector qq-drop-processing">
            <span>Processing dropped files...</span>
            <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
        </span>
        <ul class="qq-upload-list-selector qq-upload-list">
            <li>
                <div class="qq-progress-bar-container-selector">
                    <div class="qq-progress-bar-selector qq-progress-bar"></div>
                </div>
                <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                <span class="qq-upload-file-selector qq-upload-file"></span>
                <span class="qq-upload-size-selector qq-upload-size"></span>
                <a class="qq-upload-cancel-selector qq-upload-cancel" href="#">Cancel</a>
                <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
            </li>
        </ul>
    </div>
    </script>
    <!-- styles -->
    <style type="text/css">
    .qq-upload-button-selector {
        background: #0080FF;
    }
    #response {
      margin-bottom: 20px;
      text-align: center;
    }
    #response .success {
      color: #08a300;
    }
    #response .failure {
      color: #dc0000;
    }
    div.failure {
      background-color: #FF0;
    }
    .error {
        border: 2px solid red;
    }
    input.error {
        border: 2px solid red;
    }
    select.error {
        border: 2px solid red;
    }
    </style>
  </head>
  <body>
    <!-- new-event-form -->
    <div id="new-event-form" data-role="page">
    <!-- header -->
    <div data-role="header"><h1>NEW EVENT</h1></div>
    <div class="content" data-role="content">
    <div id="response"></div>
    <form id="new-event" action="fineuploader-test.php" method="post">
    <div data-role="fieldcontain">
        <fieldset data-role="controlgroup">
            <legend>Event Type:</legend>
            <div id="eventtype-input">
                <input type="radio" name="eventtype" id="eventtype_1" value="1" checked="checked" />
                <label for="eventtype_1">Ride</label>

                <input type="radio" name="eventtype" id="eventtype_2" value="2" />
                <label for="eventtype_2">Clinic</label>

                <input type="radio" name="eventtype" id="eventtype_3" value="3" />
                <label for="eventtype_3">Social Event</label>

                <input type="radio" name="eventtype" id="eventtype_4" value="4" />
                <label for="eventtype_4">Meeting</label>

                <input type="radio" name="eventtype" id="eventtype_5" value="5" />
                <label for="eventtype_5">Non-Club Event</label>
            </div>
       </fieldset>
    </div>
    <div data-role="fieldcontain">
        <label for="eventname">Event Name:</label>
        <input type="text" name="eventname" id="eventname" value="" maxlength="40" required />
    </div>
    <div id="descriptioninput" data-role="fieldcontain">
        <label for="description">Description:</label>
        <input type="text" name="description" id="description" value="" maxlength="40"  />
    </div>
    <div id="attachments" data-role="fieldcontain">
        <fieldset data-role="controlgroup">
            <legend>Attachments:</legend>
                <input type="checkbox" name="hasattachments" id="hasattachments" value="1" />
                <label for="hasattachments">Attachments</label>
        </fieldset>
    </div>
    <div id="manual-fine-uploader">Browse...</div>
        <div class="ui-body ui-body-b">
        <fieldset class="ui-grid-a">
            <div class="ui-block-a"><input type="reset" data-theme="d" value="Cancel"></div>
            <div class="ui-block-b"><input type="submit" data-theme="a" value="Submit"></div>
        </fieldset>
        </div>
    </form>
    </div> <!-- /content -->
    </div> <!-- /page -->
  </body>
</html>

服务器:

<?php

// get values from POST request
$eventtype = $_POST['eventtype'];           // eventtype field
$eventname = $_POST['eventname'];           // eventname field
$description = $_POST['description'];       // description field
$hasattachments = $_POST['hasattachments']; // hasattachments field
$qqfile = $_POST['qqfile'];                 // file upload field
$qquuid = $_POST['qquuid'];                 // file upload uuid
$qqfilename = $_POST['qqfilename'];         // file upload filename

// include the upload handler class
require_once "handler.php";
// initialize errors array
$errors = array();
// validate elements
// eventtype
$eventtypes = array_flip(array('1', '2', '3', '4', '5'));
if (!isset($eventtypes[$eventtype])) $errors = addError("eventtype-isinvalid");
// eventname
$eventname = filter_var($eventname, FILTER_SANITIZE_STRING);
if(empty($eventname)) $errors = addError("eventname-isempty");
// description
$description = filter_var($description, FILTER_SANITIZE_STRING);
if (empty($description)) $errors = addError("description-isempty");
// file uploads
if ($hasattachments == 1) uploadFiles();
// functions
// add error
function addError($error) {
    switch ($error)
    {
        case "description-isempty":
            $errors[] = array("description-isempty" => "Please enter a description.");
            break;
        case "eventname-isempty":
            $errors[] = array("eventname-isempty" => "Please enter an event name.");
            break;
        case "eventtype-isinvalid":
            $errors[] = array("eventtype-isinvalid" => "Please select an event type.");
            break;
    } // end switch($error)
    return $errors;
} // end function addError()
// file uploads
function uploadFiles() {
    $uploader = new UploadHandler();
    // specify the list of valid extensions
    $uploader->allowedExtensions = array("txt", "pdf");
    // specify max file size in bytes
    $uploader->sizeLimit = 250 * 1024; // 250 kB
    // specify the input name set in the javascript.
    $uploader->inputName = "qqfile"; // matches Fine Uploader's default inputName value by default
    // specify the folder to temporarily save parts to use the chunking/resume feature
    $uploader->chunksFolder = "chunks";
    $method = $_SERVER["REQUEST_METHOD"];
    if ($method == "POST") {
        header("Content-Type: text/plain");
        // call handleUpload() with the name of the folder, relative to PHP's getcwd()
        $result = $uploader->handleUpload("uploads/");
        // get the name used for uploaded file
        $result["uploadName"] = $uploader->getUploadName();
    } // end if
} // end function uploadFiles()

// return response
if (!empty($errors)) $response = array("failure" => $errors);
else $response = array("success" => "Success! Your event has been posted.");
echo json_encode($response);

?>

【问题讨论】:

  • 您可能希望将您的问题精简为一个最小的可重现示例。
  • 不可重现?这就是我提供工作表单链接的原因。
  • 您的代码示例都不是堆栈溢出的堆栈 sn-ps 工具的良好候选者,尤其是第二个。两者都不是真正可执行的,也不需要是。我通常建议人们忘记堆栈 sn-ps 的存在,因为它们很少适用,并且无论如何存在堆栈溢出之外更好的替代方案(例如 jsbin)。
  • 是的,我不确定要为代码 sn-ps 使用哪个工具。这就是为什么我在 Firebug 中添加了一个工作表单的链接。

标签: php jquery jquery-validate fine-uploader jquery-forms-plugin


【解决方案1】:

按顺序回答您的问题:

  1. Fine Uploader 在单独的请求中发送每个文件,无法更改。
  2. Fine Uploader 已经为每个文件生成了一个唯一 ID (UUID)。此 ID 随上传请求一起发送。如果您想发送文件的其他数据,可以通过setParams API method 进行。这将与文件一起发送您选择的其他自定义参数。您可以为所有文件或特定文件指定新参数。
  3. 在表单模式下,Fine Uploader 拦截提交请求并通过 ajax/XHR 发送文件和所有表单字段。目前,它希望至少选择一个文件,因为表单字段作为每个选定文件的参数发送。缺少选定的文件意味着,在其当前状态下,无法发送表单字段。更改此设置需要调整 Fine Uploader 的内部代码。您可以通过不使用表单模式来解决此问题。相反,您需要在一个请求中提交表单数据,然后让 Fine Uploader 通过 API 发送任何选定的文件。
  4. Fine Uploader 应该拦截表单提交,因此每个文件应该只有一个响应。表单域随每个文件一起发送。
  5. 如果您想让文件字段对您的用户来说是可选的,这可能是必需的方法。

【讨论】:

  • 完美。对于#1,这就是我的想法。对于#2,我知道每个文件的 uuid,我在服务器端捕获它。但是,我需要为整个表单提交创建一个 uuid,这样我就不会复制新事件的创建。我可以弄清楚如何做到这一点。对于#3-5,这也是我的想法,所以我需要放入一些客户端逻辑,以便在有文件而不是没有文件时使用 Fine Uploader。
  • 根据 Ray Nicholus 的回答,我对代码进行了几处更改: 客户端:link 服务器:link 我还有一个小问题。如果用户选择然后取消选择附件复选框,我会收到没有文件上传错误警报。我寻找并找不到fineuploader 实例的destroy() 方法,我尝试用代码销毁它,但没有成功。有一个例程来至少捕获错误消息并销毁它们会很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多