4

ここで遊んでいる問題があります。BackboneJS モデルのコレクションがあり、各モデルには、コレクション内の順序を追跡する「順序」プロパティがあります。

私のプレイデータはこちら

var ex_group_test_data = [{

            title: 'PRE EXERCISE',
            id:         0,
            ordinal:    1,

            group_items: [{
                id:         0,
                ordinal:    0,
                title: 'item 1'
            },{
                id:         1,
                ordinal:    1,
                title: 'item 2'
            }]

        },{

            title: 'MAIN PART',
            id:         1,
            ordinal:    0,

            group_items: [{
                id:             2,
                ordinal:        0,
                title:          'item 3',
                description:    'testing descrip'
            },{
                id:         3,
                ordinal:    1,
                title: 'item 4'
            }]

        },{

            title: 'POST EXERCISE BS',
            id:         2,
            ordinal:    2,

            group_items: [{
                id:             2,
                ordinal:        0,
                title:          'item 5',
                description:    'testing descrip'
            },{
                id:         3,
                ordinal:    1,
                title: 'item 6'
            }]

        }];

そして、これが私のバックボーンコレクションの要点です

        Collections.Exercise_Groups = Backbone.Collection.extend({
            model: Models.Exercise_Group,
            comparator: function(model){
                return model.get('ordinal');
            },
            initialize: function(){

                return this;
            }

簡単なことから始めて、モデルを取得して +1 または -1 序数で移動し、コレクション内のすべてのモデルの 0 インデックスを維持できるようにしたいと考えています。

最終的には、これを、モデルをドロップしたり、任意の位置から削除したりしても、0 インデックスを維持したり、モデルを取得して +/- X 位置に移動したりできるレベルにまで引き上げたいと考えています。

これを達成するための推奨される方法はありますか?

編集1

私は解決策を考え出しました。実際に睡眠を取った後、明日これを最適化したいと思うかもしれません。モデルを元の位置に対して前方または後方に移動しているかどうかにかかわらず、コレクション内のモデルの「序数」の 0 インデックスを維持します。

EDIT 2 Err実際にはフリンジケースにエラーがあります。

/**
             * Move model to a specified location. 
             * 
             * @param   int [model id]
             * @param   int [mew item position]
             * @return  this
             */
            move_to: function(m_id, new_pos){

                //keep within range
                if(new_pos < 0)
                    new_pos = 0;
                else if(new_pos > (this.length - 1))
                    new_pos = this.length - 1;


                var model = this.get(m_id),
                    old_pos = model.get('ordinal');


                model.set({
                    ordinal: new_pos
                });
                if(new_pos == old_pos){
                    //trigger associated events
                    this.sort();
                    return this;
                }

                //update indexes of affected models
                this.each(function(m){

                    //ordinal of current model in loop
                    var m_ordinal = m.get('ordinal');

                    //skip if this is the model we just updated
                    if(m.get('id') == m_id)
                        return;

                    if(old_pos < new_pos){
                        //moving down, ordinal is increasing

                        if(m_ordinal <= new_pos && m_ordinal != 0){
                            //this is in the range we care about
                            m.set({
                                ordinal: m.get('ordinal') - 1
                            });

                        }

                    }else if(old_pos > new_pos){
                        //moving up, ordinal is decreasing                  


                        if(m_ordinal >= new_pos && (m_ordinal != (this.length - 1))){
                            //this is in the range we care about
                            m.set({
                                ordinal: m.get('ordinal') + 1
                            });

                        }

                    }

                });

                this.sort();
                return this;

            }

EDIT 3 さて、私はすべての問題、いくつかの単純なスコープのものを修正したと思います。これは私がかなり徹底的にテストしたいくつかのコードで、うまくいくと信じています。

/**
                 * Move model to a specified location. 
                 * 
                 * @param   int [model id]
                 * @param   int [mew item position]
                 * @return  this
                 */
                move_to: function(m_id, new_pos){

                    //keep within range
                    if(new_pos < 0)
                        new_pos = 0;
                    else if(new_pos > (this.length - 1))
                        new_pos = this.length - 1;


                    var model = this.get(m_id),
                        old_pos = model.get('ordinal');

                    log('old_pos ' + old_pos);
                    log('new_pos ' + new_pos);


                    model.set({
                        ordinal: new_pos
                    });
                    if(old_pos == new_pos){
                        //trigger associated events
                        this.sort();
                        return this;
                    }

                    var _this = this;
                    //update indexes of affected models
                    this.each(function(m){

                        //ordinal of current model in loop
                        var m_ordinal = m.get('ordinal');

                        //skip if this is the model we just updated
                        if(m.get('id') == m_id)
                            return;

                        if(old_pos < new_pos){
                            //moving down, ordinal is increasing

                            if(m_ordinal <= new_pos && !(m_ordinal <= 0)){
                                //this is in the range we care about
                                m.set({
                                    ordinal: m.get('ordinal') - 1
                                });

                            }

                        }else if(old_pos > new_pos){
                            //moving up, ordinal is decreasing                  
                             log('p1');

                            if(m_ordinal >= new_pos && !(m_ordinal >= (_this.length - 1))){
                                //this is in the range we care about
                                m.set({
                                    ordinal: m.get('ordinal') + 1
                                });

                            }

                        }

                    });

                    this.sort();                    
                    return this;

                }

編集4

別のバグを発見し、パッチを当てました。

Backbone.Collection.prototype.move_to = function(m_id, new_pos) {

    //keep within range
    if(new_pos < 0)
        new_pos = 0;
    else if(new_pos > (this.length - 1))
        new_pos = this.length - 1;


    var model = this.get(m_id),
        old_pos = model.get('ordinal');

    log('old_pos ' + old_pos);
    log('new_pos ' + new_pos);

    model.set({
        ordinal: new_pos
    });
    if(old_pos == new_pos){
        //trigger associated events
        this.sort();
        return this;
    }

    var _this = this;
    //update indexes of affected models
    this.each(function(m){

        log(m.id);

        //ordinal of current model in loop
        var m_ordinal = m.get('ordinal');

        //skip if this is the model we just updated
        if(m.get('id') == m_id)
            return;

        if(old_pos < new_pos){
            //moving down, ordinal is increasing

            if(m_ordinal <= new_pos && m_ordinal >= old_pos && !(m_ordinal <= 0)){
                //this is in the range we care about
                m.set({
                    ordinal: m.get('ordinal') - 1
                }, {
                    silent: true
                });

            }

        }else if(old_pos > new_pos){
            //moving up, ordinal is decreasing                  
             log('p1');

            if(m_ordinal >= new_pos && m_ordinal <= old_pos && !(m_ordinal >= (_this.length - 1))){
                //this is in the range we care about
                m.set({
                    ordinal: m.get('ordinal') + 1
                }, {
                    silent: true
                });

            }

        }

    });

    this.sort();                    
    return this;
};
4

1 に答える 1

23

backbone.js のソース コードを見ると、たとえば add メソッドが特定のインデックスへのモデルの追加をサポートしていることがわかります。

collectionName.add(model, {at: index});

位置から削除するには、次のようなカスタム関数をコレクションに作成する必要がある場合があります。

// Your Collection

removeAt: function(options) {
  if (options.at) {
    this.remove(this.at(options.at));
  }
}

+1 / -1 の場合、カスタム関数を作成して、組み込みのアンダースコア indexOf-function を利用できます

// Your Collection

moveUp: function(model) { // I see move up as the -1
  var index = this.indexOf(model);
  if (index > 0) {
    this.remove(model, {silent: true}); // silence this to stop excess event triggers
    this.add(model, {at: index-1});
  }
}

moveDown: function(model) { // I see move up as the -1
  var index = this.indexOf(model);
  if (index < this.models.length) {
    this.remove(model, {silent: true}); // silence this to stop excess event triggers
    this.add(model, {at: index+1});
  }
}

このようにして、moveUp と moveDown をモデル自体に実装して、より読みやすいコードにすることもできます。

// Your Model

moveUp: function() {
  this.collection.moveUp(this);
}

// And the same for moveDown

しかし今、index プロパティはモデル自体に保存されていません。インデックスを読み取るには を使用するだけcollection.indexOf(model)ですが、その情報を常にモデルに保存する場合は、addおよびremoveイベントにバインドして、コレクションに変更が加えられたときにすべてのインデックスを更新できます。

// Your collection

initialize: function(options?) {
  ...
  this.on('add remove', this.updateModelOrdinals);
  ...
},

...

updateModelOrdinals: function() {
  this.each(function(model, index) {
    this.model.set('ordinal', index);
  });
}

ほら!これで、車輪を再発明することなく、バックボーン独自の機能で 0-indexing を維持しながら、必要な機能が得られるはずです! 少し調子に乗ってすみません、私があなたの頭を超えたか聞いてください. そして、backbone.js のソースを読むと、非常に役立つ情報が見つかるはずです!

お役に立てれば!

于 2012-07-26T08:15:09.447 に答える