Problem with jQuery Tablesorter custom-filter having accented characters and special config - filter

I'm facing issue with custom filter defined when they :
have accented characters
textExtraction defined (to set usage of data-sort-value attribute i/o node text)
sortLocalCompare is set to true
Steps to reproduce
In column named '2' (I'm using flaticon in my app), select option "Modéré" or ">= Modéré"
Observed result
The filters doesn't find any result => the table is empty
Expected result
It should find :
1 row (when using option "Modéré") OR
2 rows (when using option ">= Modéré" as "Sérieux" is greater than "Modéré")
Please find the link with the described situation.
When I changed either:
sortLocalCompare:false
comment/remove the textExtraction attribute definition
Both case, one of them is enough, make things working.
Of course, both option to remove doesn't satisfy me as workaround. Because:
Option 1: sortLocalCompare:false when we sort by second column "Société", the company "Bâloise" is then sorted AFTER "BVZ Holding" which is due to the "â".
Option 2: I need the textExtraction function defined as I set integer values to make logic working with ">= Modéré" or also to add multiple integer separated by semicolumn to handle multiple themes to an element (and to have a custom filter listing all themes once)
I tried to make the example as short and comprehensive as possible. This table can be generated in 3 languages (My app is in english, french, german) and the filters are applied with CSS class name to be used in multiple tables accross the application like I do.
Here is the short version of my generic config (multiple tables using it) :
$(function() {
$(".tablesorter").tablesorter({
theme: 'blue',
sortLocaleCompare: true,
widgets: ["filter"],
textExtraction: textExtractionDataSortValue,
filter_onlyAvail: 'filter-onlyAvail',
widgetOptions: {
filter_functions: {
'.filter-controversy': filterControversy,
}
}
});
});
The custom filter function (generated either with english, french or german depending on the user's language):
var filterControversy = {
'Aucun': function(e, n) {
console.info(e + " n=" + n);
return e == '';
},
'Modéré': function(e, n) {
console.info(e + " n=" + n);
return e == 101;
},
' >=Modéré': function(e, n) {
console.info(e + " n=" + n);
return e >= 101;
},
'Serieux': function(e, n) {
console.info(e + " n=" + n);
return e == 102;
},
' >=Sérieux': function(e, n) {
return e >= 102;
},
'Sévère': function(e, n) {
return e == 106;
},
'Majeur': function(e, n) {
console.info(e + " n=" + n);
return e == 103;
},
'Tous': function(e, n) {
return e != '';
}
}
Thanks for your help
Tablesorter version : 2.31.3 (latest)

So you are correct about the behavior of the sortLocaleCompare causing the problem. What is happening is the filter function name is getting the accents removed. In order to solve this, you'll need to change the function name to include both the non-accent name (used for the function) along with the accented name (shown to the users) demo
You should only need to change the filterControversy object as follows:
var filterControversy = {
'Aucun': function(e, n) {
return e == '';
},
'Modere|Modéré': function(e, n) {
return e == 101;
},
' >=Modere| >=Modéré': function(e, n) {
return e >= 101;
},
'Serieux': function(e, n) {
return e == 102;
},
' >=Serieux| >=Sérieux': function(e, n) {
return e >= 102;
},
'Severe|Sévère': function(e, n) {
return e == 106;
},
'Majeur': function(e, n) {
return e == 103;
},
'Tous': function(e, n) {
return e != '';
}
};
The | separator can be changed using the filter_selectSource widget option

Related

Modifying sort columns in jqGrid

I'm having some difficulty figuring out how to programatically modify the sort definition that is sent to the server when a user clicks on a column to sort it. I have added a onSortCol function to my grid configuration. In that function, I need to check whether the "Id" column is in any sort position other than the last position. If it is, it should be removed.
Here is what I have tried:
onSortCol: function (index, iCol, sortOrder) {
var grid = $(this);
var rawSorts = index.split(",");
if (rawSorts.length > 1) {
var idFieldIndex = -1;
var processedSorts = [];
for (i = 0; i < rawSorts.length; i++) {
var currentSort = rawSorts[i].match(/[^ ]+/g);
if (idFieldIndex === -1 && currentSort[0].toUpperCase() === "ID") {
idFieldIndex = i;
}
processedSorts.push({
field: currentSort[0],
direction: currentSort[1] || sortOrder
})
}
if (idFieldIndex !== -1) {
processedSorts.splice(idFieldIndex, 1);
for (i = 0; i < processedSorts.length; i++) {
if (i + 1 < processedSorts.length) {
grid.sortGrid(processedSorts[i].field + " " + processedSorts[i].direction);
}
else {
grid.setGridParam("sortorder", processedSorts[i].direction);
grid.sortGrid(processedSorts[i].field + " ", true);
}
}
return "stop";
}
}
}
The most simple implementation seems to me the following: you don't use any sortname in the grid initially and you sort by Id on the server side if sidx is empty. It seems the only what you need to do to implement your requirements.

SlickGrid exclude slick-group (Group Header) row when sorting

I'm using SlickGrid with Groupings and need to sort the data within each Group but leave the Grouping (group header row) in the default order.
Sorting seems to sort the column data and then reorder the Grouping Headers per the data.
Has anyone done this or do I have a option/parameter set incorrectly?
Thanks
Here is my example of grouping+sorting. Take note that when I want to sort it does a sort against the column you are grouping by, I can't sort with any other columns unless it's the grouping by column (well not the way I coded my function anyway, though you could play with that)
<select id="slc_groupby" name="slc_groupby" onchange="groupByColumn(this.value)">
<option value="">...</option>
<option value="assy_number">Assy Number</option>
</select>
<span id="span_group_btn" style="position:absolute; display:none; margin-left:5px; margin-top:20px;">
<!-- Group sorting, I show this button only after a grouping column is chosen -->
<img src="/images/b_updownarrow2.gif" id="img_sorting" border="0" onclick="groupByColumn( $('#slc_groupby').val() )" />
</span>
and here comes the javascript function for grouping+sorting, take note that whenever you click on the sort button (the top one with html ID=img_sorting), it has the effect of regrouping and resorting through the groupByColumn() function (since I'm using the onclick event), though it happens so fast that you don't really see it makes a grouping again... but that's the way I got it working in all browser (Chrome included)
function groupByColumn(column) {
// sorting direction, if undefined just inverse the current direction of the global sortdir var (sortdir is defined as global variable in slickgrid)
sortdir = ((sortdir == 1) ? -1 : 1);
dataView1.groupBy(
column,
function (g) {
return g.value + " <span style='color:green'>(" + g.count + " items)</span>";
},
function (a, b) {
var a1 = a.value;
var b1 = b.value;
// string sorting
return sortdir * (a1 == b1 ? 0 : (a1 > b1 ? 1 : -1));
}
);
// display the button for group sorting
$('#span_group_btn').css("display", "inline");
}
Since U did not provide source, I can guess that your problem is with the sort method, which sorts only by selected column, so you must first sort by grouping column.
Let's say that you are grouping by UserName and have sortable column Title, your onSort method should look similar to this:
grid.onSort.subscribe(function (e, args) {
sortdir = args.sortAsc ? 1 : -1;
sortcol = args.sortCol.field; // Title column
var comparer = function (a, b) {
var x = a['UserName'], y = b['UserName'];
if (x != y)
{
return (x < y ? 1 : -1) * sortdir;
}
else
{
x = a[sortcol];
y = b[sortcol];
return (x == y ? 0 : (x > y ? 1 : -1));
}
};
dataView.sort(comparer, args.sortAsc);
});
Lets say you are grouping with 4 different columns - department, faculty, course, semester. While sorting, you manually compare these columns and always sort them in ascending or descending (whichever is your default order in the beginning), for rest of other columns you use sort direction by flipping the result of compare function
function comparer(a, b) {
return (x == y ? 0 : (x > y ? 1 : -1));
}
grid.onSort.subscribe(function(e, args) {
$(e.target).parents(".slick-header-columns").find(
".slick-header-column").removeClass(
"slick-header-column-sorted");
var currentCol = $(e.target).hasClass("slick-header-column") ? $(e.target): $(e.target).parents(".slick-header-column");
currentCol.addClass("slick-header-column-sorted");
currentCol.find(".slick-sort-indicator").removeClass(args.sortAsc ? "desc" : "asc").addClass(args.sortAsc ? "asc" : "desc");
var sortdir = args.sortAsc ? 1 : -1;
var sortcol = args.sortCol.field;
var items = dataView.getItems();
items.sort(function(a, b) {
var deptCompare = a.department == b.department ? 0 : (a.department < b.department ? -1 : 1);
if (deptCompare === 0) {
var facultyCompare = a.faculty == b.faculty ? 0 : (a.faculty < b.faculty ? -1 : 1);
if (facultyCompare === 0) {
var courseCompare = a.course == b.course ? 0 : (a.course < b.course ? -1 : 1);
if (courseCompare === 0) {
var semesterCompare = a.semester == b.semester ? 0 : (a.semester < b.semester ? -1 : 1);
if (semesterCompare === 0) {
var fieldCompare = comparer(a[sortcol], b[sortcol]);
return fieldCompare * sortdir;
} else {
return semesterCompare;
}
} else {
return courseCompare;
}
} else {
return facultyCompare;
}
} else {
return deptCompare;
}
});
dataView.refresh();
});
Second way to achieve the same is to user comparer in grouping level.
You define a comparer for group,
function groupComparer(a, b) {
var x = a.groupingKey
var y = b.groupingKey;
return (x == y ? 0 : (x > y ? 1 : -1));
}
dataView.setGrouping([
{
getter : "department",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
},{
getter : "faculty",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
},{
getter : "course",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
},{
getter : "semester",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
}
]);
And user regular sorting
grid.onSort.subscribe(function (e, args) {
dataView.sort(function(a,b){
var x = a[args.sortCol.field];
var y = b[args.sortCol.field];
return (x == y ? 0 : (x > y ? 1 : -1));
}, args.sortAsc);
});

Setting Sort Direction on Column Click for ASP.NET Telerik MVC Grid Column

Currently using the Telerik MVC 3.0 in Asp.net. I Have grid with few Columns.
When the pageloads the rows are binded. When i click on the column it should sort in Descending sorder in the first Click instead of Ascending order.
You can do it by overwritting grid's toggleOrder method.
First, define a new ReverseToggleOrder function:
function ReverseToggleOrder(l) {
l = typeof l == "number" ? this.columns[l] : l;
var n = "desc";
if (l.order == "desc") {
n = "asc";
} else {
if (l.order == "asc") {
n = null;
}
}
l.order = n;
var m = $.inArray(l, this.sorted);
if (this.sortMode == "single" && m < 0) {
$.each(this.sorted, function () {
this.order = null;
});
this.sorted = [];
}
if (m < 0 && n) {
this.sorted.push(l);
}
if (!n) {
this.sorted.splice(m, 1);
}
}
function grid_onLoad(e) {
var grid = $(this).data('tGrid');
grid.toggleOrder = ReverseToggleOrder;
}
Then in grid's OnLoad event handler you need to overwrite its default behaviour:
.ClientEvents(events => events.OnLoad("grid_onLoad"))
The Grid does not support such sorting configuration. It always sorts ASC then DESC.

Calling sort on slickgrid

In the slickgrid I'm able to set the sort column and it's sort direction using the grid.SetSortColumn(colName,true/false). This only sets the sorting glyph but does no sorting. Is there a way to call the sort event handler. I've defined the sort handler like grid.onSort.subscribe(function(){});
The behavior you are observing is correct.
grid.setSortColumn(columnId, isAsc);
only updates the glyph on the sort column.
In your case, you will initially need to sort the data, and then use setSortColumn to update the glyph on sortColumn. You can reuse sorter used in onSort event like this:
var gridSorter = function(columnField, isAsc, grid, gridData) {
var sign = isAsc ? 1 : -1;
var field = columnField
gridData.sort(function (dataRow1, dataRow2) {
var value1 = dataRow1[field], value2 = dataRow2[field];
var result = (value1 == value2) ? 0 :
((value1 > value2 ? 1 : -1)) * sign;
return result;
});
grid.invalidate();
grid.render();
}
var grid = new Slick.Grid($gridContainer, gridData, gridColumns, gridOptions);
//These 2 lines will sort you data & update glyph while loading grid
//columnField is field of column you want to sort initially, isAsc - true/false
gridSorter(columnField, isAsc, grid, gridData);
//I had the columnField, columnId same else used columnId below
grid.setSortColumn(columnField, isAsc);
grid.onSort.subscribe(function(e, args) {
gridSorter(args.sortCol.field, args.sortAsc, grid, gridData);
});
How I arrived on this solution?
Read comments here. https://github.com/mleibman/SlickGrid/issues/325
dataView.fastSort does the job. You can then use setSortColumn to set the sorting glyph.
I have multiple column sort enabled, I had to change the function to pass the correct sort column.
grid.onSort.subscribe(function(e, args) {
gridSorter(**args.sortCols[0].sortCol.field**, **args.sortCols[0].sortAsc**, grid, gridData);
});
You can trigger click event on the column header...which does sorting
I fixed the issue like this...
$('.slick-header-columns').children().eq(0).trigger('click'); // for first column
I was inspired by Mr.Hunts answer but I took a slightly different approach to extend the current grid.setSortColumn(columnId, isAsc) to grid.setInitialSortColumn(columnId, isAsc). This will apply the sort and do everything grid.setSortColumn does.
var thisGrid = { //Your grid obj
columns: , // Your columns object
grid: , // new Slick.Grid....
}
thisGrid.grid.onSort.subscribe(function (e, args) { // ar var cols = args.sortCols;]
thisGrid.grid.customSort(args);
});
thisGrid.grid.customSort = function (args) {
var cols = args.sortCols;
thisGrid.dataView.sort(function (dataRow1, dataRow2) {
if (cols) {
for (var i = 0, l = cols.length; i < l; i++) {
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field],
value2 = dataRow2[field];
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result != 0) {
return result;
}
}
}
return 0;
});
}
thisGrid.grid.setInitialSortColumn = function (columnId, ascending) {
thisGrid.grid.setInitialSortColumns([{
columnId: columnId,
sortAsc: ascending
}
]);
};
thisGrid.grid.setInitialSortColumns = function (cols) {
sortColumns = cols;
$.each(sortColumns, function (i, col) {
var columnIndex = thisGrid.grid.getColumnIndex(col.columnId);
var column = thisGrid.columns[columnIndex];
if (col.sortAsc == null) {
col.sortAsc = true;
}
var args = {
grid: thisGrid.grid,
multiColumnSort: true,
sortCols: [{
sortCol: column,
sortAsc: col.sortAsc
}
]
}
thisGrid.grid.setSortColumn(col.columnId, col.sortAsc);
thisGrid.grid.customSort(args);
});
};
// Trigger
thisGrid.grid.setInitialSortColumn("dateDue", true);
I can't leave comments due to reputation, which is where this would be most appropriate, however, my answer is in regard to #Premshankar Tiwari and #Siddharth answers.
I preferred the dataView.fastSort option in Siddharth's answer, which works for me in all browsers except IE7 and 8. I didn't test it in IE9 or above. Unfortunately, most on my network run IE7 or 8 due to compatibility issues for legacy applications. BUT, Premshankar's answer works in IE7 and 8.
So, I ended up doing something like this:
if (msie > 0) {
$(".slick-header-columns").children().eq(5).trigger("click");
$(".slick-header-columns").children().eq(4).trigger("click");
} else {
dataView.fastSort('process','unit');
}
where column index (5) = 'unit' and column index (4) = 'process'. Notice that is the reverse order in dataView.fastSort method. I am also using a function that detects IE browser version and assigns it to msie.
My only complaint about utilizing the .trigger method is that if you set up your grid to dynamically hide/show columns, the indexed feature would potentially sort on unintended columns unless you are only calling it on initialization when hide/show capabilities are present.
Maybe it will help you. Looks like SlickGrid is triggering sort to self - so You can trigger it manually if You want.
I'm using multicolumn sorting, and loading saved sort data when initialising the grid.
As expected, setSortColumns set the sorting, but didnt actually apply it, and dataView.reSort() or .fastSort() didnt seem to help, regardless of what point in loading I called them
(I must have missed something, but just couldnt get it to work).
In the end, this worked for me. I call it immediately after populating my dataView from an ajax call.
Its probably not the slickest, so happy to take feedback on board!
function forceResort() {
var sortColumns = grid.getSortColumns();
var cols = [];
$.each(sortColumns, function(index, value) {
var columnId = value.columnId;
var sortAsc = value.sortAsc;
var sortCol = { field: columnId };
var col = { sortCol: sortCol, sortAsc : sortAsc};
cols.push(col);
});
dataView.sort(function (dataRow1, dataRow2) {
var sortResult = 0;
for (var i = 0, l = cols.length; i < l; i++) {
if (sortResult !== 0) {
break;
}
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field] || ''; //handle nulls - otherwise erratic sorting
var value2 = dataRow2[field] || ''; //handle nulls - otherwise erratic sorting
if ($.inArray(field, dateTypeColumns) > -1) {
sortResult = compareDates(value1, value2) * sign;
} else {
if ($.inArray(field, numericColumns) > -1) {
sortResult = compareSimple(value1, value2) * sign;
} else {
sortResult = compareAlphaNumeric(value1, value2) * sign;
}
}
}
return sortResult;
});
grid.invalidate();
grid.render();
}
A more clean solution is not to rely on the arguments to onSort but call getSortColumns instead:
function gridSorter() {
var scol=grid.getSortColumns();
if (scol.length===0) return;
var scolId=scol[0].columnId, asc=scol[0].sortAsc;
data.sort(function(a, b) {
var result = a[scolId] > b[scolId] ? 1 : a[scolId] < b[scolId] ? -1 : 0;
return asc ? result : -result;
});
grid.invalidate();
}
Then do:
grid.onSort.subscribe(gridSorter);
This will allow to reestablish sorting anytime you want (from example after reloading the data with ajax) simply by calling gridSorter()
If you want multiple column sorting:
function grid_sorter(args, grid, dataView) {
let cols = args.sortCols;
console.log(cols)
dataView.sort(function (dataRow1, dataRow2) {
for (let i = 0, l = cols.length; i < l; i++) {
let field = cols[i].sortCol.field;
let sign = cols[i].sortAsc ? 1 : -1;
let value1 = dataRow1[field], value2 = dataRow2[field];
let result = (value1 === value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result !== 0) {
return result;
}
}
return 0;
});
grid.invalidate();
grid.render();
}
grid_sorter(default_sorting, grid_2, dataView_2);
cols is an object like this:
- sortCols {
- length: 2
- 0 : {
"sortAsc: true,
"sortCol": {
"field: column_id
}
}
- 1: {..}
}

