Swapping elements in a list is a common task. But as a rule it is often made in a thorny way, especially if it’s Drag&Drop. And now I am going to tell you about a very easy and flexible way to do it using Marionette.js and jQuery UI Sortable.

Installing jQuery UI

We will need Sortable part only, so in order to save the traffic, I unchecked all the ticks for you here. You just need to download it.

Pay attention

We are using a reference to Marionette in the code below:

var Marionette = Backbone.Marionette;

Creating Behavior template with Marionette.Js

This functionality will be implemented with Behaviors.

Here’s the behavior code that will be responsible for sorting models inside the collection:

Behaviors.Sortable=Marionette.Behavior.extend({ 
    onRender:function(){
        var  collection=this.view.collection // Close the collection
            ,items=this.view.children._views // Get the list of  child elements 
            ,view
            ;
        for(var v in items){
            view=items[v]
            // Hook the element to the model by cid
            view.$el.attr('data-backbone-cid',view.model.cid);
        }
        this.$el.sortable({ // Make the list sortable
            axis: this.options.axis||false,
            grid: this.options.grid||false,
            containment: this.options.containment||false,
            cursor: "move",
            handle:this.options.handle||false,
            revert: this.options.revert||false,
            update: function( event, ui ) {
                var model=collection.get(ui.item.data('backbone-cid')); 
                // Get an attached model 
                collection.remove(model,{silent:true});
                 // On the quiet remove it from the collection 
                collection.add(model,{at:ui.item.index(),silent:true});
                 //And sneakily add it to the necessary index
            }
        });
    }
});

What is it?

It’s a behavior model that is made for CollectionView. It waits for onRender event and after that attaches each ItemView element to its model with the help of cid.

Then we let this list sort with the help of Drag&Drop using jQuery.

Sortable options

It is possible to pass different set of options for each type, you can read more about it in the jQuery UI documentation. Not all options are implemented in the above mentioned code, you can add your options if you want.

Sorting

When one of the elements is dragged we delete from the collection attached to it by cid model and add again by the necessary index. silent:true flag is required so that Marionette.js wouldn’t try to rearrange it all in its own way, it isn’t good at it.

Combine СollectionView and Behavior

Now let's try it in action

var IView=Marionette.ItemView.extend({// Create new ItemView
    template:'#item-template'
})
var CView=Marionette.CollectionView.extend({// Create CollectionView
    itemView:IView,
    behaviors: {// here’s all the magic works 
        Sortable:{// Apply  Sortable behavior for this type. 
                    //As an example I passed a containment  parameter 
            containment:'parent' // Now we can drag elements inside the father caddy.
        }
    }
});

And now with the help of just one line behaviors: {Sortable:{}} you can add Drag&Drop sorting of the CollectionView.

How to save it to the server?

I don’t know in what way the order of sorting is kept on your server, but with the help of the above mentioned approach you can pass the order in any format.

I use MongoDB, so without special problems with the help of сollection.toJSON() send it to the server Node.JS and save it as is. You can send to the sever an ordered array of id, which you can get with the help of

collection.pluck('id');

That's it!

Hope this article helped you.

Please leave your comments and tell me what you would like to read about.

Write your own articles at Kukuruku Hub

2 comments

Joan Boixadós
Would this be a good solution if I only need to save (PUT) the dragged item and not the entire collection?
Kukuruku Hub
It depends on what you are trying to achieve. You can save the model by calling model.save(), but then you'd probably have to have a field which would point to the right collection.