underscore template backbonejs javascript jquery-ui backbone.js backbone.js-collections

javascript - template - Guardando el orden de JQuery UI Sortable en la colección Backbone.js



backbonejs github (3)

Tengo una colección de Backbone.js que me gustaría poder ordenar usando la ordenación de jQuery UI. Nada elegante, solo tengo una lista que me gustaría poder ordenar.

El problema es que no estoy seguro de cómo obtener el orden actual de los artículos después de haberlos ordenado y comunicar eso a la colección. Sortable puede serializarse, pero eso no me dará los datos del modelo que necesito dar a la colección.

Idealmente, me gustaría poder obtener una matriz del orden actual de los modelos en la colección y usar el método de reinicio para la colección, pero no estoy seguro de cómo obtener el pedido actual. Por favor comparta ideas o ejemplos para obtener una matriz con el orden del modelo actual.


Hice esto usando jQuery UI Sortable para activar un evento en la vista de elementos cuando se descarta un elemento. Luego puedo activar otro evento en la vista de elementos que incluye el modelo como datos a los que está vinculada la vista de colección. La vista de colección puede ser responsable de actualizar el orden de clasificación.

Ejemplo de trabajo

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

jQuery UI ordenable

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

El evento de stop está vinculado a una función que desencadena la drop en el nodo DOM para el elemento con el índice del elemento (proporcionado por jQuery UI) como datos.

Vista de artículo

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

El evento drop está vinculado a la función drop que activa un evento update-sort en el nodo DOM de la vista de elementos con los datos [this.model, index] . Eso significa que estamos pasando el modelo actual y su índice (desde jQuery UI ordenable) a quien esté vinculado al evento update-sort .

Vista de elementos (colección)

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

La vista Items está vinculada al evento update-sort y la función utiliza los datos que pasa el evento (modelo e índice). El modelo se elimina de la colección, el atributo ordinal se actualiza en cada artículo restante y el orden de los elementos por id se envía al servidor para almacenar el estado.

Colección

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

La colección tiene una función de comparator definida que ordena la recolección por ordinal . Esto mantiene sincronizado el orden de los elementos, ya que el "orden predeterminado" de la colección es ahora el valor del atributo ordinal .

Tenga en cuenta que hay cierta duplicación de esfuerzos: no es necesario eliminar el modelo y volver a agregarlo a la colección si una colección tiene una función de comparación como lo hace jsfiddle. Además, la vista puede no necesitar volver a renderizarse.

Nota : en comparación con la otra respuesta, mi sensación fue que era más correcto notificar directamente a la instancia del modelo del elemento que necesitaba actualizarse en lugar de la colección. Ambos enfoques son válidos. La otra respuesta aquí va directamente a la colección en lugar de tomar el enfoque de modelo primero. Elija lo que tenga más sentido para usted.


Solo use Backbone.CollectionView !

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

Voila!


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