PDA

View Full Version : Multiple fields sort



cristi_vladan
25 Sep 2008, 10:33 PM
I saw multiple opened threads, discussions talking about Ext.data.Store support for multiple fields sort and i didn't saw any valid solution, here is my solution:


Ext.override(Ext.data.Store, {

sortData : function(f, direction){
direction = direction || 'ASC';
var st = this.fields.get(f).sortType;
var multipleSortInfo = this.fields.get(f).multipleSortInfo;

var fn = function(r1, r2){
var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
var ret = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
for (i = 0 ; (multipleSortInfo !== undefined && ret == 0 && i < multipleSortInfo.length); i++) {
var x1 = r1.data[multipleSortInfo[i].field], x2 = r2.data[multipleSortInfo[i].field];
var dir = (direction != multipleSortInfo[i].direction) ? direction.toggle("ASC", "DESC") : direction;
ret = (x1 > x2) ? 1 : ((x1 < x2) ? -1 : 0);
if (dir == 'DESC') ret = -ret;


};
return ret;
};
this.data.sort(direction, fn);
if(this.snapshot && this.snapshot != this.data){
this.snapshot.sort(direction, fn);
}
}
});


You can use this feature by adding a new property to the Ext.data.Record, reader fields:

For example if you want to add an extra field to be the second, third sort criteria, you can do by adding this property multipleSortInfo to the field when you build the reader record.


rec = Ext.data.Record.create([
{name: 'a', type:'float'},
{name: 'b', type:'float'},
{name: 'date', type: 'date', dateFormat: 'd/m/Y', multipleSortInfo: [{field: 'b', direction:'DESC'}, {field: 'a', direction:'ASC'}]}
]);
reader = new Ext.data.JsonReader({
root: 'x'
}, rec);

store = new Ext.data.GroupingStore({
url: '/servlet', // you can load data here for example
sortInfo:{field: 'date', direction: "ASC"},
reader: reader
});

So if you want to sort the store by date field, the date field will be the first sort criteria, and when there are multiple records with the same value, the second sort criteria will be b and so on ... (a, etc.).
Direction from multipleSortInfo will be toggled, when sort will be changed in the main field.
So, you can bind this store to a grid for example, and if you sort(click on header) by date ASC, then if there are multiple b on the same date, the b field will be first sorted DESC and so on ...

Christian.

Animal
1 Oct 2008, 1:37 AM
Or



Ext.override(Ext.data.Store, {
/**
* Sort by multiple fields in the specified order.
* @param {Array} An Array of field sort specifications, or, if ascending
* sort is required on all columns, an Array of field names. A field specification
* looks like:<pre><code>
{
field: 'orderNumber',
direction: 'ASC'
}
</code><pre>
*/
sortByFields: function(fields) {

// Collect sort type functions,
// Convert string field names to field+direction spec objects.
var st = [];
for (var i = 0; i < fields.length; i++) {
if (typeof fields[i] == 'string') {
fields[i] = {
field: fields[i],
direction: 'ASC'
};
}
st.push(this.fields.get(fields[i].field).sortType);
}

var fn = function(r1, r2) {
var result;
for (var i = 0; !result && i < fields.length; i++) {
var v1 = st[i](r1.data[fields[i].field]);
var v2 = st[i](r2.data[fields[i].field]);
result = (v1 > v2) ? 1 : ((v1 < v2) ? -1 : 0);
if (fields[i].direction == 'DESC') result = -result;
}
return result;
};
this.data.sort('ASC', fn);
if(this.snapshot && this.snapshot != this.data){
this.snapshot.sort('ASC', fn);
}
this.fireEvent("datachanged", this);
}
});

DTT_11-1983
1 Oct 2008, 6:22 PM
Hi Animal,
Where can I put sortByFields to my code ?
I'm newbie. I tried put it in my Reader

{name: 'column2', sortByFields: [{field: 'column1', direction:'DESC'}, {field: 'column2', direction:'ASC'}]}
but it does not work.
Thanks

mjlecomte
1 Oct 2008, 6:52 PM
Good work, I'm sure there will be some happy campers out there to see this.

As constructive suggestion: What would probably be good is to add this to the header menu where you can alter the sort dynamically. Currently you can click on the header anywhere to sort the column, or if you hover over the hidden dropdown you can click on sorting options. So in those dropdowns might be some way to specify that you want to add to the sort array and if so in which direction should the sort be.

Taking the thought even further there might be a sort submenu similar to the "columns" submenu. That submenu might be the GUI for the active sort implementation on the grid. Maybe that submenu could support drag/drop so you could alter the order of the sorted fields.

I suppose an alternative to that complexity might be to implement a context menu or add to the existing menu a custom sort option the way excel does to implement the same (see image).

http://extjs-ux.org/repo/authors/mjlecomte/images/excel_sort.PNG

cristi_vladan
2 Oct 2008, 3:13 AM
Hi Animal,
Where can I put sortByFields to my code ?
I'm newbie. I tried put it in my Reader

