Backbone.jsによる逆の並べ替え順序


89

BACKBONE.JS Iましたがコンパレータ機能で設定コレクションを得ました。モデルをうまく並べ替えていますが、順序を逆にしたいと思います。

モデルを昇順ではなく降順に並べ替える方法を教えてください。


2
文字列(created_atフィールドを含む)の逆ソートについては、別の質問でこの回答を参照してください
Eric Hu

2
2012年の初めから、並べ替えスタイルのコンパレータがサポートされています。2つの引数を受け入れ、-1、0、または1を返すだけです。github.com/ documentcloud / backbone / commit /…
geon

これは私のために(文字列と数値を)働いていたものです:stackoverflow.com/questions/5013819/...
FMD

回答:


133

まあ、コンパレータから負の値を返すことができます。たとえば、Backboneのサイトの例を取り上げて、順序を逆にすると、次のようになります。

var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;

chapters.comparator = function(chapter) {
  return -chapter.get("page"); // Note the minus!
};

chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

alert(chapters.pluck('title'));

3
hi5はmineと同じサンプルコードを使用しており、15秒以内に違いがあります。気にされたように私は言わなければなりません。
DhruvPathak、2011

もちろん、マイナス記号です。迅速な対応ありがとうございました!
Drew Dara-Abrams

また、(Backboneのサイトで述べたように)モデルの属性を変更すると(たとえば、「length」属性をチャプタに追加すると)、これは機能しなくなります。その場合は、コレクションの「sort()」を手動で呼び出す必要があります。
cmcculloh 2012

9
2012年の初めから、並べ替えスタイルのコンパレータがサポートされています。2つの引数を受け入れ、-1、0、または1を返すだけです。github.com/ documentcloud / backbone / commit /…
geon

@Fasani応答は、数値以外のタイプでも機能します。詳しくは、stackoverflow.com
questions / 5013819 /…

56

個人的に、私はここに与えられた解決策のどれにも満足していません:

  • ソートタイプが非数値の場合、-1による乗算ソリューションは機能しません。これを回避する方法はありますが(Date.getTime()たとえば、呼び出しによって)、これらのケースは特定のものです。並べ替えられるフィールドの特定のタイプを気にすることなく、並べ替えの方向を逆にする一般的な方法が欲しいのですが。

  • 文字列ソリューションの場合、文字列を一度に1文字ずつ構成すると、特に大きなコレクション(または実際には、大きな並べ替えフィールド文字列)を使用する場合、パフォーマンスのボトルネックのように見えます

以下は、文字列、日付、数値フィールドに対して適切に機能するソリューションです。

最初に、次のように、sortBy関数の結果の結果を逆にするコンパレータを宣言します。

function reverseSortBy(sortByFunction) {
  return function(left, right) {
    var l = sortByFunction(left);
    var r = sortByFunction(right);

    if (l === void 0) return -1;
    if (r === void 0) return 1;

    return l < r ? 1 : l > r ? -1 : 0;
  };
}

ここで、並べ替えの方向を逆にしたい場合は、次の操作を行うだけです。

var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;

// Your normal sortBy function
chapters.comparator = function(chapter) {
  return chapter.get("title"); 
};


// If you want to reverse the direction of the sort, apply 
// the reverseSortBy function.
// Assuming the reverse flag is kept in a boolean var called reverseDirection 
if(reverseDirection) {
   chapters.comparator = reverseSortBy(chapters.comparator);
}

chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

alert(chapters.pluck('title'));

これが機能する理由は Backbone.Collection.sort、sort関数に2つの引数がある場合の動作が異なるです。この場合、に渡されるコンパレータと同じように動作しArray.sortます。このソリューションは、単一引数のsortBy関数を2つの引数のコンパレーターに適合させ、結果を逆にすることで機能します。


7
この質問に対して最も賛成された回答を持つ人として、私はこのアプローチが本当に好きであり、もっと賛成すべきだと思います。
Andrew De Andrade 2013