'JSON' is undefined error in IE only

I'm making an AJAX call to a WCF service and when I pass in my data i use JSON.stringify()
The call returns and works fine in FF, & Chrome, but not IE8. I get an error: 'JSON' is undefined
suggestions?
p.s. I also want this to work in IE7
Use json2 for a consistent cross browser implementation.
https://github.com/douglascrockford/JSON-js
I had the issue with IE9. IE9 was rendering my page in "quirks" mode, the solution was simply to add <!DOCTYPE html>. This took me out of "quirks" mode which I'm sure fixed more than just this issue!
Update
Check the JSON3 library. It works like a charm.
Changes from JSON2
I hope this helps.
Hope this helps. I got this from a few online sources long back. don't have their links. Sorry that i'm unable to cite references.
var JSON = JSON || {};
// implement JSON.stringify serialization
JSON.stringify = JSON.stringify || function(obj) {
var t = typeof (obj);
if (t != "object" || obj === null) {
// simple data type
if (t == "string")
obj = '"' + obj + '"';
return String(obj);
} else {
// recurse array or object
var n, v, json = [], arr = (obj && obj.constructor == Array);
for (n in obj) {
v = obj[n];
t = typeof (v);
if (t == "string")
v = '"' + v + '"';
else if (t == "object" && v !== null)
v = JSON.stringify(v);
json.push((arr ? "" : '"' + n + '":') + String(v));
}
return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
}
};
// implement JSON.parse de-serialization
JSON.parse = JSON.parse || function() {
var r = "(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)", k = '(?:[^\\0-\\x08\\x0a-\\x1f"\\\\]|\\\\(?:["/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';
k = '(?:"' + k + '*")';
var s = new RegExp(
"(?:false|true|null|[\\{\\}\\[\\]]|" + r + "|" + k + ")", "g"), t = new RegExp(
"\\\\(?:([^u])|u(.{4}))", "g"), u = {
'"' : '"',
"/" : "/",
"\\" : "\\",
b : "\u0008",
f : "\u000c",
n : "\n",
r : "\r",
t : "\t"
};
function v(h, j, e) {
return j ? u[j] : String.fromCharCode(parseInt(e, 16));
}
var w = new String(""), x = Object.hasOwnProperty;
return function(h, j) {
h = h.match(s);
var e, c = h[0], l = false;
if ("{" === c)
e = {};
else if ("[" === c)
e = [];
else {
e = [];
l = true;
}
for ( var b, d = [ e ], m = 1 - l, y = h.length; m = 0;)
delete f[i[g]];
}
return j.call(n, o, f);
};
e = p({
"" : e
}, "");
}
return e;
};
}();
To make your function works better in IE import JSON2 parser code in your file, as IE by default does not support JSON.Stringify().
It can be found here
In IE open the compatibility view settings and remove the localhost from the listbox for "Websites you have added to Compatibility View".
It worked for me.
JQuery 2.x is no longer compatible with IE 6-8. JQuery 2.0 beta 2 release notes
I know the main question is in regard to older versions of JQuery, but this was causing the error for me. I installed JQuery 1.x, which is API-compatible with JQuery 2.x, and added the following detection code:
<!--[if lt IE 9]>
<script src="js/jquery-1.11.1.min.js"></script>
<![endif]-->
<!--[if gte IE 9]>
<script src="js/jquery.min.js"></script>
<![endif]-->

Resources