25

I want to add a button upload to my dropzone file uploader. currently it's uploading the file directly after selecting or dragging the file into the dropzone area. What I want to do is: 1. Select or drap file to be uploaded. 2. Validate 3. Hit or press the button upload to upload the file.

N.B: File is only being uploaded after pressing the button upload.

Here is my form

<form id='frmTarget' name='dropzone' action='upload_files.php' class='dropzone'>
   <div class='fallback'>
      <input name='file' type='file' multiple />
   </div>
   <input id='refCampaignID' name='refCampaignID' type='hidden' value=\ "$rowCampaign->CampaignID\" />
</form>

Here is my JS

Dropzone.options.frmTarget = 
    {
            url: 'upload_files.php',
            paramName: 'file',
            clickable: true,
            maxFilesize: 5,
            uploadMultiple: true, 
            maxFiles: 2,
            addRemoveLinks: true,
            acceptedFiles: '.png,.jpg,.pdf',
            dictDefaultMessage: 'Upload your files here',
            success: function(file, response)
            {
                setTimeout(function() {
                    $('#insert_pic_div').hide();
                    $('#startEditingDiv').show();
                }, 2000);
            }
        };

Here is my php post request

 foreach ($_FILES["file"] as $key => $arrDetail) 
   {
      foreach ($arrDetail as $index => $detail) {
         //print_rr($_FILES["file"][$key][$index]);
         $targetDir = "project_images/";
         $fileName = $_FILES["file"]['name'][$index];
         $targetFile = $targetDir.$fileName;

         if(move_uploaded_file($_FILES["file"]['tmp_name'][$index],$targetFile))
         {
            $db = new ZoriDatabase("tblTarget", $_REQUEST["TargetID"], null, 0);
            $db->Fields["refCampaignID"] = $_REQUEST["refCampaignID"];
            $db->Fields["strPicture"] = $fileName;
            $db->Fields["blnActive"] = 1;
            $db->Fields["strLastUser"] = $_SESSION[USER]->USERNAME;
            $result = $db->Save();

            if($result->Error == 1){
               return "Details not saved.";
            }else{
               return "Details saved.";
            }
         }else{
            return "File not uploaded.";
         }
      }
   }
Gael Musi
  • 559
  • 1
  • 6
  • 18

3 Answers3

69

You need to:

  1. Add a button:

    <button type="submit" id="button" class="btn btn-primary">Submit</button>
    
  2. Tell Dropzone not to automatically upload the file when you drop it, as it will by default. That's done with the autoProcessQueue config option:

    autoProcessQueue: false
    
  3. Since Dropzone will now not auto-upload the files, you need to manually tell it to do that when you click your button. So you need an event handler for that button click, which tells Dropzone to do the upload:

    $("#button").click(function (e) {
        e.preventDefault();
        myDropzone.processQueue();
    });
    
  4. That will just POST the uploaded file, without any of your other input fields. You probably want to post all fields, eg your refCampaignID, a CSRF token if you have one, etc. To do that, you need to copy them into the POST before sending. Dropzone has a sending event which is called just before each file is sent, where you can add a callback:

    this.on('sending', function(file, xhr, formData) {
        // Append all form inputs to the formData Dropzone will POST
        var data = $('form').serializeArray();
        $.each(data, function(key, el) {
            formData.append(el.name, el.value);
        });
    });
    

Putting it all together:

