Saving jQuery UI Sort for Backbone.js Collection

I have a collection of Backbone.js that I would like to sort using jQuery UI Sortable. Nothing special, I just have a list that I would like to sort.

The problem is that I'm not sure how to get the current order of elements after sorting and report this to the collection. Sorting can serialize itself, but it will not give me the model data that I need to provide collections.

Ideally, I would just like to get an array of the current order of models in the collection and use the reset method for the collection, but I'm not sure how to get the current order. Share any ideas or examples to get an array with the current order of the model.

+45
javascript jquery-ui backbone.js-collections
Apr 13 2018-12-12T00:
source share
3 answers

I did this using jQuery UI Sortable to trigger an event in the element view when the element was dropped. Then I can trigger another event in the element view, which includes the model as data to which the collection view is bound. Then the collection view may be responsible for updating the sort order.

Working example

http://jsfiddle.net/7X4PX/260/

jQuery UI Sortable

$(document).ready(function() { $('#collection-view').sortable({ // consider using update instead of stop stop: function(event, ui) { ui.item.trigger('drop', ui.item.index()); } }); }); 

The stop event is tied to a function that fires a drop in the DOM node for an element with the element index (provided by jQuery UI) as data.

View Position

 Application.View.Item = Backbone.View.extend({ tagName: 'li', className: 'item-view', events: { 'drop' : 'drop' }, drop: function(event, index) { this.$el.trigger('update-sort', [this.model, index]); }, render: function() { $(this.el).html(this.model.get('name') + ' (' + this.model.get('id') + ')'); return this; } }); 

The drop event is tied to the drop function, which fires the update-sort event in the representation of DOM node elements with data [this.model, index] . This means that we are passing the current model and index (from jQuery UI sortable) who is associated with the update-sort event.

View items (collections)

 Application.View.Items = Backbone.View.extend({ events: { 'update-sort': 'updateSort' }, render: function() { this.$el.children().remove(); this.collection.each(this.appendModelView, this); return this; }, appendModelView: function(model) { var el = new Application.View.Item({model: model}).render().el; this.$el.append(el); }, updateSort: function(event, model, position) { this.collection.remove(model); this.collection.each(function (model, index) { var ordinal = index; if (index >= position) { ordinal += 1; } model.set('ordinal', ordinal); }); model.set('ordinal', position); this.collection.add(model, {at: position}); // to update ordinals on server: var ids = this.collection.pluck('id'); $('#post-data').html('post ids to server: ' + ids.join(', ')); this.render(); } }); 

The Items view is bound to the update-sort event, and the function uses the data transmitted by the event (model and index). The model is removed from the collection, the ordinal attribute is updated for each remaining element, and the order of the elements by identifier is sent to the server to store the state.

Collection

 Application.Collection.Items = Backbone.Collection.extend({ model: Application.Model.Item, comparator: function(model) { return model.get('ordinal'); }, }); 

There is a comparator function in the collection that orders the collection using ordinal . This keeps the displayed order of the items in sync since the "default order" of the collection is now equal to the value of the ordinal attribute.

Note that there is some duplication of effort: the model does not need to be removed and added back to the collection if the collection has a comparator function, as jsfiddle does. In addition, the view may not be needed for re-rendering.

Note : compared to the other answer, I felt that it was more correct to notify the model instance of the element that needed to be updated, and not directly in the collection. Both approaches are valid. Another answer here goes directly to the collection, rather than to a model-based approach. Choose what makes more sense to you.

+81
Apr 13 '12 at 23:50
source share

http://jsfiddle.net/aJjW6/2/

HTML:

 `<div class="test-class"> <h1>Backbone and jQuery sortable - test</h1> <div id="items-collection-warper"></div> </div>` 

JavaScript:

 $(document).ready(function(){ var collection = [ {name: "Item ", order: 0}, {name: "Item 1", order: 1}, {name: "Item 2", order: 2}, {name: "Item 3", order: 3}, {name: "Item 4", order: 4} ]; var app = {}; app.Item = Backbone.Model.extend({}); app.Items = Backbone.Collection.extend({ model: app.Item, comparator: 'order', }); app.ItemView = Backbone.View.extend({ tagName: 'li', template: _.template('<span><%= name %> - <b><%= order %></b></span>'), initialize: function(){ }, render: function(){ var oneItem = this.$el.html(this.template(this.model.attributes)); return this; } }); app.AppView = Backbone.View.extend({ el: "#items-collection-warper", tagName: 'ul', viewItems: [], events:{ 'listupdate': 'listUpdate' }, initialize: function(){ var that = this; this.$el.sortable({ placeholder: "sortable-placeholder", update: function(ev, ui){ that.listUpdate(); } }); }, render: function(){ var that= this; this.collection.each(function(item){ that.viewItems.push(that.addOneItem(item)); return this; }); }, addOneItem: function(item){ var itemView = new app.ItemView({model: item}); this.$el.append(itemView.render().el); return itemView; }, listUpdate: function(){ _.each(this.viewItems, function(item){ item.model.set('order', item.$el.index()); }); this.collection.sort({silent: true}) _.invoke(this.viewItems, 'remove'); this.render(); } }); var Items = new app.Items(collection) var appView = new app.AppView({collection: Items}); appView.render(); }); 

CSS

 .test-class{ font-family: Arial; } .test-class li{ list-style:none; height:20px; } .test-class h1{ font-size: 12px; } .ui-sortable-helper{ opacity:0.4; } .sortable-placeholder{ background: #ddd; border:1px dotted #ccc; } 
+9
Nov 19 '13 at 12:37
source share

Just use Backbone.CollectionView !

 var collectionView = new Backbone.CollectionView( { sortable : true, collection : new Backbone.Collection } ); 

Voila!

+6
Jan 10 '14 at 19:33
source share



All Articles