{name: 'column2', sortByFields: [{field: 'column1', direction:'DESC'}, {field: 'column2', direction:'ASC'}]}
but it does not work.
Thanks

Try my solution!

Animal
2 Oct 2008, 8:52 AM
Hi Animal,
Where can I put sortByFields to my code ?
I'm newbie. I tried put it in my Reader

{name: 'column2', sortByFields: [{field: 'column1', direction:'DESC'}, {field: 'column2', direction:'ASC'}]}
but it does not work.
Thanks

It's a function, you have to call it and it sorts by the fields you specify.

egs
30 Oct 2008, 1:23 AM
@Animal -- I have been looking at your sortByFields function and I'm wondering if it's possible to use this for sorting by Group Count when using a GroupingView.

Here's a link to a thread describing the issue: http://extjs.com/forum/showthread.php?t=51306

When using a GroupingView I can group by one field, and sort by the same or another field.
I want to be able to group by one field and sort by the group count. Since this group count is different depending on the field I group by, I cannot use a "bogus" field to store the count.

Any tips/advice would be greatly appreciated !

Thanks !



Or



Ext.override(Ext.data.Store, {
/**
* Sort by multiple fields in the specified order.
* @param {Array} An Array of field sort specifications, or, if ascending
* sort is required on all columns, an Array of field names. A field specification
* looks like:<pre><code>
{
field: 'orderNumber',
direction: 'ASC'
}
</code><pre>
*/
sortByFields: function(fields) {

// Collect sort type functions,
// Convert string field names to field+direction spec objects.
var st = [];
for (var i = 0; i < fields.length; i++) {
if (typeof fields[i] == 'string') {
fields[i] = {
field: fields[i],
direction: 'ASC'
};
}
st.push(this.fields.get(fields[i].field).sortType);
}

var fn = function(r1, r2) {
var result;
for (var i = 0; !result && i < fields.length; i++) {
var v1 = st[i](r1.data[fields[i].field]);
var v2 = st[i](r2.data[fields[i].field]);
result = (v1 > v2) ? 1 : ((v1 < v2) ? -1 : 0);
if (fields[i].direction == 'DESC') result = -result;
}
return result;
};
this.data.sort('ASC', fn);
if(this.snapshot && this.snapshot != this.data){
this.snapshot.sort('ASC', fn);
}
this.fireEvent("datachanged", this);
}
});

Animal
30 Oct 2008, 7:37 AM
You'll have to look at the source. The GroupingStore will have to sort by the group field followed by whatever other fields you want to sort by. It should just work as long as teh group field is the first field in the sortByFields parameters.

egs
31 Oct 2008, 3:44 AM
@Animal -- You say that the GroupingStore will have to sort by the group field followed by whatever other fields I want to sort by. But, afaik the Group count is not a field. The Group count will not be the same if I Group by another field.

Today I'm using
values.rs.length to display the Group count. Are you saying that I can use this as a field reference as well ?

Thanks for any information !

Animal
31 Oct 2008, 10:38 AM
Group "count"?

http://extjs.com/deploy/dev/docs/?class=Ext.data.GroupingStore&member=groupField

The GroupingStore sorts by the groupField. This is what enables the GroupingView to collect its data.

You need to tell it to sort by the groupField, and then the other fields.

egs
2 Nov 2008, 7:59 AM
Hmm.. It might be me not getting this, but I'll try to explain it once more.

If you take a look at the picture bellow, you'll see a grid using a GroupingView.
The groupField property of the GroupingStore is set to the title column.

As a result of this the grid is grouped by the title field.

Now, I would like groups to be sorted on the "Group Count". To get the number of documents/rows in each group I use: values.rs.length


view: new Ext.grid.GroupingView({
forceFit:true,
hideGroupedColumn: true,
startCollapsed: true,
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Reads" : "Read"]})'
}),

In the picture you can see that groups are grouped by title, but the "Group Count" is not sorted. I would like the group with 32 reads to be at top, and the group with 5 read to be at the bottom.

The "Group Count" would be different depending on the column/field I choose to group by, and cannot then be a field in the GroupingStore.

The big question is then: How can I Group By a spesific column using the groupField property, but then sort by the "Group Count" ?

Grid Grouped by the Title field:
http://egdomino1.sfj.ergogroup.no/Test/Petter/Temp.nsf/GroupCount.gif

Same grid, but sorted by the Read Date field:
http://egdomino1.sfj.ergogroup.no/Test/Petter/Temp.nsf/GroupCount2.gif

Thanks !

Best regards,
Petter

johnstontrav
25 Nov 2008, 6:23 PM
Hi Animal,


It's a function, you have to call it and it sorts by the fields you specify.

I am trying to get your multi-sorting code working. Here is my call string:


this.store.sortByFields([{field: 'date', direction: 'DESC'},{field: 'sta', direction: 'ASC'}]);

Nothing happens.

here is my code structure:


Ext.ns('myNS');

