web-dev-qa-db-fra.com

Enregistrement de l'ordre de tri de jQuery UI dans la collection Backbone.js

J'ai une collection Backbone.js que j'aimerais pouvoir trier en utilisant Sortable de jQuery UI. Rien d'extraordinaire, j'ai juste une liste que j'aimerais pouvoir trier.

Le problème est que je ne sais pas comment obtenir l'ordre actuel des articles après avoir été triés et les communiquer à la collection. Triable peut se sérialiser, mais cela ne me donnera pas les données de modèle que je dois donner à la collection.

Idéalement, j'aimerais pouvoir simplement obtenir un tableau de l'ordre actuel des modèles dans la collection et utiliser la méthode de réinitialisation pour la collection, mais je ne sais pas comment obtenir l'ordre actuel. Veuillez partager vos idées ou exemples pour obtenir un tableau avec la commande de modèle actuelle.

45
VirtuosiMedia

J'ai fait cela en utilisant jQuery UI Sortable pour déclencher un événement sur la vue de l'élément lorsqu'un élément est déposé. Je peux ensuite déclencher un autre événement sur la vue d'élément qui inclut le modèle en tant que données auxquelles la vue de collection est liée. La vue de collection peut alors être responsable de la mise à jour de l'ordre de tri.

Exemple de travail

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

L'événement stop est lié à une fonction qui déclenche drop sur le nœud DOM pour l'élément avec l'index de l'élément (fourni par jQuery UI) en tant que données.

Affichage des éléments

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

L'événement drop est lié à la fonction drop qui déclenche un update-sort événement sur le nœud DOM de la vue d'élément avec les données [this.model, index]. Cela signifie que nous transmettons le modèle actuel et son index (à partir de jQuery UI triable) à quiconque est lié au update-sort un événement.

Affichage des objets (collection)

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 vue Items est liée à la update-sort événement et la fonction utilise les données transmises par l'événement (modèle et index). Le modèle est supprimé de la collection, l'attribut ordinal est mis à jour sur chaque élément restant et l'ordre des éléments par id est envoyé au serveur pour stocker l'état.

Collection

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

La collection a une fonction comparateur définie qui ordonne la collection par ordinal. Cela permet de synchroniser l'ordre rendu des éléments, car "l'ordre par défaut" de la collection est désormais de la valeur de l'attribut ordinal.

Notez qu'il y a une certaine duplication d'efforts: le modèle n'a pas besoin d'être supprimé et ajouté à la collection si une collection a une fonction de comparaison comme le fait jsfiddle. La vue peut également ne pas avoir besoin de se restituer.

Remarque : par rapport à l'autre réponse, mon sentiment était qu'il était plus correct de notifier l'instance de modèle de l'élément qu'il devait être mis à jour au lieu de directement la collection. Les deux approches sont valables. L'autre réponse ici va directement à la collection au lieu d'adopter l'approche du modèle d'abord. Choisissez celui qui vous convient le mieux.

81
Cymen

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
Mateusz Godlewski

Utilisez simplement Backbone.CollectionView !

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

Voila!

6
Brave Dave