Mengintegrasikan Dropzone.js ke dalam formulir HTML yang ada dengan bidang lain

181

Saat ini saya memiliki formulir HTML di mana pengguna mengisi rincian iklan yang ingin mereka posting. Sekarang saya ingin dapat menambahkan dropzone untuk mengunggah gambar barang yang dijual.

Saya telah menemukan Dropzone.js yang tampaknya melakukan sebagian besar yang saya butuhkan. Namun, ketika melihat ke dalam dokumentasi, tampak bahwa Anda perlu menentukan kelas dari seluruh formulir sebagai dropzone(bukan hanya elemen input ). Ini kemudian berarti bahwa seluruh formulir saya menjadi dropzone .

Apakah mungkin untuk menggunakan dropzone hanya di sebagian dari formulir saya, yaitu dengan hanya menetapkan elemen sebagai kelas "dropzone" , daripada seluruh formulir?

Saya dapat menggunakan formulir terpisah, tetapi saya ingin pengguna dapat mengirimkan semuanya dengan satu tombol.

Atau, apakah ada perpustakaan lain yang bisa melakukan ini?

Terimakasih banyak

Ben Thompson
sumber

Jawaban:

59

Berikut cara lain untuk melakukannya: tambahkan divformulir Anda dengan dropzone classname, dan terapkan dropzone secara terprogram.

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

Catatan: Menonaktifkan autoDiscover, jika tidak Dropzone akan mencoba melampirkan dua kali

Artikel Blog : Dropzone js + Asp.net: Cara mudah untuk mengunggah gambar Massal

Satinder singh
sumber
25
Dengan itu, ia tidak dapat menggunakan tombol kirim default, itu tidak menanggapi pertanyaannya
clement
5
tetapi ini masih tidak menggunakan bentuk asli untuk mengirim
dangel
3
ini masalah saya dan Anda menyelesaikannya, ty @Satindersingh
Su4p
1
@ Su4p: saya senang ini membantu Anda, Anda juga dapat memeriksa tautan artikel blog untuk penjelasan detail beserta opsi pengubahan ukuran gambar saat mengunggah
Satinder singh
2
Ini sangat membantu, Anda dapat mengatur elemen apa saja sebagai dropzone jika Anda mengatur url secara manual. Saya menggunakan penangan sukses untuk memposting nama file ke bidang tersembunyi / dinonaktifkan dalam bentuk utama.
DigitalDesignDj
40

Saya memiliki masalah yang sama persis dan menemukan bahwa jawaban Varan Sinayee adalah satu-satunya yang benar-benar menyelesaikan pertanyaan aslinya. Jawaban itu dapat disederhanakan, jadi inilah versi yang lebih sederhana.

Langkah-langkahnya adalah:

  1. Buat formulir normal (jangan lupa metode dan enctype args karena ini tidak lagi ditangani oleh dropzone).

  2. Letakkan div di dalamnya dengan class="dropzone"(itulah yang dilampirkan Dropzone padanya) dan id="yourDropzoneName"(digunakan untuk mengubah opsi).

  3. Setel opsi Dropzone, untuk mengatur url tempat formulir dan file akan diposting, nonaktifkan autoProcessQueue (jadi itu hanya terjadi ketika pengguna menekan 'kirim') dan mengizinkan beberapa unggahan (jika Anda membutuhkannya).

  4. Setel fungsi init untuk menggunakan Dropzone alih-alih perilaku default saat tombol kirim diklik.

  5. Masih dalam fungsi init, gunakan pengendali event "sendmultiple" untuk mengirim data formulir bersama file.

Voa! Anda sekarang dapat mengambil data seperti yang Anda lakukan dengan formulir normal, dalam $ _POST dan $ _FILES (dalam contoh ini akan terjadi di 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());
        });
    }
}
mrtnmgs
sumber
1
Solusi ini bagus dan berfungsi, tetapi tidak mengalihkan ke halaman berikutnya lagi, karena mencegah perilaku pengiriman default.
Felix G.
@TIIUNDER - siap untuk mengirim info formulir melalui panggilan ajax tanpa memuat ulang halaman - itulah sebabnya ada e.preventDefault ();
born2fr4g
1
@TIUNDER Anda dapat menambahkan arahan ulang dalam acara sukses
doflamingo
Apakah mungkin untuk mengirimkan formulir setelah processQueue()panggilan? Saya mencoba menggunakan submit()atau click(), keduanya tidak bekerja.
Gray Li
1
+1 Ini sepertinya satu-satunya solusi yang berfungsi. Alih-alih melakukan formData.append satu per satu, Anda juga dapat melakukannya $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (maaf saya tidak tahu bagaimana cara membuat linebreak di sini)
Aximili
20

