将Dropzone.js与其他字段集成到现有的HTML表单中


179

我目前有一个HTML表单,用户可以填写他们希望发布的广告的详细信息。现在,我希望能够添加一个dropzone来上传待售商品的图片。

我发现Dropzone.js似乎可以满足我的大部分需求。但是,查看文档时,您似乎需要将整个表单的类指定为dropzone(而不是仅输入元素)。这意味着我的整个表单成为了dropzone

是否可以仅在表单的一部分中使用dropzone,即仅通过将元素指定为class “ dropzone”而不是整个表单来使用?

我可以使用单独的表单,但是我希望用户能够通过一个按钮提交所有表单。

另外,还有另一个图书馆可以做到这一点吗?

非常感谢

Answers:


58

这是另一种方法:div在您的表单中添加一个具有类名dropzone的,并以编程方式实现dropzone。

HTML:

<div id="dZUpload" class="dropzone">
      <div class="dz-default dz-message"></div>
</div>

jQuery的:

$(document).ready(function () {
    Dropzone.autoDiscover = false;
    $("#dZUpload").dropzone({
        url: "hn_SimpeFileUploader.ashx",
        addRemoveLinks: true,
        success: function (file, response) {
            var imgName = response;
            file.previewElement.classList.add("dz-success");
            console.log("Successfully uploaded :" + imgName);
        },
        error: function (file, response) {
            file.previewElement.classList.add("dz-error");
        }
    });
});

注意:禁用自动发现,否则Dropzone将尝试附加两次

博客文章Dropzone js + Asp.net:上传批量图像的简单方法


24
这样一来,他就无法使用默认的“提交”按钮,它也
无法回答

5
但这仍然没有使用原始表格来提交
dangel

3
这是我的问题,您已解决,例如@Satindersingh
Su4p 2015年

1
@ Su4p:很高兴能为您提供帮助,您也可以在上传时查看博客文章链接以获取详细说明以及调整大小图像选项
Satinder singh 2015年

2
这很有帮助,如果您手动设置url,则可以将任何元素设置为放置区。我使用成功处理程序将文件名发布到主要形式的隐藏/禁用字段中。
DigitalDesignDj 2015年

40

我遇到了完全相同的问题,发现Varan Sinayee的答案是唯一可以解决原始问题的答案。不过,该答案可以简化,所以这是一个简单的版本。

这些步骤是:

  1. 创建一个普通形式(不要忘记方法和enctype args,因为它不再由dropzone处理)。

  2. 在div内放入div class="dropzone"(这是Dropzone的附加方式)和id="yourDropzoneName"(用于更改选项)。

  3. 设置Dropzone的选项,以设置将在其中发布表单和文件的url,停用autoProcessQueue(因此仅当用户按下“提交”时才发生)并允许多次上传(如果需要)。

  4. 单击“提交”按钮时,将初始化功能设置为使用Dropzone代替默认行为。

  5. 仍在init函数中,使用“ sendingmultiple”事件处理程序将表单数据与文件一起发送。

瞧!现在,您可以像使用普通格式一样在$ _POST和$ _FILES中检索数据(在示例中,这将在upload.php中发生)

的HTML

<form action="upload.php" enctype="multipart/form-data" method="POST">
    <input type="text" id ="firstname" name ="firstname" />
    <input type="text" id ="lastname" name ="lastname" />
    <div class="dropzone" id="myDropzone"></div>
    <button type="submit" id="submit-all"> upload </button>
</form>

JS

Dropzone.options.myDropzone= {
    url: 'upload.php',
    autoProcessQueue: false,
    uploadMultiple: true,
    parallelUploads: 5,
    maxFiles: 5,
    maxFilesize: 1,
    acceptedFiles: 'image/*',
    addRemoveLinks: true,
    init: function() {
        dzClosure = this; // Makes sure that 'this' is understood inside the functions below.

        // for Dropzone to process the queue (instead of default form behavior):
        document.getElementById("submit-all").addEventListener("click", function(e) {
            // Make sure that the form isn't actually being sent.
            e.preventDefault();
            e.stopPropagation();
            dzClosure.processQueue();
        });

        //send all the form data along with the files:
        this.on("sendingmultiple", function(data, xhr, formData) {
            formData.append("firstname", jQuery("#firstname").val());
            formData.append("lastname", jQuery("#lastname").val());
        });
    }
}

1
这个解决方案很好并且可行,但是由于阻止了默认的提交行为,它不再重定向到下一页。
Felix G.

