Backbone.js ile ters sıralama düzeni


89

İle backbone.js ben bıraktığım bir karşılaştırıcı işleviyle kurulmuş bir koleksiyonu var. Modelleri güzelce sıralıyor ama sırayı tersine çevirmek istiyorum.

Modelleri artan sırada değil, azalan sırada nasıl sıralayabilirim?


2
Dizelerde ters sıralama için (oluşturulan_at alanları dahil), başka bir soru için bu yanıta bakın
Eric Hu

2
2012'nin başında sadece 2 argümanları ve getiri -1, 0 veya 1 kabul beri sıralama tarzı komparatörlerinin için destek var github.com/documentcloud/backbone/commit/...
Geon

Benim için işe yarayan şey buydu (Dizeler ve Sayılar): stackoverflow.com/questions/5013819/…
Fasani

Yanıtlar:


133

Peki, karşılaştırıcıdan negatif değerler döndürebilirsiniz. Örneğin Backbone'un sitesinden örnek alırsak ve sırayı tersine çevirmek istersek, şöyle görünecektir:

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 benimki ile aynı örnek kodu kullanmak için ve 15 saniye fark içinde. Fikir gibi söylemeliyim.
DhruvPathak

Tabii ki, sadece bir eksi işareti. Hızlı yanıtlarınız için ikinize de teşekkür ederim!
Drew Dara-Abrams

Ayrıca (Backbone sitesinde belirtildiği gibi), modelin niteliklerinden herhangi birini değiştirirseniz (örneğin bölüme bir "uzunluk" niteliği eklerseniz) bunun bozulacağını unutmayın. Bu durumda Koleksiyonda "sort ()" öğesini manuel olarak çağırmanız gerekecektir.
cmcculloh

9
2012'nin başında sadece 2 argümanları ve getiri -1, 0 veya 1 kabul beri sıralama tarzı komparatörlerinin için destek var github.com/documentcloud/backbone/commit/...
Geon

@Fasani yanıtı, sayılar dışındaki türler için çalışır, lütfen bir göz atın: stackoverflow.com/questions/5013819/…
JayC

56

Şahsen, burada verilen çözümlerin hiçbirinden memnun değilim:

  • Sıralama türü sayısal olmadığında -1 ile çarpma çözümü çalışmaz. Bunun etrafından dolaşmanın yolları olsa da ( Date.getTime()örneğin arayarak ) bu vakalar özeldir. Sıralanan alanın belirli türü hakkında endişelenmek zorunda kalmadan, her türden yönü tersine çevirmenin genel bir yolunu istiyorum.

  • Dize çözümü için, her seferinde bir karakter dizesi oluşturmak, özellikle büyük koleksiyonlar (veya aslında, büyük sıralama alanı dizeleri) kullanırken bir performans darboğazı gibi görünüyor.

Dize, Tarih ve Sayısal alanlar için iyi çalışan bir çözüm:

İlk olarak, aşağıdaki gibi bir sortBy işlevinin sonucunu tersine çevirecek bir karşılaştırıcı bildirin:

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

Şimdi, sıralamanın yönünü tersine çevirmek istiyorsanız, tek yapmamız gereken:

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

Bunun işe Backbone.Collection.sortyaramasının nedeni , sıralama işlevinin iki bağımsız değişkeni varsa farklı davranmasıdır. Bu durumda, karşılaştırıcının geçtiği gibi davranır Array.sort. Bu çözüm, tek bağımsız değişken sortBy işlevini iki bağımsız değişken karşılaştırıcısına uyarlayarak ve sonucu tersine çevirerek çalışır.


7
Bu sorunun cevabını en çok veren kişi olarak, bu yaklaşımı gerçekten seviyorum ve daha fazla olumlu oy alması gerektiğini düşünüyorum.
Andrew De Andrade

Çok teşekkür ederim Andrew
Andrew Newdigate

Çok güzel, bunu biraz değiştirip Backbone.Collection'ın prototipinde soyutlamayı bıraktım. Çok teşekkürler!
Kendrick Ledet

