Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrating Dropzone.js into existing HTML form with other fields

People also ask

Does dropzone require jQuery?

It does not require any external libraries such as jQuery. dropzone. js has features such as thumbnail previews, progress bars, themining support and the ability to upload large files.


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


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

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

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.


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

Further to what sqram was saying, Dropzone has an additional undocumented option, "hiddenInputContainer". All you have to do is set this option to the selector of the form you want the hidden file field to be appended to. And voila! The ".dz-hidden-input" file field that Dropzone normally adds to the body magically moves into your form. No altering the Dropzone source code.

Now while this works to move the Dropzone file field into your form, the field has no name. So you will need to add:

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

to dropzone.js after this line:

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

around line 547.


I want to contribute an answer here as I too have faced the same issue - we want the $_FILES element available as part of the same post as another form. My answer is based on @mrtnmgs however notes the comments added to that question.

Firstly: Dropzone posts its data via ajax

Just because you use the formData.append option still means that you must tackle the UX actions - i.e. this all happens behind the scenes and isn't a typical form post. Data is posted to your url parameter.

Secondly: If you therefore want to mimic a form post you will need to store the posted data

This requires server side code to store your $_POST or $_FILES in a session which is available to the user on another page load as the user will not go to the page where the posted data is received.

Thirdly: You need to redirect the user to the page where this data is actioned

Now you have posted your data, stored it in a session, you need to display/action it for the user in an additional page. You need to send the user to that page as well.

So for my example:

[Dropzone code: Uses 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';
        })
    },
});