19

I have a dropzone.js instance on a web page with the following options:

autoProcessQueue:false
uploadMultiple:true
parallelUploads:20
maxFiles:20

It is programmatically instantiated, as it is part of a larger form. I have it rigged up to process the queue when the form is submitted.

The goal is for my users to be able to use the dropzone to manage images for an item, so I'd like them to be able to re-order the images by dragging and dropping the dropzone.js image previews. Is there a good way to do this? I've tried using jquery-ui's sortable but it doesn't seem to play nice with dropzone.js.

Machavity
  • 30,841
  • 27
  • 92
  • 100
ralbatross
  • 2,448
  • 4
  • 25
  • 45

5 Answers5

28

I've got it working now using jquery-ui's sortable. The trick was to make sure to use the 'items' option in sortable to pick only the dz-preview elements, because dropzone.js has the dz-message element along with the dz-preview elements in the main container. Here's how my code looks:

The HTML:

<div id="image-dropzone" class="dropzone square">

The script:

$(function() {
    $("#image-dropzone").sortable({
        items:'.dz-preview',
        cursor: 'move',
        opacity: 0.5,
        containment: '#image-dropzone',
        distance: 20,
        tolerance: 'pointer'
    });
})
ralbatross
  • 2,448
  • 4
  • 25
  • 45
  • 1
    I also have the functionality to rearrange the images and store it on server, how can I get the new order of files? – MegaBytes Mar 09 '15 at 06:23
  • Really nice, but could I ask you how to create call back function after sort-able success? – Samphors Jan 16 '16 at 03:16
  • Also I added this: `$dropzone.sortable({start: function(e, ui) { $dropzone.removeClass('dz-clickable'); ui.item.removeClass('dz-success') }, stop: function() $dropzone.addClass('dz-clickable') }, update: function(e, ui) { console.log('Item reordered!', ui.item); }` – remove dz-clickable to disable open file dialog after dragging. remove dz-success because animation played every time after drag. Also I had problem with item disappearing while dragging – there was bug in jquery-ui's sortable.js – replaced `this.document[0]` with `this.document[0].body` on line 1008 – Lev Lukomsky Jul 20 '16 at 20:12
  • @LevLukomsky What is "$dropzone"? That doesn't resolve to anything. – Aaron Jul 27 '16 at 22:35
  • @aaron assume that `$dropzone = $('.images-dropzone'); new Dropzone($dropzone.get(0), options); $dropzone.sortable(sortable_options);` – Lev Lukomsky Aug 01 '16 at 14:37
  • @ralbatross Am I correct in assuming that this should not go into the Dropzone.js file and should be entered in a separate .js file? – Mike Wiesenhart Jan 16 '17 at 20:58
  • @MikeWiesenhart Correct – ralbatross Jan 17 '17 at 22:30
  • @ralbatross Great. The above code worked for me, but they are not saving like that. Any suggestions? – Mike Wiesenhart Jan 18 '17 at 21:14
  • 1
    @MikeWiesenhart that's probably worth a separate SO question, but basically I had to maintain a bit of extra meta-data in the dropzone items and then send that along in the POST, as well as in the response from the POST – ralbatross Jan 19 '17 at 15:01
  • jquery's UI sortable is a smooth script but unfortunately it doesnt work on the mobile, unlike the SortableJS script – luke_mclachlan Apr 29 '22 at 11:18
6

Besides the code from ralbatross you will need to set the order of the file queue of dropzone..

Something like:

$("#uploadzone").sortable({
    items: '.dz-preview',
    cursor: 'move',
    opacity: 0.5,
    containment: '#uploadzone',
    distance: 20,
    tolerance: 'pointer',
    stop: function () {

        var queue = uploadzone.files;
        $('#uploadzone .dz-preview .dz-filename [data-dz-name]').each(function (count, el) {           
            var name = el.getAttribute('data-name');
            queue.forEach(function(file) {
               if (file.name === name) {
                    newQueue.push(file);
               }
            });
        });

        uploadzone.files = newQueue;

    }
});

And remember that the file is processed async, i keep an hashtable for reference when the file is done and save the order at the end.

It doesn't work with duplicate filenames

Chris
  • 8,168
  • 8
  • 36
  • 51
  • 1
    Thanks for the snippet, worked for me. However, in my dropzone build, filename is stored inside the span element so I wrote `var name = el.innerHTML;` instead of `var name = el.getAttribute('data-name');` – Atan Jun 29 '16 at 16:16
  • 2
    Same fix as Atan, as well as defining `newQueue` before trying to push anything to it: `var queue = uploadzone.files, newQueue = [];` – Nate Beaty Apr 05 '17 at 01:26
  • Interesting. Dropzone of today (5.5) must not need this odd queue hack, as it seems to work fine with .sortable directly. – IncredibleHat Oct 28 '19 at 20:41
  • @IncredibleHat I haven't used it for a long time but that could be because either you have parallelUploads to 1, or you are lucky that all files finish in the same order that they are sorted try a large file as second and a small one as first. – Chris Nov 04 '19 at 13:44
3

You can use SortableJS (https://github.com/SortableJS/Sortable)

new Sortable(document.getElementById('dropzone'), {
  draggable: '.dz-preview'
})
cnmuc
  • 6,025
  • 2
  • 24
  • 29
2

Here's another option without any plugins. On the success event callback, you can do some manual sorting:

   var rows = $('#dropzoneForm').children('.dz-image-preview').get();

    rows.sort(function (row1, row2) {
        var Row1 = $(row1).children('.preview').find('img').attr('alt');   
        var Row2 = $(row2).children('.preview').find('img').attr('alt');
        if (Row1 < Row2) {
            return -1;
        }

        if (Row1 > Row2) {
            return 1;
        }
        return 0;
    });


    $.each(rows, function (index, row) {
        $('#dropzoneForm').append(row);
    });
Greg Sipes
  • 683
  • 6
  • 16
0

this is how to reorder the preview images with duplicate file names

 //allow the reordering of the images being rendered
    $('.dropzone').sortable({
            items: '.dz-preview',
            cursor: 'move',
            opacity: 0.5,
            containment: '.dropzone',
            distance: 20,
            tolerance: 'pointer',
            stop: function () {
                var queue = myDropzone.files;
                newQueue = [];
                $('.dropzone .dz-preview .dz-filename [data-dz-name]').each(function (count, el) {
                    var name = el.innerHTML;

                    queue.every(function(file, index){ 
                        if (file.name === name) {
                            newQueue.push(file);
                            return false;
                        }
                        return true;
                    });
                });
               myDropzone.files = newQueue;
          }
        });