Інтеграція Dropzone.js у існуючу форму HTML з іншими полями


181

На даний момент у мене є HTML-форма, яку користувачі заповнюють детально оголошення, яке хочуть розмістити. Тепер я хочу мати змогу додати зону випаду для завантаження зображень предмета для продажу.

Я знайшов Dropzone.js, який, здається, робить більшу частину того, що мені потрібно. Однак при перегляді документації виявляється, що вам потрібно вказати клас всієї форми як dropzone(на відміну від просто вхідного елемента). Це означає, що вся моя форма стає краплею зоною .

Чи можливо використовувати dropzone лише в частині моєї форми, тобто лише вказавши елемент як клас "dropzone" , а не всю форму?

Я можу використовувати окремі форми, але я хочу, щоб користувач міг подати все це однією кнопкою.

Як альтернатива, чи є ще одна бібліотека, яка може це зробити?

Велике дякую

Відповіді:


59

Ось ще один спосіб зробити це: додайте 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: простий спосіб завантаження масових зображень


25
При цьому він не може скористатися кнопкою подання за замовчуванням, вона не відповідає на його запитання
клімент

5
але це все ще не використовує оригінальну форму для подання
dangel

3
це було моєю проблемою, і ви вирішили її, ty @Satindersingh
Su4p

1
@ Su4p: Я радий, що допоможе вам, також ви можете перевірити посилання на статтю в блозі для детального пояснення разом із варіантом розміру зображення під час завантаження
Satinder singh

2
Це дуже допомогло. Ви можете налаштувати будь-який елемент як зону випаду, якщо встановити URL вручну. Я використовував обробник успіху, щоб розмістити ім'я файлу в прихованому / відключеному полі в основній формі.
DigitalDesignDj

40

У мене була точно така ж проблема, і я виявив, що відповідь Варана Сінаї була єдиною, яка фактично вирішила початкове питання. Цю відповідь можна спростити, тому ось простіша версія.

Етапи:

  1. Створіть нормальну форму (не забувайте про аргументи методу та enctype, оскільки це вже не обробляється dropzone).

  2. Помістіть діл всередину class="dropzone"(так додається Dropzone до нього) та id="yourDropzoneName"(використовується для зміни параметрів).

  3. Встановіть параметри Dropzone, встановіть URL-адресу, де будуть розміщуватися форма та файли, деактивуйте autoProcessQueue (так це відбувається лише тоді, коли користувач натисне «подати») та дозволити кілька завантажень (якщо вам це потрібно).

  4. Встановіть функцію init використовувати Dropzone замість поведінки за замовчуванням, коли натискається кнопка подання.

  5. Виконуючи функцію init, використовуйте обробник подій "sendmultiple" для надсилання даних форми разом із файлами.

Вуаля! Тепер ви можете отримати дані, як і в звичайній формі, у $ _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
Це рішення є приємним і працює, але воно більше не переспрямовує на наступну сторінку через запобігання поведінці надсилання за замовчуванням.
Фелікс Г.

@TIIUNDER - його підготовлено для надсилання інформації форми через дзвінок ajax без перезавантаження сторінки - ось чому існує e.preventDefault ();
born2fr4g

1
@TIUNDER ви можете додати переадресацію у випадку успіху
doflamingo

Чи можна подати форму після processQueue()дзвінка? Я намагаюся використовувати submit()або click(), і те, і інше не виходить.
Сірий Лі