とてもいいですが、これを少し調整して、Backbone.Collectionのプロトタイプで抽象化しました。本当にありがとう!
Kendrick Ledet 2015

46

Backbone.jsのコレクションコンパレータは、Underscore.jsメソッド_.sortByに依存しています。sortByの実装方法は、文字列を逆にソートすることを困難にする方法でjavascript .sort()を「ラップ」することになります。文字列の単純な否定は、最終的にNaNを返し、ソートを中断します。

アルファベット順の逆順など、文字列を使用した逆順の並べ替えを実行する必要がある場合は、次のようにしてこれを実行するのは本当にハックな方法です。

comparator: function (Model) {
  var str = Model.get("name");
  str = str.toLowerCase();
  str = str.split("");
  str = _.map(str, function(letter) { 
    return String.fromCharCode(-(letter.charCodeAt(0)));
  });
  return str;
}

決してきれいではありませんが、「文字列否定子」です。JavaScriptでネイティブオブジェクトタイプを変更することに不安がない場合は、文字列否定子を抽出し、それをString.Prototypeのメソッドとして追加することで、コードをより明確にすることができます。ただし、JavaScriptでネイティブオブジェクトタイプを変更すると予期しない結果が生じる可能性があるため、おそらくこれを実行したいのは、自分が何をしているかを知っている場合だけです。


これはとても便利です。アンドリュー、ありがとう!
アベル

1
問題ありません。逆アルファベット順のソートを実装している理由と、ユーザーエクスペリエンスの観点からおそらくよりエレガントなソリューションがあるかどうかを自問してください。
Andrew De Andrade

1
@AndrewDeAndrade理由:「created_at」属性でコレクションをソートして、最新のものを最初に提供したいと考えています。この属性はバックボーンのデフォルトの属性の1つであり、文字列として格納されます。あなたの答えは私が望むものに最も近くなります。ありがとう!
Eric Hu

これは驚くべきことであり、過去1時間、この問題の解決に取り組んでいます。

28

私の解決策は、ソート後に結果を元に戻すことでした。

二重レンダリングがサイレントで最初にソートされるのを防ぐには、「リセット」をトリガーします。

collections.sort({silent:true})
collections.models = collections.models.reverse();
collections.trigger('reset', collections, {});

2
より良い解決策は、コンパレータの結果を無効にすることです。
ダニエルXムーア

7
ダニエル、文字列や日付を並べ替えるときなど、それが常に可能であるとは限りません。
Gavin Schulz

1
もちろんそうだ。Dateの場合、コンパレータのリターンを使用でき-Date.getTime()ます。システムの日付がUNIXエポックを超えると思われる場合は、追加のハッキングを行うことができます。アルファベット順については、上記のアンドリューの答えを見てください。
asparagino

@DanielXMooreなぜそれがより良い解決策になるのですか?速いですか?個人的には、ユーザーが最後にコレクションを並べ替えた属性を保存し、その属性で並べ替えた場合は現在の並べ替えを逆にするのは非常に簡単です。(ウィキペディアのテーブルに表示される並べ替え動作を実装するには、テーブルヘッダーの属性を繰り返しクリックすることで並べ替えの方向を切り替えることができます)こうすることで、Ascから切り替えた場合にコンパレータロジックをきれいに保ち、並べ替え操作を節約できます。 to
Desc

13

現在のデータを返す代わりに、逆比例値を返すようにコンパレーター関数を変更します。からのコード:http : //documentcloud.github.com/backbone/#Collection-comparator

例:

var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;

/* Method 1: This sorts by page number */
chapters.comparator = function(chapter) {
  return chapter.get("page");
};

/* Method 2: This sorts by page number in reverse */
chapters.comparator = function(chapter) {
  return -chapter.get("page");
};

chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));

9

以下は私にとってうまくいきました:

comparator: function(a, b) {
  // Optional call if you want case insensitive
  name1 = a.get('name').toLowerCase();
  name2 = b.get('name').toLowerCase();

  if name1 < name2
    ret = -1;
  else if name1 > name2
    ret = 1;
  else
    ret = 0;

  if this.sort_dir === "desc"
    ret = -ret
  return ret;
}

collection.sort_dir = "asc";
collection.sort(); // returns collection in ascending order
collection.sort_dir = "desc";
collection.sort(); // returns collection in descending order

8

私は、バックボーンコンパレーター関数がJavaScript Array.prototype.sort()関数を使用または模倣している箇所をいくつか読みました。つまり、1、-1、または0のいずれかを使用して、コレクション内の各モデルの並べ替え順序を決定します。これは常に更新され、コレクションはコンパレーターに基づいて正しい順序で維持されます。

Array.prototype.sort()に関する情報はここにあります:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?redirectlocale=en-US&redirectslug=JavaScript% 2FReference%2FGlobal_Objects%2FArray%2Fsort

この質問に対する多くの回答は、ページに表示する直前に順序を逆にするだけです。これは理想的ではありません。

上記のMozillaに関する記事をガイドとして使用して、次のコードを使用してコレクションを逆順に並べ替えておくことができました。その後、コレクションを現在の順序でページにレンダリングし、フラグ(reverseSortDirection)を使用して順序を逆にすることができます。 。

//Assuming this or similar will be in your Backbone.Collection.
sortKey: 'id', //The field name of the item in your collection

reverseSortDirection: false,

comparator: function(a, b) {

  var sampleDataA = a.get(this.sortKey),
      sampleDataB = b.get(this.sortKey);

      if (this.reverseSortDirection) {
        if (sampleDataA > sampleDataB) { return -1; }
        if (sampleDataB > sampleDataA) { return 1; }
        return 0;
      } else {
        if (sampleDataA < sampleDataB) { return -1; }
        if (sampleDataB < sampleDataA) { return 1; }
        return 0;
      }

},

2つのモデルを除くコンパレータ。コレクションまたはモデルへの変更時に、comparor関数が実行され、コレクションの順序が変更されます。

私はこのアプローチをNumbersとStringsでテストしましたが、完全に機能しているようです。

私がこの問題に何度も取り組み、通常は回避策を講じることになるので、この答えが役に立てば幸いです。


1
ロジックはコレクション内に存在するため、これが好きですが、コレクションにハンドルを持つ任意のビューから簡単に設定sortKeyreverseSortDirectionて呼び出すことができます.sort()。他の投票数の多い回答よりも単純です。
ノアヘルドマン、2014年

5

これは、sortByメソッドをオーバーライドすることにより、エレガントに行うことができます。ここに例があります

var SortedCollection = Backbone.Collection.extend({

   initialize: function () {
       // Default sort field and direction
       this.sortField = "name";
       this.sortDirection = "ASC";
   },

   setSortField: function (field, direction) {
       this.sortField = field;
       this.sortDirection = direction;
   },

   comparator: function (m) {
       return m.get(this.sortField);
   },

   // Overriding sortBy (copied from underscore and just swapping left and right for reverse sort)
   sortBy: function (iterator, context) {
       var obj = this.models,
           direction = this.sortDirection;

       return _.pluck(_.map(obj, function (value, index, list) {
           return {
               value: value,
               index: index,
               criteria: iterator.call(context, value, index, list)
           };
       }).sort(function (left, right) {
           // swap a and b for reverse sort
           var a = direction === "ASC" ? left.criteria : right.criteria,
               b = direction === "ASC" ? right.criteria : left.criteria;

           if (a !== b) {
               if (a > b || a === void 0) return 1;
               if (a < b || b === void 0) return -1;
           }
           return left.index < right.index ? -1 : 1;
       }), 'value');
   }

});

したがって、次のように使用できます。

var collection = new SortedCollection([
  { name: "Ida", age: 26 },
  { name: "Tim", age: 5 },
  { name: "Rob", age: 55 }
]);