Dropzone.options.frmTarget = {
    autoProcessQueue: false,
    url: 'upload_files.php',
    init: function () {

        var myDropzone = this;

        // Update selector to match your button
        $("#button").click(function (e) {
            e.preventDefault();
            myDropzone.processQueue();
        });

        this.on('sending', function(file, xhr, formData) {
            // Append all form inputs to the formData Dropzone will POST
            var data = $('#frmTarget').serializeArray();
            $.each(data, function(key, el) {
                formData.append(el.name, el.value);
            });
        });
    }
}
Don't Panic
  • 9,803
  • 5
  • 25
  • 44
  • How can I send a 'csrf-token' with that? – Udara Aug 14 '18 at 03:44
  • csrf-token token issue fixed after adding headers before `autoProcessQueue` attribute `headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, ` – Udara Aug 14 '18 at 04:04
  • @Udara Step 4 of the answer shows the code which will include all inputs in a form in the POSTed data. If you have a CSRF field in your form, it will be sent - no need to also add it as a header. – Don't Panic Aug 14 '18 at 09:57
  • 1
    yeah, that works perfectly, but what if we want to do server-side validation. the queue will be empty if there is a validation error – Mohamed Salah Jun 04 '19 at 14:49
  • How to update file before `myDropzone.processQueue();` – Mangosteen Apr 20 '20 at 00:19
5

Thought I'd add a pure vanilla JS solution as well, no jQuery.

/* 'dropform' is a camelized version of your dropzone form's ID */
      Dropzone.options.dropform = {
        /* Add all your configuration here */
        autoProcessQueue: false,

        init: function()
        {
          let myDropzone = this;
          /* 'submit-dropzone-btn' is the ID of the form submit button */
          document.getElementById('submit-dropzone-btn').addEventListener("click", function (e) {
              e.preventDefault();
              myDropzone.processQueue();
          });

          this.on('sending', function(file, xhr, formData) 
          {
            /* OPTION 1 (not recommended): Construct key/value pairs from inputs in the form to be sent off via new FormData
               'dropform' is the ID of your dropzone form
               This method still works, but it's submitting a new form instance.  */
              formData = new FormData(document.getElementById('dropform'));

             /* OPTION 2: Append inputs to FormData */
              formData.append("input-name", document.getElementById('input-id').value);
          });
        }
      };

NOTE: Setting up Event Listeners such as the sending one we are doing here should be put inside the init function. If you were to place them elsewhere, for example:

init: function() 
{
    //...
},
sending: function(file, xhr, formData) 
{
  //... logic before each file send
}

this will override the default logic dropzone provides for the sending Event listener, and can cause unintended side effects. You should only do this if you know what you're doing.

Nathan
  • 925
  • 1
  • 5
  • 12
0

For Vue Js

Install the vue2-dropzone if not installed

On your desire component:

<div class="form-group">
                        <label for="">Product Name</label>
                        <input type="text" v-model="product_name" placeholder="Product Name" class="form-control">
                    </div>
                    <div class="form-group">
                        <label for="">Product SKU</label>
                        <input type="text" v-model="product_sku" placeholder="sku" class="form-control">
                    </div>
<div class="card shadow mb-4">
                <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                    <h6 class="m-0 font-weight-bold text-primary">Media</h6>
                </div>
                <div class="card-body border">
                    <vue-dropzone ref="myVueDropzone" id="dropzone" :options="dropzoneOptions" v-on:vdropzone-sending="sendingEvent"></vue-dropzone>
                </div>
            </div>

Save Button:

 <button @click="saveProduct" type="submit" class="btn btn-lg btn-primary">Save</button>

within the script tag

import vue2Dropzone from 'vue2-dropzone'

import 'vue2-dropzone/dist/vue2Dropzone.min.css'

 data() {
    return {
        product_name: '',
        product_sku: '',
      
        dropzoneOptions: {
            url: "/product/images",
            thumbnailWidth: 150,
            maxFilesize: 0.5,
            addRemoveLinks: true,
            autoProcessQueue:false,
            uploadMultiple:true,
            headers: {"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').getAttribute('content')}
        }
    }
},
methods: {
    saveProduct() {
        this.$refs.myVueDropzone.processQueue();
    },
    sendingEvent (file, xhr, formData) {
        formData.append("title", this.product_name);
        formData.append("sku", this.product_sku);
        console.log(formData);
    }

}

For More Details Please Visit These:

https://rowanwins.github.io/vue-dropzone/docs/dist/#/additionalParams

https://www.dropzonejs.com/#configuration-options

GitHub Issue: https://github.com/rowanwins/vue-dropzone/issues/476

alamRIku
  • 1
  • 1