myNS.myGrid = Ext.extend(Ext.grid.EditorGridPanel, {
border:false
,initComponent:function() {
....
....
Ext.apply(this, {
store: this.store
,loadMask: true
,cm: cm
....

});

Verigo.myGrid.superclass.initComponent.apply(this, arguments);

} // end of initComponent

,onRender:function() {

....

} // end of function onRender


});

Ext.reg('myGrid', myNS.myGrid);I have tried calling sortByFields in the initComponent and the onRender function without success. Can you give me any assistance?

Cheers,
Trav.

imnilesh
30 Aug 2009, 9:38 PM
Thanks Christian, Animal.
Above sortData function works fine for me in Ext 3.0. Though the 'datachanged' event is generated my grid is not refreshing the sort data. My code:



Ext.override(Ext.data.Store, {

sortData : function(f, direction){
// a test sort info
var multipleSortInfo = [{field: 'number', direction: 'ASC'}, {field: 'name', direction: 'DESC'}];
direction = direction || 'ASC';

var st = this.fields.get(field).sortType;

var fn = function(r1, r2) {
var ret = 0;
for (i = 0; (multipleSortInfo !== undefined && ret == 0 && i < multipleSortInfo.length); i++) {
var v1 = st(r1.data[field]), v2 = st(r2.data[field]);
var x1 = r1.data[multipleSortInfo[i].field], x2 = r2.data[multipleSortInfo[i].field];
var dir = (direction != multipleSortInfo[i].direction) ? direction
.toggle("ASC", "DESC") : direction;
ret = (x1 > x2) ? 1 : ((x1 < x2) ? -1 : 0);
if (dir == 'DESC')
ret = -ret;
};
return ret;
};

this.data.sort(direction, fn);
if (this.snapshot && this.snapshot != this.data) {
this.snapshot.sort(direction, fn);
}
}

Am I missing anything here ?

Dusted
26 Oct 2009, 3:35 AM
Hi guys,

Egs, have you found a solution to ordering by the group count as I am trying to do the same thing.

I am producing a list of people and the forum posts they have made and I would like to order by the number of posts. I am grouping on the name and I am also bringing back the number of times they have posted but it will not let me order by that number, it is still ordering by the name. I have tried using both sortInfo and store.setDefaultSort but the grid is still sorting by the name.

Any ideas?

Dusted
27 Oct 2009, 12:52 AM
For those of you wondering how this is done, if you set the remoteGroup config option to true then you can specify your own grouping in the method you use to get the store, in my case a stored procedure. Using this you can order the on the DB side and handle any other re-ordering in the XHR call.

Dusted

yaminih
25 Nov 2009, 2:06 AM
Hi,
I am facing a similar issue. I have 3 columns - Period,Name and Type. Type can be 'Low','Medium','High'. However, when I click on Sort Asc in the header, I want the display as follows:
Low
Medium
High
which is not necessarily alphabetical order.
Is there any way to define custom sorting. I tried as follows but doesnt work:

var config = {
sortableField: 'Type.Name'
};
Ext.apply(this, {
store: new Ext.data.Store({
reader: new Ext.data.JsonReader(
{
id: 'Id'
},
Ext.data.Record.create([
{ name: 'Id', mapping: 'Id' },
{ name: 'ReportingPeriod.Name', mapping: 'ReportingPeriod.Name' },
{ name: 'Name', mapping: 'Name' },
{ name: 'Type.Name', mapping: 'Type.Name', sortType: this.sortTypes }
])
)
}),
columns: [
{ header: "Id", width: 20, sortable: true, dataIndex: 'Id', hidden: true },
{ header: "Period", width: 175, sortable: true, dataIndex: 'ReportingPeriod.Name' },

{ header: "Name", width: 125, sortable: true, dataIndex: 'Name', minWidth: 100 },
{ header: "Type", width: 125, sortable: true, dataIndex: 'Type.Name', minWidth: 100 }
],
height: 150,
width: 400,
autoScroll: true,
closable: true,
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: {
rowselect: function(sm, rowidx, rec) {

}
}),
viewConfig: {
forceFit: true
}
});


----other code--,

sortTypes: function(value) {
switch (value.toLowerCase()) {
case 'Low':
return 1;
case 'Medium':
return 2;
case 'High':
return 3;

}
return 4;
},


Any help is appreciated..Thanks in advance..

imnilesh
25 Nov 2009, 5:55 AM
Do the function always returning 4 ??

sortTypes: function(value) {
switch (value.toLowerCase()) {
case'Low': ====> should it be 'low' here ?
return 1;
case'Medium': ====> medium
return 2;
case'High': ====> high
return 3;

}
return 4;
},

Dusted
27 Nov 2009, 11:21 AM
@yaminih

Are you loading the data into the grid using a query? In my case i was and gave high, medium and low the Id's 1,2 and 3 so that i could order them as you are trying.

This only works if you are using a database call though...

suchitratata
9 Jul 2010, 12:19 AM
Animal,

I just wanted to check if I can use your sortByFields() in Ext 3.0 as well. If so, where do I call that function? I tried to call it in sortChange listener of my gridpanel but it goes into endless recursion