Tích hợp Dropzone.js vào dạng HTML hiện có với các trường khác


181

Tôi hiện có một biểu mẫu HTML mà người dùng điền vào chi tiết của một quảng cáo mà họ muốn đăng. Bây giờ tôi muốn có thể thêm một dropzone để tải lên hình ảnh của mặt hàng để bán.

Tôi đã tìm thấy Dropzone.js dường như làm hầu hết những gì tôi cần. Tuy nhiên, khi xem xét tài liệu, có vẻ như bạn cần chỉ định lớp của toàn bộ biểu mẫu là dropzone(trái ngược với chỉ phần tử đầu vào ). Điều này có nghĩa là toàn bộ biểu mẫu của tôi trở thành dropzone .

Có thể sử dụng dropzone chỉ trong một phần của biểu mẫu của tôi, tức là bằng cách chỉ định phần tử là lớp "dropzone" , chứ không phải toàn bộ biểu mẫu?

Tôi có thể sử dụng các biểu mẫu riêng biệt, nhưng tôi muốn người dùng có thể gửi tất cả bằng một nút.

Ngoài ra, có một thư viện khác có thể làm điều này?

Cảm ơn nhiều

Câu trả lời:


59

Đây là một cách khác để làm điều đó: thêm một divtrong biểu mẫu của bạn với một dropzone tên lớp và triển khai dropzone theo chương trình.

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");
        }
    });
});

Lưu ý: Vô hiệu hóa tự động phát hiện, nếu không Dropzone sẽ cố gắng đính kèm hai lần

Bài viết trên blog : Dropzone js + Asp.net: Cách dễ dàng để tải lên hình ảnh hàng loạt


25
Cùng với đó, anh ta không thể sử dụng nút gửi mặc định, nó không trả lời câu hỏi của anh ta
clement

5
nhưng điều này vẫn không sử dụng mẫu ban đầu để gửi
dangel

3
đây là vấn đề của tôi và bạn đã giải quyết nó, ty @Satindingh
Su4p

1
@ Su4p: rất vui vì nó giúp bạn, bạn cũng có thể kiểm tra liên kết bài viết blog để biết chi tiết giải thích cùng với tùy chọn thay đổi kích thước hình ảnh trong khi tải lên
Satinder singh

2
Điều này giúp ích rất nhiều, bạn có thể thiết lập bất kỳ yếu tố nào dưới dạng dropzone nếu bạn thiết lập url theo cách thủ công. Tôi đã sử dụng trình xử lý thành công để đăng tên tệp vào trường ẩn / bị vô hiệu hóa ở dạng chính.
DigitalDesignDj

40

Tôi đã có cùng một vấn đề và thấy rằng câu trả lời của Varan Sinayee là câu hỏi duy nhất thực sự giải quyết được câu hỏi ban đầu. Câu trả lời đó có thể được đơn giản hóa, vì vậy đây là một phiên bản đơn giản hơn.

Các bước là:

  1. Tạo một biểu mẫu bình thường (đừng quên phương thức và mã hóa đối số vì điều này không được xử lý bởi dropzone nữa).

  2. Đặt một div bên trong với class="dropzone"(đó là cách Dropzone gắn vào nó) và id="yourDropzoneName"(được sử dụng để thay đổi các tùy chọn).

  3. Đặt tùy chọn của Dropzone, để đặt url nơi biểu mẫu và tệp sẽ được đăng, hủy kích hoạt autoProcessQueue (để nó chỉ xảy ra khi người dùng nhấn 'submit') và cho phép tải lên nhiều lần (nếu bạn cần).

  4. Đặt chức năng init để sử dụng Dropzone thay vì hành vi mặc định khi nhấp vào nút gửi.

  5. Vẫn trong hàm init, sử dụng trình xử lý sự kiện "sendmultipl" để gửi dữ liệu biểu mẫu cùng với các tệp.

Võngà! Bây giờ bạn có thể truy xuất dữ liệu như bạn muốn với một hình thức bình thường, trong $ _POST và $ _FILES (trong ví dụ này sẽ xảy ra trong 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>

Mã não

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
Giải pháp này rất hay và hiệu quả, nhưng nó không chuyển hướng sang trang tiếp theo nữa, vì ngăn chặn hành vi gửi mặc định.
Felix G.

@TIIUNDER - nó được chuẩn bị để gửi thông tin biểu mẫu thông qua cuộc gọi ajax mà không cần tải lại trang - đó là lý do tại sao có e.preventDefault ();
sinh2fr4g

1
@TIUNDER bạn có thể thêm chuyển hướng trong sự kiện thành công
doflamingo

Có thể gửi mẫu sau khi processQueue()gọi? Tôi cố gắng sử dụng submit()hoặc click(), cả hai đều không hoạt động.
Xám Li

1
+1 Đây dường như là giải pháp làm việc duy nhất. Thay vì thực hiện formData.append từng cái một, bạn cũng có thể làm $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (xin lỗi tôi không biết cách đặt ngắt dòng ở đây)
Aimumili

20

"Dropzone.js" là thư viện phổ biến nhất để tải lên hình ảnh. Nếu bạn muốn có "dropzone.js" như một phần của biểu mẫu của mình, bạn nên thực hiện các bước sau:

1) cho phía khách hàng:

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) cho phía máy chủ:

MVC 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
Cảm ơn vì bài đăng! Giải quyết vấn đề của tôi. Một câu hỏi nhanh khác, điều này không hoạt động khi không có hình ảnh được chọn (để tải lên), làm thế nào để giải quyết vấn đề này?
Sato

BTW: nếu bạn sử dụng hành động của bộ điều khiển với ràng buộc mô hình và gửi biểu mẫu của bạn như thế này thì mô hình sẽ trống. Vì một số lý do, phương pháp này không liên kết dữ liệu thực tế với mô hình.
Edward Chopuryan

1
khi autoProcessQueue = false không có sự kiện nào được kích hoạt
cyril

@Sato khi nhấp vào sự kiện của nút gửi, bạn có thể kiểm tra độ dài của các tệp được chấp nhận trên dropzone bằng cách sử dụng galleryfile.getAcceptedFiles (). Và nếu không có tệp nào được tải lên, bạn nên gửi biểu mẫu của mình.
Varan Sinayee

@EdwardChopuryan Điều này không liên quan đến phương pháp gửi dữ liệu theo dropzone. Có khả năng vấn đề nằm ở "quy ước đặt tên" của các thẻ đầu vào trên nền tảng của bạn, chẳng hạn như ASP.Net MVC.
Varan Sinayee

11

Hướng dẫn của Enyo là tuyệt vời.

Tôi thấy rằng tập lệnh mẫu trong hướng dẫn hoạt động tốt cho một nút được nhúng trong dropzone (tức là phần tử biểu mẫu). Nếu bạn muốn có nút bên ngoài phần tử biểu mẫu, tôi có thể hoàn thành nó bằng cách sử dụng sự kiện nhấp chuột:

Đầu tiên, 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>

Sau đó, thẻ script ....

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
Bạn không thể có một biểu mẫu trong một biểu mẫu và gửi.
paul

1
Khi tôi thử điều này, container xem trước dropzone dường như bị bỏ qua. Dropzone chỉ cần thêm các bản xem trước vào cuối biểu mẫu. Bạn sẽ cần thêm 'previewsContainer:' .dropzone-preview ',' vào cấu hình của bạn.
Aaron Hill

6
Điều này không trả lời câu hỏi ban đầu. Câu hỏi ban đầu là làm thế nào để sử dụng Dropzone với một hình thức hiện có, không phải về vị trí của nút để kích hoạt hành động.
CSSian

7

Hơn nữa với những gì sqram đã nói, Dropzone có thêm một tùy chọn không có giấy tờ, "hiddenInputContainer". Tất cả những gì bạn phải làm là đặt tùy chọn này thành bộ chọn của biểu mẫu bạn muốn trường tệp ẩn được thêm vào. Và Voila! Trường tệp ".dz-hidden-input" mà Dropzone thường thêm vào cơ thể sẽ di chuyển một cách kỳ diệu vào biểu mẫu của bạn. Không thay đổi mã nguồn Dropzone.

Bây giờ trong khi điều này hoạt động để di chuyển trường tệp Dropzone vào biểu mẫu của bạn, thì trường không có tên. Vì vậy, bạn sẽ cần phải thêm:

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

đến dropzone.js sau dòng này:

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

xung quanh dòng 547.


5

Tôi có một giải pháp tự động hơn cho việc này.

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");
    }
}

Ấu trùng:

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

Không cần phải vô hiệu hóa DropZone Discovery và việc gửi biểu mẫu thông thường sẽ có thể gửi tệp với bất kỳ trường biểu mẫu nào khác thông qua tuần tự hóa biểu mẫu tiêu chuẩn.

Cơ chế này lưu trữ nội dung tệp dưới dạng chuỗi base64 trong trường nhập ẩn khi được xử lý. Bạn có thể giải mã nó trở lại chuỗi nhị phân trong PHP thông qua tiêu chuẩnbase64_decode() phương thức .

Tôi không biết liệu phương pháp này có bị xâm phạm với các tệp lớn hay không nhưng nó hoạt động với các tệp ~ 40 MB.


Làm thế nào để bạn giải mã và xử lý dữ liệu từ các trường khác sẽ được gửi cùng với hình ảnh?
sam

@sam Không cần giải mã các trường khác. Họ không được mã hóa ở vị trí đầu tiên, chỉ có tệp được mã hóa.
Umair Ahmed

Bạn có thể chia sẻ một số mã mẫu cho html, javascript và cách truy xuất trong laravel php.
sam

1
Nếu bạn muốn thêm hình ảnh đa dạng, bạn phải xóa đầu vào tệp html và thêm nó vào js cho mỗi hình ảnh $ ('# fileUpload'). Append ('<input hidden name = "files []" value =' + content + ' /> ') trong đó nội dung là hình ảnh được mã hóa base64.
AleXzpm