1
+1 Це здається єдиним робочим рішенням. Замість того, щоб робити formData.додавати по черзі, ви також можете зробити це $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (вибачте, я не знаю, як тут поставити
рядкові перерви

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
Дякую за пост! Вирішив мою проблему. Ще одне швидке запитання: це не спрацьовує, якщо не вибрано жодного зображення (для завантаження), як це вирішити?
Сато

BTW: якщо ви використовуєте дії контролера з прив’язкою моделі та подаєте форму так, модель буде порожньою. Чомусь цей метод не прив'язує фактичні дані до моделі.
Едвард Шопурян

1
коли autoProcessQueue = неправда, жодні події не запускаються
Кирило

@Sato при натисканні кнопки надсилання ви можете перевірити довжину прийнятих файлів у dropzone за допомогою галереї галереї.getAcceptedFiles (). Довжина, і якщо не завантажено жодного файлу, слід надіслати форму.
Варан Сінайе

@EdwardChopuryan Це не пов’язано з методом подання даних по dropzone. Ймовірно, проблема полягає у вашому "умові іменування" вхідних тегів на вашій платформі, таких як ASP.Net MVC.
Varan Sinayee

11

Підручник Еньо відмінний.

Я виявив, що зразок сценарію в підручнику добре працював для кнопки, вбудованої в dropzone (тобто елемент форми). Якщо ви хочете мати кнопку поза елементом форми, я зміг виконати її за допомогою події клацання:

По-перше, 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, здається, ігнорується. Dropzone просто додає попередній перегляд у нижній частині форми. Вам потрібно буде додати до своєї конфігурації 'previewsContainer:' .dropzone-previews ','.
Аарон Хілл

6
Це не відповідає на початкове запитання. Первісний питання полягав у тому, як використовувати Dropzone з наявною формою, а не про розташування кнопки для запуску дії.
CSSian

7

На додаток до того, що говорив sqram, Dropzone має додатковий недокументований варіант, "hiddenInputContainer". Все, що вам потрібно зробити, це встановити цю опцію на селектор форми, до якої потрібно приєднати приховане поле файлу. І вуаля! Поле файлу ".dz-hidden-input", яке Dropzone зазвичай додає до тіла, магічно переходить у вашу форму. Не змінюється вихідний код 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 у прихованому полі введення при його обробці. Ви можете розшифрувати його назад у двійкову рядок у PHP за допомогою стандартного base64_decode()методу.

Я не знаю, чи не вдасться цей метод зіпсувати великі файли, але він працює з ~ 40MB файлами.


Як розшифрувати та обробити дані з інших полів, які будуть подані разом із зображеннями?
сам

@sam Не потрібно розшифровувати інші поля. Вони кодуються не в першу чергу, кодується лише файл.
Умаїр Ахмед

Чи можете ви поділитися зразком коду для html, javascript та як отримати в laravel php.
Сем

2
Якщо ви хочете додати неодноразові зображення, вам слід видалити вхідний файл html та додати його quing js для кожного зображення $ ('# fileUpload'). Append ('<input hidden name = "files []" value =' + content + ' /> ') де вміст - закодоване зображення base64.
AleXzpm

1
@codepushr - це стара відповідь того часу, коли ми не розглядали платні рішення. Зараз ми придбали FileUploader, хоча він має власні шенагігани, але достатньо сказати, що його можна налаштувати робити майже все.
Умаїр Ахмед

4

Ви можете змінити formData, ввівши подію "відправлення" зі своєї dropzone.

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

1
Мені подобається ця відповідь - але можна припустити, що ім’я поля та значення були заповнені. Це спрацьовує при завантаженні, яке може відбутися в окремий час до подання форми. Іншими словами, ви не можете припустити, що при надсиланні зображення форма заповнюється.
Антоній

4

Щоб надіслати всі файли поряд з іншими даними форми в одному запиті, ви можете скопіювати тимчасові приховані inputвузли Dropzone.js у вашу форму. Ви можете зробити це в 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 +'">');
}

Це передбачає, що у вас є div з id #botofformтаким чином, під час завантаження ви можете використовувати імена завантажених файлів.

Примітка: мій сценарій завантаження повернув theuploadedfilename.jpeg dubblenote, вам також потрібно буде зробити сценарій очищення, який перевіряє каталог завантажень на наявність файлів, які не використовуються, і видаляє їх.


Це зображення не надсилає краплізону разом з іншими полями форми. Ви зазвичай завантажуєте зображення, зберігаєте назви зображень, а потім повторно надсилаєте решту полів форми із назвами зображень.
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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.