46

Backbone.js'nin koleksiyon karşılaştırıcısı, Underscore.js yöntemi _.sortBy'ye dayanır. SortBy'nin uygulanma biçimi, javascript .sort () dizgelerini tersine sıralamayı zorlaştıracak şekilde "sarmalar". Dizenin basit olumsuzlaması, NaN döndürür ve sıralamayı bozar.

Dizelerle ters alfabetik sıralama gibi bir ters sıralama yapmanız gerekiyorsa, işte bunu yapmanın gerçekten hilekâr bir yolu:

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

Hiç de güzel değil, ama bir "dizi olumsuzlayıcı". JavaScript'te yerel nesne türlerini değiştirmeye yönelik herhangi bir niteliğiniz yoksa, string negator'ı ayıklayıp String.Prototype üzerine bir yöntem olarak ekleyerek kodu daha net hale getirebilirsiniz. Bununla birlikte, muhtemelen yalnızca ne yaptığınızı biliyorsanız bunu yapmak istersiniz, çünkü javascript'te yerel nesne türlerini değiştirmenin öngörülemeyen sonuçları olabilir.


Bu çok kullanışlıdır. Teşekkürler Andrew!
Abel

1
Sorun yok. Sadece kendinize neden ters alfabetik sıralama uyguladığınızı ve belki de kullanıcı deneyimi açısından daha zarif bir çözüm olup olmadığını sormanız gerektiğini ekleyeceğim.
Andrew De Andrade

1
@AndrewDeAndrade Nedeniyle ilgili: Bir koleksiyonu 'created_at' özniteliğine göre sıralamak istiyorum, en yenileri önce sunuyorum. Bu özellik, Backbone'un varsayılan özelliklerinden biridir ve String olarak saklanır. Cevabınız istediğime en çok yaklaşıyor. Teşekkürler!
Eric Hu

Bu inanılmaz, son bir saattir bunun çözümü üzerinde çalışıyorum.

28

Benim çözümüm, sonuçları sıralamadan sonra tersine çevirmekti.

Çift oluşturmayı önlemek için önce sessiz olarak sıralayın, ardından 'sıfırla'yı tetikleyin.

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

2
Daha iyi bir çözüm, karşılaştırıcının sonucunu reddetmektir.
Daniel X Moore

7
Daniel, bu her zaman mümkün değildir, örneğin dizeleri veya Tarihleri ​​sıralarken.
Gavin Schulz

1
Tabiki öyle. Tarih -Date.getTime()için, sisteminizdeki tarihlerin unix çağını geçeceğine inanıyorsanız, muhtemelen fazladan bir hackleme ile karşılaştırıcının geri dönmesini sağlayabilirsiniz . Alfabetik olarak, Andrew'un yukarıdaki cevabına bakın.
asparagino

@DanielXMoore Neden bu daha iyi bir çözüm? Daha hızlı mı? Kişisel olarak, kullanıcının koleksiyonu en son sıraladığı özniteliği saklamayı, ardından o özniteliğe göre yeniden sıralaması durumunda mevcut sıralamayı tersine çevirmeyi çok kolay buluyorum; (bir Wikipedia tablosunda gördüğünüz sıralama davranışını uygulamak için, burada sıralama yönünün tablo başlığındaki özniteliğe tekrar tekrar tıklanarak değiştirilebilir) Bu şekilde karşılaştırıcı mantığımı temiz tutarım ve Asc'den geçiş yaparsak kendime bir sıralama işlemi kaydederim.
azalan

13

Karşılaştırıcı işlevinizi, şu anda bulunduğunuz verileri döndürmek yerine ters orantılı bir değer döndürmek için değiştirin. Bazı kodlar: http://documentcloud.github.com/backbone/#Collection-comparator

Misal:

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

Aşağıdakiler benim için iyi çalıştı:

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