1
@codepushr cũng là một câu trả lời cũ của thời gian chúng tôi không xem xét các giải pháp trả phí. Bây giờ chúng tôi đã mua FileUploader, mặc dù nó có shenanigans riêng nhưng đủ để nói rằng nó có thể được tùy chỉnh để làm hầu hết mọi thứ.
Umair Ahmed

4

Bạn có thể sửa đổi formData bằng cách bắt sự kiện 'gửi' từ dropzone của bạn.

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

1
Tôi thích câu trả lời này - nhưng nó sẽ cho rằng tên trường và giá trị đã được điền. Điều này được kích hoạt khi tải lên có thể xảy ra tại một thời điểm riêng biệt để gửi biểu mẫu. Nói cách khác, bạn không thể cho rằng khi gửi hình ảnh, biểu mẫu được điền.
Antony

4

Để gửi tất cả các tệp cùng với dữ liệu biểu mẫu khác trong một yêu cầu, bạn có thể sao chép inputcác nút ẩn tạm thời Dropzone.js vào biểu mẫu của mình. Bạn có thể làm điều này trong addedfilesxử lý sự kiện:

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

Rõ ràng đây là một cách giải quyết phụ thuộc vào chi tiết thực hiện. Mã nguồn liên quan .


Về cơ bản, tôi đã sử dụng phương pháp này, nhưng do sự chậm trễ xử lý rõ ràng, cuối cùng đã kết nối việc xử lý nội dung tệp theo myDropzone.on("thumbnail", () => {})sự kiện. Thực hiện xử lý ngay lập tức trên "addedFile"tệp có thể vẫn được undefinedtruy cập.
Matti

Tôi đang cố gắng sử dụng cái này và nó hoạt động trong việc đưa trường nhập tệp ẩn vào biểu mẫu và khi tôi gửi, dữ liệu bài đăng hiển thị trường của tôi files[]nhưng nó trống dù tôi có làm gì. Có ý kiến ​​gì không? Làm điều đó trong Laravel nếu nó làm cho bất kỳ sự khác biệt.
zen

Xin chào! Tại sao tệp được chọn không tải lên nhưng nếu tệp bị bỏ thì không (lỗi 4)?
Ingus

2

Tôi muốn đóng góp một câu trả lời ở đây vì tôi cũng đã phải đối mặt với cùng một vấn đề - chúng tôi muốn phần tử $ _FILES có sẵn như là một phần của cùng một bài đăng như một hình thức khác. Câu trả lời của tôi dựa trên @mrtnmss tuy nhiên lưu ý các ý kiến ​​được thêm vào câu hỏi đó.

Thứ nhất: Dropzone đăng dữ liệu của mình thông qua ajax

Chỉ vì bạn sử dụng formData.appendtùy chọn vẫn có nghĩa là bạn phải giải quyết các hành động UX - tức là tất cả điều này xảy ra đằng sau hậu trường và không phải là một bài mẫu điển hình. Dữ liệu được đăng lên urltham số của bạn .

Thứ hai: Nếu bạn muốn bắt chước một bài đăng mẫu, bạn sẽ cần lưu trữ dữ liệu đã đăng

Điều này đòi hỏi mã phía máy chủ để lưu trữ $_POSThoặc$_FILES trong phiên có sẵn cho người dùng khi tải trang khác vì người dùng sẽ không truy cập trang nhận dữ liệu đã đăng.

Thứ ba: Bạn cần chuyển hướng người dùng đến trang nơi dữ liệu này được xử lý

Bây giờ bạn đã đăng dữ liệu của mình, lưu trữ nó trong một phiên, bạn cần hiển thị / hành động dữ liệu đó cho người dùng trong một trang bổ sung. Bạn cần phải gửi người dùng đến trang đó.

Vì vậy, ví dụ của tôi:

[Mã Dropzone: Sử dụng 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

Đây chỉ là một ví dụ khác về cách bạn có thể sử dụng Dropzone.js trong một hình thức hiện có.

dropzone.js:

 init: function() {

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

   return noop;
 },

Sau đó, trong tập tin tôi đặt

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

Điều này giả sử bạn có div với id #botofformtheo cách đó khi tải lên, bạn có thể sử dụng tên của các tệp đã tải lên.

Lưu ý: tập lệnh tải lên của tôi đã trả về theuploadedfilename.jpeg dubblenote, bạn cũng cần tạo một tập lệnh dọn dẹp để kiểm tra thư mục tải lên cho các tệp không được sử dụng và xóa chúng .. nếu ở dạng giao diện không xác thực :)


Điều này không gửi hình ảnh dropzone cùng với các trường mẫu khác. Những gì bạn đang làm là tải lên hình ảnh bình thường, lưu tên hình ảnh và sau đó gửi lại phần còn lại của các trường mẫu bằng tên hình ảnh.
zen

1

Đây là mẫu của tôi, dựa trên Django + Dropzone. Xem đã chọn (bắt buộc) và gửi.

<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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.