Integrating Dropzone.js into existing HTML form with other fields

245,886

Solution 1

Here's another way to do it: add a div in your form with a classname dropzone, and implement dropzone programmatically.

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

Note : Disabling autoDiscover, otherwise Dropzone will try to attach twice

Solution 2

I had the exact same problem and found that Varan Sinayee's answer was the only one that actually solved the original question. That answer can be simplified though, so here's a simpler version.

The steps are:

  1. Create a normal form (don't forget the method and enctype args since this is not handled by dropzone anymore).

  2. Put a div inside with the class="dropzone" (that's how Dropzone attaches to it) and id="yourDropzoneName" (used to change the options).

  3. Set Dropzone's options, to set the url where the form and files will be posted, deactivate autoProcessQueue (so it only happens when user presses 'submit') and allow multiple uploads (if you need it).

  4. Set the init function to use Dropzone instead of the default behavior when the submit button is clicked.

  5. Still in the init function, use the "sendingmultiple" event handler to send the form data along wih the files.

Voilà ! You can now retrieve the data like you would with a normal form, in $_POST and $_FILES (in the example this would happen in 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());
        });
    }
}

Solution 3

The "dropzone.js" is the most common library for uploading images. If you want to have the "dropzone.js" as just part of your form, you should do the following steps:

1) for the client side:

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) for the server side:

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

Solution 4

I have a more automated solution for this.

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

No need to disable DropZone Discovery and the normal form submit will be able to send the file with any other form fields through standard form serialization.

This mechanism stores the file contents as base64 string in the hidden input field when it gets processed. You can decode it back to binary string in PHP through the standard base64_decode() method.

I don't know whether this method will get compromised with large files but it works with ~40MB files.

Solution 5

Enyo's tutorial is excellent.

I found that the sample script in the tutorial worked well for a button embedded in the dropzone (i.e., the form element). If you wish to have the button outside the form element, I was able to accomplish it using a click event:

First, the 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>

Then, the script tag....

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();
        }); 
    }
}
Share:
245,886

Related videos on Youtube

Ben Thompson
Author by

Ben Thompson

Previous experience with Java, php, sql. Now attempting ios development. Java -&gt; Objective C is ok. SQL -&gt; Core Data much harder!!!

Updated on July 23, 2021