Backbone karşılaştırıcı işlevinin JavaScript Array.prototype.sort () işlevini kullandığı veya taklit ettiği bazı yerlerde okudum. Bu, koleksiyondaki her modelin sıralama düzenine karar vermek için 1, -1 veya 0 kullandığı anlamına gelir. Bu sürekli olarak güncellenir ve koleksiyon, karşılaştırıcıya göre doğru sırada kalır.

Array.prototype.sort () ile ilgili bilgiler burada bulunabilir: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?redirectlocale=en-US&redirectslug=JavaScript% 2FReference% 2FGlobal_Objects% 2FArray% 2Fsort

Bu soruya verilen pek çok cevap, sayfaya dönmeden hemen önce sırayı tersine çevirir. Bu ideal değil.

Mozilla ile ilgili yukarıdaki makaleyi bir kılavuz olarak kullanarak, koleksiyonumu aşağıdaki kodu kullanarak ters sırada sıralı tutabildim, sonra koleksiyonu mevcut sırasına göre sayfaya dönüştürdük ve sıralamayı tersine çevirmek için bir bayrak (reverseSortDirection) kullanabiliriz .

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

},

Karşılaştırıcı, iki model hariç, koleksiyon veya modelde yapılan değişikliklerde karşılaştırma işlevi çalışır ve koleksiyonun sırasını değiştirir.

Bu yaklaşımı Numbers and Strings ile test ettim ve benim için mükemmel çalışıyor gibi görünüyor.

Bu sorunla birçok kez mücadele ettiğim ve genellikle bir çalışma kullanmamla sonuçlandığım için bu cevabın yardımcı olabileceğini umuyorum.


1
Bu gibi mantık koleksiyonunda yaşıyor çünkü, ancak kolayca ayarlayabilir sortKeyve reverseSortDirectionaramayı ve .sort()koleksiyon ile ilgilenecek herhangi bir görünümden. Benim için diğer yüksek oy alan cevaplardan daha basit.
Noah Heldman

5

Bu, sortBy yöntemini geçersiz kılarak zarif bir şekilde yapılabilir. İşte bir örnek

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

});

Yani bunu şu şekilde kullanabilirsiniz:

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

Bu çözüm, alan türüne bağlı değildir.


1
İyi bir ! "void 0", "tanımsız" ile değiştirilebilir.
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

İşte sadece mevcut sırayı tersine çevirmek isteyenler için gerçekten basit bir çözüm. Sütunları iki yönde sıralanabilen bir tablonuz varsa kullanışlıdır.

collection.models = collection.models.reverse()

Masa örneğiyle ilgileniyorsanız, bunu aşağıdaki gibi bir şeyle birleştirebilirsiniz (kahve yazı)

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

  collection.sort()

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

2
Bu durumda, koleksiyona yeni bir model eklendiğinde, .set yöntemi, sıralama yöntemini kullanarak yeni eklenen modelleri sırayla tuttuğundan, sonucu reverseOrder uygulanmadan önce aldığından doğru şekilde sıralanmayacaktır.
Fabio

1

Kimlik üzerinde ters sipariş için:

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

0

Modellerimi bir tabloda görüntülediğim için biraz farklı bir gereksinimim vardı ve bunları herhangi bir collumn (model özelliği) ile ya artan ya da azalan şekilde sıralayabilmek istedim.

Tüm vakaların (değerlerin dizeler, boş dizeler, tarihler, sayılar olabileceği yerlerde) çalışabilmesi için oldukça fazla uğraşmak gerekti. Ancak bence bu oldukça yakın.

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

kullanım:

    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

Tamamlandıktan sonra modeller dizisini tersine çevirmek için sıralama işlevini geçersiz kıldım. Ayrıca, tersi tamamlanana kadar 'sıralama' olayını tetiklemeyi bıraktım.

    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

Son zamanlarda bu sorunla karşılaştı ve bir rsort yöntemi eklemeye karar verdim.

    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;

            }
    });

Umarım birisi bunu faydalı bulacaktır


0

UnderscoreJS kullanarak bir koleksiyonun modellerini ters sıralamak için hızlı ve kolay bir yol.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.