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/…
Fasani

답변:


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와 동일한 예제 코드를 사용하고 15 초 이내에 차이가 있습니다. 마음대로 말해야합니다.
DhruvPathak

물론, 마이너스 기호입니다. 빠른 답변에 감사드립니다!
Drew Dara-Abrams

또한 (Backbone의 사이트에서 언급했듯이) 모델의 속성을 변경하면 (예를 들어 챕터에 "length"속성을 추가하는 경우) 깨집니다. 이 경우 컬렉션에서 "sort ()"를 수동으로 호출해야합니다.
cmcculloh 2012-08-09

9
2012 년 초부터 정렬 스타일 비교기가 지원됩니다. 인수 2 개를 수락하고 -1, 0 또는 1을 반환하면됩니다. github.com/documentcloud/backbone/commit/…
geon

@Fasani 응답은 숫자 이외의 유형에 대해 작동합니다. 한 번보세요 : stackoverflow.com/questions/5013819/…
JayC 2014

56

개인적으로 여기에 제공된 솔루션에 만족하지 않습니다.

  • -1 곱하기 솔루션은 정렬 유형이 숫자가 아닌 경우 작동하지 않습니다. 이 문제를 해결하는 방법이 있지만 ( Date.getTime()예를 들어 호출 하여) 이러한 경우는 구체적입니다. 정렬되는 필드의 특정 유형에 대해 걱정할 필요없이 모든 종류의 방향을 바꾸는 일반적인 방법을 원합니다.

  • 문자열 솔루션의 경우 한 번에 한 문자 씩 문자열을 구성하는 것이 성능 병목 현상처럼 보입니다. 특히 대규모 컬렉션 (또는 실제로 큰 정렬 필드 문자열)을 사용할 때 더욱 그렇습니다.

다음은 문자열, 날짜 및 숫자 필드에 대해 잘 작동하는 솔루션입니다.

먼저 다음과 같이 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는 정렬 함수에 두 개의 인수가있는 경우 다르게 작동하기 때문입니다. 이 경우 비교기가에 전달 된 것과 동일한 방식으로 작동합니다 Array.sort. 이 솔루션은 단일 인수 sortBy 함수를 두 개의 인수 비교기로 조정하고 결과를 반전하여 작동합니다.


7
이 질문에 대해 가장 많은 찬성 응답을받은 사람으로서 저는이 접근 방식이 정말 마음에 들며 더 많은 찬성 투표를해야한다고 생각합니다.
Andrew De Andrade 2013

대단히 앤드류 감사
앤드류 Newdigate

아주 좋았습니다. 저는 이것을 약간 수정하고 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;
}

결코 예쁘지는 않지만 "문자열 부정"입니다. 자바 스크립트에서 네이티브 객체 유형을 수정하는 데 어려움이 없다면 문자열 부정자를 추출하여 String.Prototype에 메서드로 추가하여 코드를 더 명확하게 만들 수 있습니다. 그러나 자바 스크립트에서 네이티브 객체 유형을 수정하면 예상치 못한 결과가 발생할 수 있으므로 수행중인 작업을 알고있는 경우에만이 작업을 수행하고 싶을 것입니다.


이것은 매우 편리합니다. 감사합니다 앤드류!
Abel

1
문제가 없습니다. 나는 알파벳 역순 정렬을 구현하는 이유와 사용자 경험 관점에서 더 우아한 솔루션이 있는지 스스로에게 물어봐야한다고 덧붙일 것입니다.
Andrew De Andrade

1
@AndrewDeAndrade 이유 : 'created_at'속성으로 컬렉션을 정렬하고 최신 컬렉션을 먼저 제공하고 싶습니다. 이 속성은 Backbone의 기본 속성 중 하나이며 String으로 저장됩니다. 당신의 대답은 내가 원하는 것에 가장 가깝습니다. 감사!
Eric Hu

이것은 놀랍습니다. 지난 한 시간 동안 이것에 대한 해결책을 연구하고 있습니다.

28

내 해결책은 정렬 후 결과를 뒤집는 것입니다.

이중 렌더링을 방지하려면 먼저 자동으로 정렬 한 다음 '재설정'을 트리거하십시오.

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

2
더 나은 해결책은 비교기의 결과를 부정하는 것입니다.
Daniel X Moore

7
Daniel, 예를 들어 문자열이나 날짜를 정렬 할 때 항상 가능한 것은 아닙니다.
Gavin Schulz

1
당연히 그렇지. Date의 -Date.getTime()경우 시스템의 날짜가 유닉스 시대를 넘을 것이라고 믿는 경우 추가 해킹으로 비교기가 반환되도록 할 수 있습니다 . 알파벳순의 경우 위의 Andrew의 대답을 참조하십시오.
asparagino

@DanielXMoore 왜 이것이 반드시 더 나은 솔루션입니까? 더 빠릅니까? 개인적으로 나는 사용자가 컬렉션을 마지막으로 정렬 한 속성을 저장하는 것이 매우 쉽다는 것을 알게되었습니다. 그리고 그가 다시 그 속성을 기준으로 정렬한다면 현재 정렬을 반대로합니다. (위키 백과 테이블에서 볼 수있는 정렬 동작을 구현하기 위해, 테이블 헤더에서 속성을 반복적으로 클릭하여 정렬 방향을 전환 할 수 있습니다.) 이렇게하면 비교기 논리를 깨끗하게 유지하고 Asc에서 전환하면 정렬 작업을 절약 할 수 있습니다. 내림차순 정렬 순서
Mansiemans 2013-04-03

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

Backbone 비교기 함수가 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;
      }

},

두 모델을 제외한 비교기, 컬렉션 또는 모델 변경시 compartor 기능이 실행되고 컬렉션의 순서가 변경됩니다.

이 접근 방식을 숫자와 문자열로 테스트했으며 완벽하게 작동하는 것 같습니다.

나는이 문제로 여러 번 고생하고 일반적으로 해결 방법을 사용하기 때문에이 답변이 도움이되기를 바랍니다.


1
이 같은 나는 논리 컬렉션에 살고 있기 때문에,하지만 당신은 쉽게 설정할 수 있습니다 sortKeyreverseSortDirection전화를하고 .sort()컬렉션에 핸들이있는보기에서. 다른 고득점 답변보다 간단합니다.
Noah Heldman 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

현재 주문을 단순히 뒤집고 자하는 사람들을위한 정말 간단한 해결책이 있습니다. 두 방향으로 열을 정렬 할 수있는 테이블이있는 경우 유용합니다.

collection.models = collection.models.reverse()

테이블 케이스 (coffeescript)에 관심이 있다면 다음과 같이 결합 할 수 있습니다.

  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

테이블에 모델을 표시하고 있다는 점에서 약간 다른 요구 사항이 있었는데, 모든 collumn (모델 속성)과 오름차순 또는 내림차순으로 정렬 할 수 있기를 원했습니다.

모든 경우 (값은 문자열, 빈 문자열, 날짜, 숫자가 될 수있는 경우)를 처리하는 데 상당한 양의 작업이 필요했습니다. 그러나 이것은 매우 비슷하다고 생각합니다.

    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 : 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.