Comments

  • Ben Thompson
    Ben Thompson almost 3 years

    I currently have a HTML form which users fill in details of an advert they wish to post. I now want to be able to add a dropzone for uploading images of the item for sale.

    I have found Dropzone.js which seems to do most of what I need. However, when looking into the documentation, it appears that you need to specify the class of the whole form as dropzone (as opposed to just the input element). This then means that my entire form becomes the dropzone.

    Is it possible to use the dropzone in just part of my form, i.e. by only specifying the element as class "dropzone", rather than the whole form?

    I could use separate forms, but I want the user to be able to submit it all with one button.

    Alternatively, is there another library that can do this?

    Many thanks

  • paul
    paul over 10 years
    You cannot have a form inside a form and submit.
  • Aaron Hill
    Aaron Hill over 9 years
    When I try this, the dropzone-previews container seems to be ignored. Dropzone just adds the previews to the bottom of the form. You will need to add 'previewsContainer: '.dropzone-previews',' to your configuration.
  • CSSian
    CSSian about 9 years
    This doesn't answer the original question. The original question was how to use Dropzone with an existing form, not about the location of the button to trigger the action.
  • clement
    clement about 9 years
    With that, he can't use the default submit button, it doesn't respond to his question
  • Satinder singh
    Satinder singh almost 9 years
    @clement: OP doesn't want to add 'dropzone' class in form tag, coz this make whole form as dropzone. So with my answer he can add separate div inside form tag or outside form like as popup modal and by jQuery initialize dropzone.
  • Satinder singh
    Satinder singh almost 9 years
    Its Asynchronous so file get save without submit button, On submit he can save uploaded files name into db
  • dangel
    dangel almost 9 years
    but this still doesn't use the original form to submit
  • Su4p
    Su4p over 8 years
    this was my issue and you resolved it, ty @Satindersingh
  • Satinder singh
    Satinder singh over 8 years
    @Su4p : am glad it helps you, also you can check blog article link for details explanation along with resize image option while uploading
  • DigitalDesignDj
    DigitalDesignDj over 8 years
    @dangel I thought that was what I wanted too, but I am very happy with the resulting solution. I suggest you just submit the uploads right away.
  • DigitalDesignDj
    DigitalDesignDj over 8 years
    This helped a lot, you can setup any element as a dropzone if you setup the url manually. I used the success handler to post the filename to a hidden/disabled field in the primary form.
  • Sato
    Sato about 8 years
    Thanks for the post! Solved my problem. Another quick question, this does not work when no images selected(to upload), how to solve this?
  • Felix G.
    Felix G. about 8 years
    This solution is nice and works, but it doesn't redirect to the next page anymore, because of preventing the default submit behavior.
  • Rusty
    Rusty about 8 years
    To the beginners using Dropzone.js. To select a file, you will have to click on the div itself which is in this answer <div class="dz-default dz-message"></div>
  • born2fr4g
    born2fr4g almost 8 years
    @TIIUNDER - its prepared for sending form info via ajax call without page reload - thats why there is e.preventDefault();
  • Edward Chopuryan
    Edward Chopuryan over 7 years
    BTW: if you use controller action with model binding and submit your form like this the model will be empty. For some reason this method doesn't bind the actual data to the model.
  • doflamingo
    doflamingo over 7 years
    @TIUNDER you can add redirect in success event
  • Matti
    Matti over 6 years
    I basically used this approach, but due to apparent processing delays, in the end hooked up the file content processing under the myDropzone.on("thumbnail", () => {}) event. Doing the processing immediately on "addedFile" the file might still be undefined upon access.
  • sam
    sam over 6 years
    How do you decode and process data from other fields that will be submitted together with the images?
  • Umair Ahmed
    Umair Ahmed over 6 years
    @sam There is no need to decode the other fields. They are not getting encoded in the first place, only the file gets encoded.
  • sam
    sam over 6 years
    Can you share some sample code for the html ,javascript and how to retrieve in laravel php.
  • bungdito
    bungdito about 6 years
    the upload process with that html and javascript seems works to me, but not work when I want to process on server side script.. i dont understand how to decode using base64_decode() on codeigniter controller to upload file :D
  • bungdito
    bungdito about 6 years
    i used file_put_contents() to save decoded image file, it's works.. but the file can't open/view
  • Umair Ahmed
    Umair Ahmed about 6 years
    @bungdito Sorry, can't say anything about CI. I haven't done file handling in it.
  • Grey Li
    Grey Li almost 6 years
    Is it possible to submit the form after processQueue() call? I try to use submit() or click(), both not work.
  • cyril
    cyril over 5 years
    when autoProcessQueue= false no events are fired
  • Varan Sinayee
    Varan Sinayee over 5 years
    @Sato on click event of submit button you can check the length of accepted files on dropzone by using galleryfile.getAcceptedFiles().length and if there is no file uploaded you should submit your form.
  • Varan Sinayee
    Varan Sinayee over 5 years
    @EdwardChopuryan This is not related to the method of submiting data by dropzone. Likely the problem is on your "naming convention" of input tags on your platform such as ASP.Net MVC.
  • Emiel Bruijntjes
    Emiel Bruijntjes over 5 years
    +1 This seems to be the only working solution. Instead of doing formData.append one by one, you can also do $(":input[name]", $("form")).each(function () { formData.append(this.name, $(':input[name=' + this.name + ']', $("form")).val()); }); (sorry I don't know how to put linebreaks here)
  • AleXzpm
    AleXzpm over 5 years
    this will only work for one image, if you try to add more the $('#file').val(content); will override the input and only the last image will be sent to the server, how can I change this to send multiple images?
  • Umair Ahmed
    Umair Ahmed over 5 years
    @AleXzpm Sorry, that was the first and last time I used Dropzone, can't help you for the time being.
  • AleXzpm
    AleXzpm over 5 years
    If you want to add mutiple images you have to remove the html file input and add it quing js for each image $('#fileUpload').append('<input hidden name="files[]" value='+content+'/>') where content is the base64 encoded image.
  • Umair Ahmed
    Umair Ahmed over 5 years
    @AleXzpm if you can suggest an edit, please do so, I'll accommodate it. Or you can post a separate answer extending mine.
  • Leoh
    Leoh over 5 years
    how can i append another input file for a single image?
  • zen
    zen about 5 years
    I'm trying to use this and it works in bringing the hidden file input field to the form, and when I submit, the post data shows my field files[] but it is blank no matter what I do. Any ideas? Doing it in Laravel if it makes any difference.
  • zen
    zen about 5 years
    This doesn't submit dropzone images together with other form fields. What you're doing is uploading images normally, saving the image names, and then re-submitting rest of the form fields with image names.
  • Radderz
    Radderz about 5 years
    There is already an option within dropzone.js to set the autoDiscover = false. Setting this option within the document load was too late in the page execution cycle for me.
  • Sem
    Sem over 4 years
    Not sure why, but I have to use $('#myDropzone').dropzone({...}) instead of Dropzone.options.myDropzone. Other than that, worked nicely.
  • Antony
    Antony over 4 years
    I like this answer - but it would assume that fieldname and value have been populated. This is triggered on the upload which may occur at a separate time to the form submission. In otherwords you can't assume that when sending the image the form is filled out.
  • codepushr
    codepushr over 4 years
    This won't work reliably, as the input fields value has a browser capped max size. In my case the uploaded file is capped at 384kb, due to the base64 string not fitting completely into the value.
  • Ingus
    Ingus about 4 years
    Perfect! This is the closest i need!
  • Ingus
    Ingus almost 4 years
    Hello! Why does selected file does upload but if file is dropped then not (error 4)?
  • Bodo
    Bodo over 3 years
    @doflamingo I found it better to redirect/show confirmation inside the completemultiple event handler. Doing so in the success handler made it execute multiple times (for each file attached), which sometimes even interrupted the form upload altogether.
  • ucMedia
    ucMedia over 3 years
    Works like charm!
  • Shehroz Altaf
    Shehroz Altaf over 3 years
    It is working, But I am uploading 3 images, it is only sending 2 images on the backend. I have changed this below code: maxFiles: 10, uploadMultiple: true, Why it is sending only 2 images?
  • Antony
    Antony over 3 years
    I would try with an alternative image and see if its a problem with the files. Alternatively does your PHP/ASP etc give you any errors? It could be the image is too big, not enough disc space, server limits/settings etc.
  • Shehroz Altaf
    Shehroz Altaf over 3 years
    No. My PHP has no error. It is uploading images correctly. However, I got the solution. I changed below lines: url: myURL uploadMultiple: true, parallelUploads: 25, maxFiles: 25, autoProcessQueue: false, addRemoveLinks: true,
  • aross
    aross about 3 years
    This is the only answer that works with a plain form submit, so does not require JS to handle the form submit.
  • Rich
    Rich about 3 years
    I find your explanations very interesting. I can't get the elements to go to the processing page. I think it has to do with sessions. Could you give an example of the php processing page or indicate why my _FILE and _POST elements are not resolving.
  • Antony
    Antony about 3 years
    Just post to a page that does <?php print_r($_FILES); print_r($_POST); ?> and analyse it through the Browser console > Networking tab (thats what its called in Chrome) and see what outputs.
  • Santosh Dangare
    Santosh Dangare over 2 years
    I got exactly what I'am looking for, thank you @Satindersingh
  • Hodorogea Alexandru
    Hodorogea Alexandru about 2 years
    I get Uncaught ReferenceError: dzClosure is not defined when using this :( Does anyone know how I could fix that?
  • mending3
    mending3 about 2 years
    is this ajax request?