How to custom sort grid using two parameters? - extjs

I want to make custom sorting for the grid so that the data/items which have negative id be always placed on top, and the rest should be sorted depending on the selected column (dataIndex)
I have tried to use sortFn in columns but don't know how to proceed. If I return the value then it won't affect sorting by name (in this example).
{
text: 'Name',
zwidth: 150,
autoSizeColumn: true,
sortable: true,
hideable: true,
dataIndex: 'name',
sorter: {
sorterFn: function (a, b) {
if (a.id < 0 || b.id < 0)
// how to put them in first two positons and rest sort by 'name'
}
}
}
The whole example could be found here in this fiddle.
https://fiddle.sencha.com/#view/editor&fiddle/3kqi
I am using ExtJS 6.

Based on the documentation, from the sorter function you need to return:
0 if a and b should be considered as same in terms of order,
1 if a should be after b,
-1 if a should be before b.
So you need to handle the different cases for example like this:
sorterFn: function (a, b) {
if (a.id < 0 && b.id > 0) {
return -1;
}
if (a.id > 0 && b.id < 0) {
return 1;
}
return a.data.name == b.data.name ? 0 : a.data.name > b.data.name ? 1 : -1;
}
This will result in the expected behaviour in your Fiddle if you click on the Name column. However, if you click again for descending sort, the negative ids will be at the end, and the positives at the beginning.
If you'd like to handle descending order differently, you can use this.getDirection() within the sorter function, the result is either ASC or DESC, and you can set up different logic based on this.

Related

How to return column that will be sorted by number within component in React Table?