"Dropzone.js" adalah perpustakaan paling umum untuk mengunggah gambar. Jika Anda ingin memiliki "dropzone.js" hanya sebagai bagian dari formulir Anda, Anda harus melakukan langkah-langkah berikut:

1) untuk sisi klien:

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) untuk sisi server:

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." });
    }
Varan Sinayee
sumber
2
Terima kasih untuk kirimannya! Memecahkan masalah saya. Pertanyaan cepat lain, ini tidak berfungsi ketika tidak ada gambar yang dipilih (untuk mengunggah), bagaimana mengatasinya?
Sato
BTW: jika Anda menggunakan aksi pengontrol dengan model mengikat dan mengirimkan formulir Anda seperti ini model akan kosong. Untuk beberapa alasan metode ini tidak mengikat data aktual ke model.
Edward Chopuryan
1
ketika autoProcessQueue = false tidak ada acara yang dipecat
cyril
@Sato pada acara klik tombol kirim Anda dapat memeriksa panjang file yang diterima di dropzone dengan menggunakan galleryfile.getAcceptedFiles (). Length dan jika tidak ada file yang diunggah, Anda harus mengirimkan formulir Anda.
Varan Sinayee
@ EdwardChopuryan Ini tidak terkait dengan metode pengiriman data dengan dropzone. Kemungkinan masalahnya adalah pada "konvensi penamaan" Anda dari tag input pada platform Anda seperti ASP.Net MVC.
Varan Sinayee
11

Tutorial Enyo sangat bagus.

Saya menemukan bahwa skrip sampel dalam tutorial berfungsi dengan baik untuk tombol yang disematkan di dropzone (yaitu, elemen bentuk). Jika Anda ingin memiliki tombol di luar elemen formulir, saya dapat menyelesaikannya menggunakan acara klik:

Pertama, 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>

Kemudian, tag skrip ....

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();
        }); 
    }
}
kablamus
sumber
23
Anda tidak dapat memiliki formulir di dalam formulir dan mengirimkan.
paul
1
Ketika saya mencoba ini, wadah dropzone-preview tampaknya diabaikan. Dropzone hanya menambahkan pratinjau ke bagian bawah formulir. Anda perlu menambahkan 'previewsContainer:' .dropzone-previews ',' ke konfigurasi Anda.
Aaron Hill
6
Ini tidak menjawab pertanyaan awal. Pertanyaan aslinya adalah bagaimana cara menggunakan Dropzone dengan formulir yang ada, bukan tentang lokasi tombol untuk memicu tindakan.
CSSian
7

Lebih jauh dari apa yang dikatakan sqram, Dropzone memiliki opsi tambahan tanpa dokumen, "hiddenInputContainer". Yang harus Anda lakukan adalah mengatur opsi ini ke pemilih formulir yang Anda inginkan bidang file yang tersembunyi akan ditambahkan. Dan voila! Bidang file ".dz-hidden-input" yang biasanya ditambahkan Dropzone ke tubuh secara ajaib pindah ke formulir Anda. Tidak mengubah kode sumber Dropzone.

Sekarang sementara ini berfungsi untuk memindahkan bidang file Dropzone ke formulir Anda, bidang tersebut tidak memiliki nama. Jadi, Anda perlu menambahkan:

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

ke dropzone.js setelah baris ini:

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

sekitar garis 547.

Codedragon
sumber
5

Saya punya solusi yang lebih otomatis untuk ini.

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

Tidak perlu menonaktifkan DropZone Discovery dan pengiriman formulir normal akan dapat mengirim file dengan bidang formulir lain melalui serialisasi formulir standar.

Mekanisme ini menyimpan konten file sebagai string base64 di bidang input tersembunyi saat diproses. Anda dapat mendekodekannya kembali ke string biner dalam PHP melalui base64_decode()metode standar .

Saya tidak tahu apakah metode ini akan dikompromikan dengan file besar tetapi berfungsi dengan ~ 40MB file.

Umair Ahmed
sumber
Bagaimana Anda memecahkan kode dan memproses data dari bidang lain yang akan dikirimkan bersama dengan gambar?
sam
@sam Tidak perlu mendekodekan bidang lainnya. Mereka tidak disandikan di tempat pertama, hanya file yang disandikan.
Umair Ahmed
Bisakah Anda membagikan beberapa contoh kode untuk html, javascript dan cara mengambil di laravel php.
sam
1
Jika Anda ingin menambahkan gambar mutiple Anda harus menghapus input file html dan menambahkannya quing js untuk setiap gambar $ ('# fileUpload'). Append ('<input hidden name = "files []" value =' + content + ' /> ') di mana konten adalah gambar yang disandikan base64.
AleXzpm
1
@codepushr juga merupakan jawaban lama saat kami tidak mempertimbangkan solusi berbayar. Sekarang kita telah membeli FileUploader, meskipun ia memiliki shenanigans sendiri tetapi cukup untuk mengatakan itu dapat disesuaikan untuk melakukan hampir semua hal.
Umair Ahmed
4