@TIIUNDER-它准备通过ajax调用发送表单信息而无需重新加载页面-这就是为什么有e.preventDefault();的原因。
–born2fr4g

1
@TIUNDER,您可以在成功事件中添加重定向
doflamingo

processQueue()致电后可以提交表格吗?我尝试使用submit()click(),两者都不起作用。
灰色李

1
+1这似乎是唯一可行的解​​决方案。除了做formData.append一个接一个,您还可以做 $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (很抱歉,我不知道如何在此处放置换行符)
Aximili

20

“ dropzone.js”是用于上传图像的最常用的库。如果您希望将“ dropzone.js”作为表单的一部分,则应执行以下步骤:

1)对于客户端:

HTML:

    <form action="/" enctype="multipart/form-data" method="POST">
        <input type="text" id ="Username" name ="Username" />
        <div class="dropzone" id="my-dropzone" name="mainFileUploader">
            <div class="fallback">
                <input name="file" type="file" multiple />
            </div>
        </div>
    </form>
    <div>
        <button type="submit" id="submit-all"> upload </button>
    </div>

jQuery的:

    <script>
        Dropzone.options.myDropzone = {
            url: "/Account/Create",
            autoProcessQueue: false,
            uploadMultiple: true,
            parallelUploads: 100,
            maxFiles: 100,
            acceptedFiles: "image/*",

            init: function () {

                var submitButton = document.querySelector("#submit-all");
                var wrapperThis = this;

                submitButton.addEventListener("click", function () {
                    wrapperThis.processQueue();
                });

                this.on("addedfile", function (file) {

                    // Create the remove button
                    var removeButton = Dropzone.createElement("<button class='btn btn-lg dark'>Remove File</button>");

                    // Listen to the click event
                    removeButton.addEventListener("click", function (e) {
                        // Make sure the button click doesn't submit the form:
                        e.preventDefault();
                        e.stopPropagation();

                        // Remove the file preview.
                        wrapperThis.removeFile(file);
                        // If you want to the delete the file on the server as well,
                        // you can do the AJAX request here.
                    });

                    // Add the button to the file preview element.
                    file.previewElement.appendChild(removeButton);
                });

                this.on('sendingmultiple', function (data, xhr, formData) {
                    formData.append("Username", $("#Username").val());
                });
            }
        };
    </script>

2)对于服务器端:

ASP.Net MVC

    [HttpPost]
    public ActionResult Create()
    {
        var postedUsername = Request.Form["Username"].ToString();
        foreach (var imageFile in Request.Files)
        {

        }

        return Json(new { status = true, Message = "Account created." });
    }

2
感谢您的帖子!解决了我的问题。另一个快速的问题,当没有选择(上传)图像时,此方法不起作用,该如何解决?
佐藤

顺便说一句:如果您将控制器操作与模型绑定一起使用,并像这样提交表单,则模型将为空。由于某种原因,该方法未将实际数据绑定到模型。
Edward Chopuryan

1
当autoProcessQueue = false时,不会触发任何事件
cyril

@Sato提交按钮的单击事件,您可以使用galleryfile.getAcceptedFiles()。length检查dropzone上可接受文件的长度,如果没有上传文件,则应提交表单。
Varan Sinayee

@EdwardChopuryan这与通过dropzone提交数据的方法无关。问题可能出在您的平台(例如ASP.Net MVC)上的输入标签的“命名约定”上。
Varan Sinayee

11

Enyo的教程非常出色。

我发现本教程中的示例脚本对于嵌入dropzone(即form元素)中的按钮非常有效。如果您希望按钮位于form元素之外,我可以使用click事件来完成它:

首先,HTML:

<form id="my-awesome-dropzone" action="/upload" class="dropzone">  
    <div class="dropzone-previews"></div>
    <div class="fallback"> <!-- this is the fallback if JS isn't working -->
        <input name="file" type="file" multiple />
    </div>

</form>
<button type="submit" id="submit-all" class="btn btn-primary btn-xs">Upload the file</button>

然后,脚本标签...。

Dropzone.options.myAwesomeDropzone = { // The camelized version of the ID of the form element

    // The configuration we've talked about above
    autoProcessQueue: false,
    uploadMultiple: true,
    parallelUploads: 25,
    maxFiles: 25,

    // The setting up of the dropzone
    init: function() {
        var myDropzone = this;

        // Here's the change from enyo's tutorial...

        $("#submit-all").click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            myDropzone.processQueue();
        }); 
    }
}

23
您不能在表单中包含表单并提交。
保罗

