Với Backbone.js, tôi đã thiết lập một bộ sưu tập với hàm so sánh. Nó sắp xếp các mô hình một cách độc đáo, nhưng tôi muốn đảo ngược thứ tự.
Làm cách nào để sắp xếp các mô hình theo thứ tự giảm dần thay vì tăng dần?
Với Backbone.js, tôi đã thiết lập một bộ sưu tập với hàm so sánh. Nó sắp xếp các mô hình một cách độc đáo, nhưng tôi muốn đảo ngược thứ tự.
Làm cách nào để sắp xếp các mô hình theo thứ tự giảm dần thay vì tăng dần?
Câu trả lời:
Vâng, bạn có thể trả về giá trị âm từ trình so sánh. Ví dụ, nếu chúng ta lấy ví dụ từ trang web của Backbone và muốn đảo ngược thứ tự, nó sẽ như thế này:
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'));
Cá nhân tôi không hài lòng với bất kỳ giải pháp nào được đưa ra ở đây:
Giải pháp nhân với -1 không hoạt động khi kiểu sắp xếp không phải là số. Mặc dù có những cách giải quyết vấn đề này (bằng cách gọi Date.getTime()ví dụ) những trường hợp này là cụ thể. Tôi muốn một cách tổng quát để đảo ngược hướng của bất kỳ loại nào mà không phải lo lắng về loại trường cụ thể được sắp xếp.
Đối với giải pháp chuỗi, việc xây dựng một chuỗi một ký tự tại một thời điểm có vẻ giống như một nút cổ chai về hiệu suất, đặc biệt là khi sử dụng các bộ sưu tập lớn (hoặc thực sự, các chuỗi trường sắp xếp lớn)
Đây là một giải pháp hoạt động hiệu quả cho các trường Chuỗi, Ngày và Số:
Đầu tiên, khai báo một bộ so sánh sẽ đảo ngược kết quả của một kết quả của một hàm sortBy, như sau:
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;
};
}
Bây giờ, nếu bạn muốn đảo ngược hướng của loại, tất cả những gì chúng ta cần làm là:
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'));
Lý do điều này hoạt động là Backbone.Collection.sorthoạt động khác nhau nếu hàm sắp xếp có hai đối số. Trong trường hợp này, nó hoạt động theo cách giống như trình so sánh được truyền vào Array.sort. Giải pháp này hoạt động bằng cách điều chỉnh hàm sortBy đối số đơn thành một bộ so sánh hai đối số và đảo ngược kết quả.
Bộ so sánh bộ sưu tập của Backbone.js dựa vào phương thức Underscore.js _.sortBy. Cách sortBy được triển khai kết thúc bằng cách "gói" javascript .sort () theo cách làm cho việc sắp xếp ngược lại các chuỗi trở nên khó khăn. Sự phủ định đơn giản của chuỗi kết thúc trả về NaN và phá vỡ sắp xếp.
Nếu bạn cần thực hiện sắp xếp ngược lại với Chuỗi, chẳng hạn như sắp xếp theo thứ tự bảng chữ cái ngược, đây là một cách thực sự khó thực hiện:
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;
}
Nó không có nghĩa là đẹp, nhưng nó là một "bộ phủ định chuỗi". Nếu bạn không gặp bất kỳ e ngại nào với việc sửa đổi các loại đối tượng gốc trong javascript, bạn có thể làm cho mã của bạn rõ ràng hơn bằng cách trích xuất trình phủ định chuỗi và thêm nó như một phương thức trên String.Prototype. Tuy nhiên, bạn có thể chỉ muốn làm điều này nếu bạn biết mình đang làm gì, vì việc sửa đổi các loại đối tượng gốc trong javascript có thể gây ra những hậu quả không lường trước được.
Giải pháp của tôi là đảo ngược kết quả sau khi sắp xếp.
Để ngăn kết xuất kép, hãy sắp xếp đầu tiên với im lặng, sau đó kích hoạt 'đặt lại'.
collections.sort({silent:true})
collections.models = collections.models.reverse();
collections.trigger('reset', collections, {});
-Date.getTime(), có thể có thêm một số hack nếu bạn tin rằng ngày trong hệ thống của mình sẽ vượt qua kỷ nguyên unix. Đối với thứ tự bảng chữ cái, hãy xem câu trả lời của Andrew ở trên.
Sửa đổi hàm so sánh của bạn để trả về một số giá trị theo tỷ lệ nghịch thay vì trả về dữ liệu hiện tại của bạn. Một số mã từ: http://documentcloud.github.com/backbone/#Collection-comparator
Thí dụ:
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"}));
Những điều sau đây hoạt động tốt cho tôi:
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
Tôi đã đọc một số nơi mà hàm so sánh Backbone sử dụng hoặc bắt chước hàm Array.prototype.sort () của JavaScript. Điều này có nghĩa là nó sử dụng 1, -1 hoặc 0 để quyết định thứ tự sắp xếp của từng mô hình trong bộ sưu tập. Điều này liên tục cập nhật và bộ sưu tập vẫn theo thứ tự chính xác dựa trên bộ so sánh.
Thông tin về Array.prototype.sort () có thể được tìm thấy tại đây: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?redirectlocale=en-US&redirectslug=JavaScript% 2FReference% 2FGlobal_Objects% 2FArray% 2Fsort
Nhiều câu trả lời cho câu hỏi này chỉ đơn giản là đảo ngược thứ tự ngay trước khi đưa nó lên trang. Đây không phải là lý tưởng.
Sử dụng bài viết trên trên Mozilla làm hướng dẫn, tôi đã có thể sắp xếp bộ sưu tập của mình theo thứ tự ngược lại bằng cách sử dụng mã sau, sau đó chúng tôi chỉ cần hiển thị bộ sưu tập sang trang theo thứ tự hiện tại và chúng ta có thể sử dụng cờ (reverseSortDirection) để đảo ngược thứ tự .
//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;
}
},
Bộ so sánh ngoại trừ hai mô hình, khi thay đổi bộ sưu tập hoặc mô hình, chức năng bộ so sánh sẽ chạy và thay đổi thứ tự của bộ sưu tập.
Tôi đã thử nghiệm cách tiếp cận này với Numbers và Strings và dường như nó hoạt động hoàn hảo đối với tôi.
Tôi thực sự hy vọng câu trả lời này có thể giúp ích vì tôi đã vật lộn với vấn đề này nhiều lần và thường kết thúc bằng cách sử dụng một công việc xung quanh.
sortKeyvà reverseSortDirectionvà cuộc gọi .sort()từ bất kỳ điểm cho rằng có một tay cầm vào bộ sưu tập. Đối với tôi, đơn giản hơn những câu trả lời được bình chọn cao hơn khác.
Điều này có thể được thực hiện một cách trang nhã bằng cách ghi đè phương thức sortBy. Đây là một ví dụ
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');
}
});
Vì vậy, bạn có thể sử dụng nó như thế này:
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();
Giải pháp này không phụ thuộc vào loại trường.
Đây là một giải pháp thực sự đơn giản, dành cho những người chỉ đơn giản muốn lật thứ tự hiện tại. Sẽ rất hữu ích nếu bạn có một bảng có các cột có thể được sắp xếp theo hai hướng.
collection.models = collection.models.reverse()
Bạn có thể kết hợp nó với một cái gì đó như thế này nếu bạn quan tâm đến trường hợp bảng (coffeescript):
collection.comparator = (model) ->
model.get(sortByType)
collection.sort()
if reverseOrder
collection.models = collection.models.reverse()
Tôi có một yêu cầu hơi khác, đó là tôi đang hiển thị các mô hình của mình trong một bảng và tôi muốn có thể sắp xếp chúng theo bất kỳ cột nào (thuộc tính mô hình) và tăng dần hoặc giảm dần.
Phải mất rất nhiều thời gian để làm cho tất cả các trường hợp hoạt động (trong đó các giá trị có thể là chuỗi, chuỗi rỗng, ngày tháng, số. Tuy nhiên, tôi nghĩ điều này khá gầ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;
}
},
sử dụng:
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);
},
Tôi chỉ ghi đè hàm sắp xếp để đảo ngược mảng mô hình khi hoàn thành. Ngoài ra, tôi đã tạm dừng việc kích hoạt sự kiện 'sắp xếp' cho đến khi hoàn thành việc đảo ngược.
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;
},
Gần đây đã gặp phải vấn đề này và chỉ quyết định thêm một phương thức 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;
}
});
Hy vọng rằng ai đó sẽ thấy điều này hữu ích
Đây là một cách nhanh chóng và dễ dàng để sắp xếp ngược lại các mô hình của bộ sưu tập bằng cách sử dụng UnderscoreJS
var reverseCollection = _.sortBy(this.models, function(model) {
return self.indexOf(model) * -1;
});