I am creating a table with React Table library and I don't know how to format returning number for cells and to have working sorting by numbers. When I return something different that number sorting is no longer working as expected It works by alphabetical order not by numerical.
One of columns:
{
Header: "Ocena",
accessor: row => {
const votes = row["usersVote"].reduce(
(acc, r) => acc + (r.vote === "up" ? 1 : -1),
0
);
return (
votes > 0 && (
<StyledVote color="rgb(48, 131, 115)">
+{Number(votes)}
</StyledVote>
)
);
return votes;
},
When I comment out returning of component and leave only return: votes sorting is working properly. How to return a component and have fully working sorting by numerical order?
Ok, I found an answer.
accessor function is calling before data is moved to the table and in that place we should prepare our data to be sortable (in my case I need numbers):
accessor: row => +row['usersVote']
And later when we want to render that data in other way we need to call Cell function
Cell: row => <NumberComponent row={row} />
And do whatever you want to do with that data
Source: https://react-table.tanstack.com/docs/api/useTable#column-options

React Material UI Table Name Sorting seems little bit off

Quick question about sorting the table. Anyone can explain why it's not sorting ASC or DESC example taken straight from Material UI Example: https://codesandbox.io/s/13r5l3qyz3,
Results:
Gargantua
Koala Den
aorro
or
aorro
Koala Den
Gargantua
Thanks
This behavior comes from the way the sort is implemented in this example. Here's the sort function (line 215 in the CodeSandbox you linked to):
const data =
order === "desc"
? this.state.data.sort((a, b) => (b[orderBy] < a[orderBy] ? -1 : 1))
: this.state.data.sort((a, b) => (a[orderBy] < b[orderBy] ? -1 : 1));
Assuming that you're ordering by name and order === "desc", that'll basically boil down to:
const data = this.state.data.sort((a, b) => (b.name < a.name ? -1 : 1));
So, the final order will be a result of comparisons that look like this:
"Koala Den" < "aorro"
"Gargantua" < "Koala Den"
But, JavaScript string comparison can have surprising results. Specifically, since the K in "Koala Den" is uppercase and the a in "aorro" is lowercase, this will be the result:
"Koala Den" < "aorro" // true
"Gargantua" < "Koala Den" // true
So, the sort is working as expected given the sorting method used. It's just not a case-insensitive string sort like you might expect.
You can check this by making "aorro" start with an uppercase A. Then the sort will have the expected results.
To fix this problem, the sort function would probably have to be re-implemented to work with all of the types that could be present in each column.
Converting the data to lower/upper case while comparing helps solve the problem. This also works for strings starting with numbers.
(i.e. for an array like ['Aeon', '3F Works', 'mBand', 'MAQ']
Here is the sample code:
const data =
order === "desc"
? this.state.data.sort((a, b) => (b[orderBy].toLowerCase() < a[orderBy].toLowerCase() ? -1 : 1))
: this.state.data.sort((a, b) => (a[orderBy].toLowerCase() < b[orderBy].toLowerCase() ? -1 : 1));

Grouping in store with values in extjs 6.2

I am trying to group my store on department name . Department name contains some null values also . when i am trying grouping along with sort function its result in multiple group from same name.
see this fiddel for details. I am not getting what i am doing wrong. Kindly advise.
Your sorterFn is wrong.
The sorterFn has to return three different values:
1 if the second argument is strictly greater than the first.
-1 if the second argument is strictly smaller than the first.
0 if both arguments are the same group.
Your sorterFn never returns 0. Try this one:
sorterFn: function(a, b) {
if(a.get('department')=="Management" && b.get('department')=="Management") return 0;
if(a.get('department')=="Management") return 1;
if(b.get('department')=="Management") return -1;
if(a.get('department') < b.get('department')) return 1;
if(a.get('department') > b.get('department')) return -1;
return 0;
},
Furthermore, your transform function is useless. It is called only from the original sorterFn, which you overwrite. You would have to account for null values in your sorterFn, if you wish so. (However, usually one would put fallback categories like "Others" in the end, not between "IT" and "Sales".)
Also, to write the department in the header line, you have to override the groupHeaderTpl template, e.g.
groupHeaderTpl: [
'<tpl if=\'name\'>{name}<tpl else>Others</tpl>'
]

ExtJS 6.2 Sort grid Panel groupings based on summary row

I've been searching for hours to figure out how to do this. Essentially what I want to do is group data based on one column, create a summary for that grouping, then sort the groups based on the summary.
Using one of their kitchen sink examples, I would like to be able to sort these groups by summary value rate.
http://examples.sencha.com/extjs/6.0.0/examples/classic/grid/group-summary-grid.html
This can be done using a grouper with a sorterFn. The sorterFn should compare the summary values you are sorting by. For the kitchen sink example you mentioned, if you want to sort by the sum of the estimate column while grouping by the project column, the grouper would look like:
groupers: [{
property: 'project',
sorterFn: function(a,b) {
var suma=0; store.each(function (rec) { suma += rec.data.project === a.data.project ? rec.data.estimate:0; });
var sumb=0; store.each(function (rec) { sumb += rec.data.project === b.data.project ? rec.data.estimate:0; });
if (suma > sumb) return 1;
if (suma < sumb) return -1;
return 0;
}
}]
The grouper can be applied using:
store.group(store.groupers[0]);
See fiddle: https://fiddle.sencha.com/#fiddle/1im3

In ExtJS how do I know when a store starts sorting and finishes sorting?

I have a store for a grid. The user can click on the headers to sort. I need to know when a store begins sorting and finishes sorting. What do I attach to? I can see no begin sort and end sort events for the store.
Here is the sort that I am using:
Ext.override(Ext.data.Store, {
// override
createSortFunction: function (field, direction) {
direction = direction || "ASC";
var directionModifier = direction.toUpperCase() == "DESC" ? -1 : 1;
var sortType = this.fields.get(field).sortType;
//create a comparison function. Takes 2 records, returns 1 if record 1 is greater,
//-1 if record 2 is greater or 0 if they are equal
return function (r1, r2) {
var v1;
var v2;
v1 = sortType(r1.data[field]);
v2 = sortType(r2.data[field]);
// To perform case insensitive sort
if (v1.toLowerCase) {
v1 = v1.toLowerCase();
v2 = v2.toLowerCase();
}
return directionModifier * (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
};
}
});
The general solution is that you should use Ext.util.Observable.capture() to listen to all events on the store so you can see what is really happening.
The answer is that it depends on whether remoteSort is true or not. If it's true, it does the same thing as loading the store from the server. If it is false, then it would appear to be synchronous.
Remote Sort:
beforeload
datachanged
refresh
load
read
Local Sort:
datachanged
read
Sorting about 1000 elements took 20ms
Demonstration:
http://jsfiddle.net/el_chief/q9cvs/3/
You could fire your own events too:
Ext.data.Store.override({
sort: function(sorters, direction){
this.fireEvent('sorting', this, {});
this.callParent(arguments);
this.fireEvent('sorted', this, {});
}
});

Resources