1
当我尝试这样做时,dropzone-previews容器似乎被忽略了。Dropzone只是将预览添加到表单的底部。您将需要在配置中添加'previewsContainer:'.dropzone-previews'。
亚伦·希尔

6
这不能回答原始问题。最初的问题是如何在现有表单中使用Dropzone,而不是关于触发操作的按钮位置。
CSSian

7

除了sqram所说的以外,Dropzone还有一个未公开的选项“ hiddenInputContainer”。您所要做的就是将此选项设置为希望将隐藏文件字段附加到的表单的选择器。瞧!Dropzone通常添加到身体的“ .dz-hidden-input”文件字段会神奇地移动到您的窗体中。无需更改Dropzone源代码。

现在,尽管这可以将Dropzone文件字段移动到表单中,但该字段没有名称。因此,您需要添加:

_this.hiddenFileInput.setAttribute("name", "field_name[]");

在此行之后放到dropzone.js:

_this.hiddenFileInput = document.createElement("input");

在第547行附近。


5

我对此有一个更自动化的解决方案。

HTML:

<form role="form" enctype="multipart/form-data" action="{{ $url }}" method="{{ $method }}">
    {{ csrf_field() }}

    <!-- You can add extra form fields here -->

    <input hidden id="file" name="file"/>

    <!-- You can add extra form fields here -->

    <div class="dropzone dropzone-file-area" id="fileUpload">
        <div class="dz-default dz-message">
            <h3 class="sbold">Drop files here to upload</h3>
            <span>You can also click to open file browser</span>
        </div>
    </div>

    <!-- You can add extra form fields here -->

    <button type="submit">Submit</button>
</form>

JavaScript:

Dropzone.options.fileUpload = {
    url: 'blackHole.php',
    addRemoveLinks: true,
    accept: function(file) {
        let fileReader = new FileReader();

        fileReader.readAsDataURL(file);
        fileReader.onloadend = function() {

            let content = fileReader.result;
            $('#file').val(content);
            file.previewElement.classList.add("dz-success");
        }
        file.previewElement.classList.add("dz-complete");
    }
}

Laravel:

// Get file content
$file = base64_decode(request('file'));

无需禁用DropZone Discovery,普通表单提交将能够通过标准表单序列化将文件与任何其他表单字段一起发送。

处理后,此机制会将文件内容作为base64字符串存储在隐藏的输入字段中。您可以通过标准base64_decode()方法将其解码回PHP中的二进制字符串。

我不知道这种方法是否会因为大文件而受损,但它可以处理约40MB的文件。


您如何解码和处理将与图​​像一起提交的其他字段中的数据?
萨姆

@sam无需解码其他字段。首先,不会对它们进行编码,而只会对文件进行编码。
Umair Ahmed '18

您可以共享一些html,javascript以及如何在laravel php中进行检索的示例代码。
萨姆(Sam)

1
如果要添加多个图像,则必须删除html文件输入,并为每个图像添加js队列js $('#fileUpload')。append('<input hidden name =“ files []” value ='+ content +' />'),其中content是base64编码的图像。
AleXzpm

1
@codepushr很好地回答了我们不考虑付费解决方案时的旧答案。现在我们已经购买了FileUploader,尽管它具有自己的恶作剧,但可以说它可以定制以执行几乎所有操作。
Umair Ahmed

4

您可以通过捕获来自dropzone的'sending'事件来修改formData。

dropZone.on('sending', function(data, xhr, formData){
        formData.append('fieldname', 'value');
});

1
我喜欢这个答案-但它会假定已经填充了字段名和值。这是在上载时触发的,该上载可能会在表单提交的单独时间发生。换句话说,您不能假设发送图像时已填写表格。
安东尼,

4

为了在单个请求中提交所有文件以及其他表单数据,您可以将Dropzone.js临时隐藏input节点复制到您的表单中。您可以在addedfiles事件处理程序中执行此操作:

var myDropzone = new Dropzone("myDivSelector", { url: "#", autoProcessQueue: false });
myDropzone.on("addedfiles", () => {
  // Input node with selected files. It will be removed from document shortly in order to
  // give user ability to choose another set of files.
  var usedInput = myDropzone.hiddenFileInput;
  // Append it to form after stack become empty, because if you append it earlier
  // it will be removed from its parent node by Dropzone.js.
  setTimeout(() => {
    // myForm - is form node that you want to submit.
    myForm.appendChild(usedInput);
    // Set some unique name in order to submit data.
    usedInput.name = "foo";
  }, 0);
});

显然,这是一种依赖于实现细节的解决方法。相关源代码