//sort by "age" asc
collection.setSortField("age", "ASC");
collection.sort();

//sort by "age" desc
collection.setSortField("age", "DESC");
collection.sort();

このソリューションはフィールドタイプに依存しません。


1
いいね!「void 0」は「undefined」に置き換えることができます。
GMO

3
// For numbers, dates, and other number-like things
var things = new Backbone.Collection;
things.comparator = function (a, b) { return b - a };

// For strings
things.comparator = function (a, b) {
  if (a === b) return 0;
  return a < b ? -1 : 1;
};

2

これは、現在の順序を逆にしたいだけの人のための、本当にシンプルなソリューションです。列が2方向に配列できるテーブルがある場合に便利です。

collection.models = collection.models.reverse()

テーブルケース(コーヒースクリプト)に興味がある場合は、次のようなものと組み合わせることができます。

  collection.comparator = (model) ->
    model.get(sortByType)

  collection.sort()

  if reverseOrder
    collection.models = collection.models.reverse()

2
この場合、新しいモデルがコレクションに追加されると、.setメソッドはsortメソッドを使用して新しく追加されたモデルの順序を維持するため、正しく並べ替えられません。reverseOrderが適用される前の結果を取得します。
Fabio、

1

IDの逆順の場合:

comparator: function(object) { return (this.length - object.id) + 1; }

0

テーブルにモデルを表示しているという点で少し異なる要件があり、それらを任意の列(モデルプロパティ)で昇順または降順でソートできるようにしたかったのです。

すべてのケースを機能させるにはかなりの手間がかかります(値は文字列、空の文字列、日付、数値の場合があります。しかし、これはかなり近いと思います。

    inverseString: function(str)
    {
        return str.split("").map(function (letter) { return String.fromCharCode(-(letter.charCodeAt(0))); }).join("");
    }
    getComparisonValue: function (val, desc)
    {
        var v = 0;
        // Is a string
        if (typeof val === "string")
        {
            // Is an empty string, upgrade to a space to avoid strange ordering
            if(val.length === 0)
            {
                val = " ";
                return desc ? this.inverseString(val) : val;
            }                

            // Is a (string) representing a number
            v = Number(val);
            if (!isNaN(v))
            {
                return desc ? -1 * v : v;
            }
            // Is a (string) representing a date
            v = Date.parse(val);
            if (!isNaN(v))
            {
                return desc ? -1 * v : v;
            }
            // Is just a string
            return desc ? this.inverseString(val) : val;
        }
        // Not a string
        else
        {
            return desc ? -1 * val : val;
        }
    },

使用する:

    comparator: function (item)
    {
        // Store the collumn to 'sortby' in my global model
        var property = app.collections.global.get("sortby");

        // Store the direction of the sorting also in the global model
        var desc = app.collections.global.get("direction") === "DESC";

        // perform a comparison based on property & direction
        return this.getComparisonValue(item.get(property), desc);
    },

0

sort関数をオーバーライドして、完了時にモデル配列を逆にします。また、リバースが完了するまで、「ソート」イベントのトリガーを保留しました。

    sort : function(options){

        options = options || {};

        Backbone.Collection.prototype.sort.call(this, {silent:true});
        this.models.reverse();

        if (!options.silent){
            this.trigger('sort', this, options);
        }

        return this;
    },

0

最近この問題に遭遇し、rsortメソッドを追加することにしました。

    Collection = Backbone.Collection.extend({
            comparator:function(a, b){
                return a>b;
            },
            rsort:function(){
                var comparator = this.comparator;

                this.comparator = function(){
                    return -comparator.apply(this, arguments);
                }
                this.sort();

                this.comparator = comparator;

            }
    });

うまくいけば、誰かがこれが役に立つと思うでしょう


0

UnderscoreJSを使用してコレクションのモデルを逆ソートする迅速かつ簡単な方法を次に示します

 var reverseCollection = _.sortBy(this.models, function(model) {
   return self.indexOf(model) * -1;
 });

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.