Anda dapat mengubah formData dengan menangkap acara 'pengiriman' dari dropzone Anda.

dropZone.on('sending', function(data, xhr, formData){
        formData.append('fieldname', 'value');
});
shawnrushefsky
sumber
1
Saya suka jawaban ini - tetapi akan mengasumsikan bahwa nama field dan nilai telah diisi. Ini dipicu pada unggahan yang dapat terjadi pada waktu yang terpisah dengan pengiriman formulir. Dengan kata lain, Anda tidak dapat berasumsi bahwa saat mengirim gambar, formulir diisi.
Antony
4

Untuk mengirimkan semua file bersama dengan data formulir lainnya dalam satu permintaan, Anda dapat menyalin Dropzone.js inputnode tersembunyi sementara ke dalam formulir Anda. Anda dapat melakukan ini dalam addedfilesevent handler:

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

Jelas ini adalah solusi yang tergantung pada detail implementasi. Kode sumber terkait .

Leonid Vasilev
sumber
Saya pada dasarnya menggunakan pendekatan ini, tetapi karena keterlambatan pemrosesan yang jelas, pada akhirnya menghubungkan pengolahan konten file di bawah myDropzone.on("thumbnail", () => {})acara tersebut. Melakukan pemrosesan segera pada "addedFile"file mungkin masih dapat undefineddiakses.
Matti
Saya mencoba menggunakan ini dan berfungsi membawa bidang input file tersembunyi ke formulir, dan ketika saya kirim, data posting menunjukkan bidang saya files[]tetapi kosong apa pun yang saya lakukan. Ada ide? Melakukannya di Laravel jika ada bedanya.
zen
Halo! Mengapa file yang dipilih tidak diunggah tetapi jika file dijatuhkan maka tidak (kesalahan 4)?
Ingus
2

Saya ingin berkontribusi jawaban di sini karena saya juga menghadapi masalah yang sama - kami ingin elemen $ _FILES tersedia sebagai bagian dari pos yang sama dengan formulir lain. Jawaban saya didasarkan pada @ mrtnmgs namun mencatat komentar yang ditambahkan ke pertanyaan itu.

Pertama: Dropzone memposting datanya melalui ajax

Hanya karena Anda menggunakan formData.appendopsi masih berarti bahwa Anda harus menangani tindakan UX - yaitu ini semua terjadi di belakang layar dan bukan bentuk posting yang khas. Data diposting ke urlparameter Anda .

Kedua: Jika Anda ingin menirukan postingan form, Anda perlu menyimpan data yang diposting

Ini memerlukan kode sisi server untuk menyimpan $_POSTatau$_FILES dalam sesi yang tersedia untuk pengguna di halaman lain karena pengguna tidak akan pergi ke halaman di mana data yang diposting diterima.

Ketiga: Anda harus mengarahkan pengguna ke halaman tempat data ini ditindaklanjuti

Sekarang Anda telah memposting data Anda, menyimpannya dalam satu sesi, Anda perlu menampilkan / mengambil tindakan untuk pengguna di halaman tambahan. Anda perlu mengirim pengguna ke halaman itu juga.

Jadi untuk contoh saya:

[Kode Dropzone: Menggunakan 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';
        })
    },
});
Antony
sumber
1

Ini hanyalah contoh lain bagaimana Anda bisa menggunakan Dropzone.js dalam formulir yang ada.

dropzone.js:

 init: function() {

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

   return noop;
 },

Lalu, nanti dalam file yang saya masukkan

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

Ini mengasumsikan Anda memiliki div dengan id #botofform seperti itu saat mengunggah Anda dapat menggunakan nama file yang diunggah.

Catatan: skrip unggah saya mengembalikan dubblenoteupuploadedfilename.jpeg Anda juga perlu membuat skrip pembersihan yang memeriksa direktori unggahan untuk file yang tidak digunakan dan menghapusnya .. jika dalam bentuk front-end tidak diautentikasi :)

taggart
sumber
Ini tidak mengirim gambar dropzone bersama dengan bidang formulir lainnya. Apa yang Anda lakukan adalah mengunggah gambar secara normal, menyimpan nama gambar, dan kemudian mengirimkan kembali bidang formulir lainnya dengan nama gambar.
zen
1

Ini contoh saya, berdasarkan Django + Dropzone. Lihat telah memilih (wajib) dan mengirimkan.

<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>
smartworld-dm
sumber