我基本上使用了这种方法,但是由于明显的处理延迟,最终在myDropzone.on("thumbnail", () => {})事件下挂接了文件内容处理。"addedFile"可能仍在undefined访问时立即对文件进行处理。
马蒂

我正在尝试使用此方法,它可以将隐藏文件输入字段带入表单,并且在我提交时,帖子数据显示了我的字段,files[]但是无论我做什么,它都是空白的。有任何想法吗?如果有任何区别,请在Laravel中进行。
zen

你好!为什么选择的文件可以上传,但是如果文件被删除则不能上传(错误4)?
印格斯

2

我想在这里提供一个答案,因为我也遇到过同样的问题-我们希望将$ _FILES元素作为另一种形式作为同一帖子的一部分提供。我的答案基于@mrtnmgs,但是注意到添加到该问题的评论。

首先:Dropzone通过ajax发布其数据

仅仅因为您使用该formData.append选项仍然意味着您必须解决UX操作-即这一切都在幕后发生,而不是典型的表单发布。数据已过帐到您的url参数。

其次:如果因此要模仿表单发布,则需要存储发布的数据

这需要服务器端代码来存储您的会话$_POST$_FILES会话,该会话在另一页面加载时可供用户使用,因为用户将不会转到接收已发布数据的页面。

第三:您需要将用户重定向到操作此数据的页面

现在,您已经发布了数据,并将其存储在会话中,您需要在其他页面中为用户显示/操作数据。您还需要将用户发送到该页面。

因此,对于我的示例:

[Dropzone代码:使用Jquery]

$('#dropArea').dropzone({
    url:        base_url+'admin/saveProject',
    maxFiles:   1,
    uploadMultiple: false,
    autoProcessQueue:false,
    addRemoveLinks: true,
    init:       function(){
        dzClosure = this;

        $('#projectActionBtn').on('click',function(e) {
            dzClosure.processQueue(); /* My button isn't a submit */
        });

        // My project only has 1 file hence not sendingmultiple
        dzClosure.on('sending', function(data, xhr, formData) {
            $('#add_user input[type="text"],#add_user textarea').each(function(){
                formData.append($(this).attr('name'),$(this).val());
            })
        });

        dzClosure.on('complete',function(){
            window.location.href = base_url+'admin/saveProject';
        })
    },
});

1

这只是如何以现有形式使用Dropzone.js的另一个示例。

dropzone.js:

 init: function() {

   this.on("success", function(file, responseText) {
     //alert("HELLO ?" + responseText); 
     mylittlefix(responseText);
   });

   return noop;
 },

然后,稍后在文件中

function mylittlefix(responseText) {
  $('#botofform').append('<input type="hidden" name="files[]" value="'+ responseText +'">');
}

假设您有一个id为div的div,则#botofform在上传时可以使用上传文件的名称。

注意:我的上载脚本返回了theuploadedfilename.jpeg dubblenote,您还需要制作一个清除脚本,以检查上载目录中是否有未使用的文件,并以前端非身份验证形式将它们删除.. :)


这不会将dropzone图片与其他表单字段一起提交。您正在执行的操作是正常上传图像,保存图像名称,然后重新提交带有图像名称的其余表单字段。
zen

1

这是我的示例,基于Django + Dropzone。视图已选择(必需)并提交。

<form action="/share/upload/" class="dropzone" id="uploadDropzone">
    {% csrf_token %}
        <select id="warehouse" required>
            <option value="">Select a warehouse</option>
                {% for warehouse in warehouses %}
                    <option value={{forloop.counter0}}>{{warehouse.warehousename}}</option>
                {% endfor %}
        </select>
    <button id="submit-upload btn" type="submit">upload</button>
</form>

<script src="{% static '/js/libs/dropzone/dropzone.js' %}"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script>
    var filename = "";

    Dropzone.options.uploadDropzone = {
        paramName: "file",  // The name that will be used to transfer the file,
        maxFilesize: 250,   // MB
        autoProcessQueue: false,
        accept: function(file, done) {
            console.log(file.name);
            filename = file.name;
            done();    // !Very important
        },
        init: function() {
            var myDropzone = this,
            submitButton = document.querySelector("[type=submit]");

            submitButton.addEventListener('click', function(e) {
                var isValid = document.querySelector('#warehouse').reportValidity();
                e.preventDefault();
                e.stopPropagation();
                if (isValid)
                    myDropzone.processQueue();
            });

            this.on('sendingmultiple', function(data, xhr, formData) {
                formData.append("warehouse", jQuery("#warehouse option:selected").val());
            });
        }
    };
</script>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.