Tablesorter value should always be visible when choosing a filter - tablesorter

I am currently using table sorter and just want to know if there is a way to have a value by default always shows up regardless of the selected filter from the filter-select list. I tried using filter functions, but after I added a filter function for a column that has a filter-select, it loses the filter-select list with all of the available values.
For example, here is the filter function that I tried using, it should show "John" regardless of the values that are selected:
0 : function(e, n, f, i, $r, c, data) {
var x = e===f;
var y = e==='John';
var show = x|y;
return show;
},
Am I missing something?

In javascript, the OR operator requires two vertical bars:
0 : function(e, n, f, i, $r, c, data) {
var x = e===f;
var y = e==='John';
var show = x || y;
return show;
},
Maybe a better method would be to use the filter_defaultFilter option which can be used as follows (demo):
$(function() {
$('table').tablesorter({
theme: 'blue',
widgets: ['zebra', 'filter'],
widgetOptions: {
filter_defaultFilter: {
// Ox will always show
// {q} is replaced by the user query
2: '{q}|Ox'
}
}
});
});
Also, make sure to include a "filter-match" class name in the header cell:
<th class="filter-match">...</th>
otherwise "OR" queries default to exact cell content matches.

Related

Data attribute for (Mottie) Tablesorter filter_selectSource

I have a dynamic table which can contain a status column that can contain a predefined list of status, for example:
0: closed
1: Open
2: Pending
3: ...
The status label is displayed in the table, but the id number is used for actual filtering. I successfully applied tablesorter filter-select to display a select filter, but it either display label (won't filter) or id (not pretty).
I could fix this using filter_selectSource inside javascript, but since my table is dynamic and displayed using Handlebar, I'm looking for an html solution using data attributes.
Is there a data attribute that could be used to set the filter select label/value, similar to how data-text can be used to define unparsed text? Or is there a way to define a custom parser for filter that would return a label/value combo as an array for example?
Based on Mottie reply and tablesorter.filter.getOptions source, I came up with this. Adding the filter-metaselect class to my column(s) th enables the data-value attribute in the cell td to be used as the select options. The parsed/unparsed text can still be used. Note that the child part of getOptions has been omitted since I'm not using feature at the moment.
Table Cell :
<td data-value="1">
Projet actif
</td>
Select option :
<option value="1" parsed="projet actif" data-function-name="1">Projet actif</option>
Javascript:
filter_selectSource: {
".filter-metaselect": function (table, column, onlyAvail) {
table = $( table )[0];
var rowIndex, tbodyIndex, len, row, cache, indx, child, childLen, colData,
c = table.config,
wo = c.widgetOptions,
arry = [];
for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
cache = c.cache[tbodyIndex];
len = c.cache[tbodyIndex].normalized.length;
// loop through the rows
for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
// get cached row from cache.row ( old ) or row data object
// ( new; last item in normalized array )
row = cache.row ?
cache.row[ rowIndex ] :
cache.normalized[ rowIndex ][ c.columns ].$row[0];
// check if has class filtered
if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
continue;
}
// Get the column data attributes
if (row.getElementsByTagName('td')[column].getAttribute('data-value')) {
colData = row.getElementsByTagName('td')[column].getAttribute('data-value');
} else {
colData = false;
}
// get non-normalized cell content
if ( wo.filter_useParsedData ||
c.parsers[column].parsed ||
c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
arry[ arry.length ] = {
value : (colData) ? colData : cache.normalized[ rowIndex ][ column ],
text : cache.normalized[ rowIndex ][ column ]
};
// child row parsed data
/* TODO */
} else {
arry[ arry.length ] = {
value : (colData) ? colData : cache.normalized[ rowIndex ][ c.columns ].raw[ column ],
text : cache.normalized[ rowIndex ][ c.columns ].raw[ column ]
};
// child row unparsed data
/* TODO */
}
}
}
// Remove duplicates in `arry` since using an array of objects
// won't do it automatically
var arr = {};
for ( var i=0, len=arry.length; i < len; i++ )
arr[arry[i]['text']] = arry[i];
arry = new Array();
for ( var key in arr )
arry.push(arr[key]);
return arry;
}
}
The filter_selectSource documentation has an example where this widget option calls the filter.getOptions which returns an array of cell text or parsed values (based on the filter parser setting); if that doesn't return the values you want, grab the values yourself and return an array in that function.
Here is a basic example of how to use it: http://jsfiddle.net/Mottie/856bzzeL/117/ (related to Is there a way in tablesorter to filter to select only rows where the field is empty?)
$(function(){
$('table').tablesorter({
theme: 'blue',
widgets: ['zebra', 'filter'],
widgetOptions: {
filter_functions: {
0: {
'{empty}' : function (e, n, f, i, $r, c) {
return $.trim(e) === '';
}
}
},
filter_selectSource: {
0: function (table, column, onlyAvail) {
// get an array of all table cell contents for a table column
var array = $.tablesorter.filter.getOptions(table, column, onlyAvail);
// manipulate the array as desired, then return it
array.push('{empty}');
return array;
}
}
}
});
});

Highcharts error 14 in chart from HTML table

I'm using the highcharts data module to build a chart from an html table. In the data configuration of the chart I just have:
data: {
table: table
}
But if I have string values such as "null", "NA", or even comma separators in the HTML table I get highcharts error 14, 'string value passed to chart...'
What I've tried:
Since HC should be able to handle null values I replaced NA will null in the tables. I also tried just leaving the blanks "" blank. But the issue is with the thousand separators. So I added thousandsSep: ',' hoping the chart output would understand that commas are part of the display but that doesn't work.
My next thought was to use a formatter function:
data: {
table: function(){...change strings to float etc}
}
None of my attempts at the latter seem to work as I can't figure out what the data object looks like when accessed from a table. Any advice would be appreciated.
A solution that seems to have fixed the issue was to add a "parsed" function here is the api reference: http://api.highcharts.com/highcharts/data.parsed
I added the following to the data property:
data: {
table: 'datatable',
parsed: function()
{
var chartData = this.columns;
var nData = [];
for(var a in chartData)
{
var tempArray = [];
for(var e in chartData[a])
{
var v = chartData[a][e].replace(/\,/g,"").replace("NA","0");
/\d/g.test(v) == true ? v = parseFloat(v) : v = v;
tempArray.push(v);
}
nData.push(tempArray);
}
this.columns = nData;
//alert(JSON.stringify(nData));
//this.columns = [];
//this.columns.push(nData[0]);
//this.columns.push(nData[1]);
}
},
...etc

How to pass a function to angular ui-grid column total

I'm using angular ui-grid (no ng-grid) and want to pass a function to calculate a column's total value. In the documentation they explicitly say it is possible; it is just that I canĀ“t find how to do it.
This is how I'm showing a total (sum) for another columns:
aggregationType: uiGridConstants.aggregationTypes.sum,
aggregationHideLabel: true,
footerCellFilter: 'currencyFilter',
footerCellClass: 'ui-grid-centerCell'
Now, instead of using uiGridConstants.aggregationTypes.sum, I want to pass a function to calculate the value.
Many thanks and bye ...
My Idea is to Create a method in your Controller like
$scope.sum = function(row){
var sum1 = row.entity.sum1 + row.entity.sum2;
console.log('Sum of Value is = ',sum1);
}
Note : sum1 and sum2 is columnDefs of Field value like
$scope.gridsOptions = {
columnDefs : [
{
field : 'sum1',
name :'xx'
},
{
field : 'sum2',
name : 'xxx'
}
]}
You can also solve this by adding custom tree aggregation.
treeCustomAggregations: {
sum: {
aggregationFn: stats.aggregator.sumSquareErr, finalizerFn: function (aggregation) {
//Do rest of your calculations here
var total = $scope.gridApi.grid.columns[column_number].getAggregationValue() ;
aggregation.value = total ;
aggregation.rendered = (aggregation.value).toFixed(1);
}
Or you can refer this question for custom aggregate template and calling your custom function from it.

How do you set the tablesorter default filter type

I have a tablesorter table with titles in the cells. I'd like to be able to search on multiple, non-contiguous words in the title. The fuzzy match (~) does the job. How do I get this to be the default matcher? I don't want my users to have learn/remember it.
I tried a custom filter like this
....
widgetOptions: {
filter_external: '.search', // input box that user input goes into
filter_columnFilters: false,
filter_functions : {
1: function (e, n, f, i, $r) {
return this.filter.types.fuzzy( e, '~' + n, f, i, $r);
}
}
}
.....
but that didn't work. Ideas?
I just added a new filter widget option filter_defaultFilter in the working branch of the GitHub repository
To use it, include the column class name or index and a filter mask with the filter selector (~ in your case) and a query tag ({query} or {q}).
$(function () {
$('table').tablesorter({
theme: 'blue',
widgets: ['zebra', 'filter'],
widgetOptions: {
filter_defaultFilter: {
// set default fuzzy match on first column
0 : '~{q}'
}
}
});
});
Here is a demo applying a default exact match to filter selects for issue #704.
The documentation is available now in the working branch. The main documentation won't be updated until this weekend.

Two related questions on jqGrid column header filters and the advanced filtering dialog

In developing my first ASP.NET MVC 3 app using the jqGrid to display some data, I'm using the column header filters and also allowing for the advanced filter toolbar filtering to be done. Independently these things work pretty well.
First question - Has anyone a solution for communicating the current column header filter settings to the advanced filters?
As an example, a user can filter on the "Ice Cream Name" column, entering a partial name, e.g., "Chocolate", and it'll filter down to "Chocolate Explosion", "Dark Chocolate", etc. - great. What would be nice would be to open the advanced filter and have that "contains 'Chocolate'" column filter automatically populated in the advanced filter. I recognize that the other direction (where someone could AND or OR two values for the same column, e.g. 'Chocolate' OR 'Caramel') becomes problematic but in the other direction, it seems like it might be possible. Perhaps this is just a setting of the grid I'm missing. Anyone solved this?
Second question - I currently can do some filtering with the column header filters, show some result set in the grid and then go into the advanced filter dialog and set up a different filter. That will display the correct results but the column header filters are not cleared, giving the impression that the filtering is not working. How can I reset those column header filters after the use clicks the "Find" button on the dialog?
I find your question very interesting, so I prepared the demo which demonstrate how one can combine Advanced Searching dialog and Toolbar Searching in one grid.
One important, but simple trick is the usage of recreateFilter: true. Per default the searching dialog will be created once and then will be only hide or show. As the result the postData.filters parameter will be not refreshed. After setting recreateFilter: true the problem with filling of the advanced searching dialog with the values from the searching toolbar will be solved. I personally set the default searching options as the following
$.extend(
$.jgrid.search,
{
multipleSearch: true,
multipleGroup: true,
recreateFilter: true,
overlay: 0
}
);
Now to more complex part of the solution is the function refreshSerchingToolbar which I wrote. The function is not so simple, but it's simply in use:
loadComplete: function () {
refreshSerchingToolbar($(this), 'cn');
}
The last parameter is the same parameter which you used as defaultSearch property of the searching toolbar method filterToolbar (the default value is 'bw', but I personally prefer to use 'cn' and set jqGrid parameter ignoreCase: true).
If you fill the advanced searching dialog of the demo with the following field
and click the "Find" button, you will have the following grid:
(I marked the 'Total' column as non-searchable with respect of search: false to show only that all works correctly in the case also)
One can see that all fields of the searching toolbar excepting "Amount" are filled with the values from the searching dialog. The field are not filled because we used "grater or equal" operation instead of "equal". The function refreshSerchingToolbar fills only the elements of the searching toolbar which can be produced by the
Just as a reminder I should mention that in case of the usage of Filter Toolbar it is very important to define searchoptions.sopt options of the colModel. For all non-string column contains (dates, numbers, selects, int, currency) it is extremely important to have 'eq' as the first element of the sopt array. See here and here for details.
If you change the filter of the Advanced Dialog to the following
you will have as expected
At the end I include the code of the refreshSerchingToolbar function:
var getColumnIndex = function (grid, columnIndex) {
var cm = grid.jqGrid('getGridParam', 'colModel'), i = 0, l = cm.length;
for (; i < l; i += 1) {
if ((cm[i].index || cm[i].name) === columnIndex) {
return i; // return the colModel index
}
}
return -1;
},
refreshSerchingToolbar = function ($grid, myDefaultSearch) {
var postData = $grid.jqGrid('getGridParam', 'postData'), filters, i, l,
rules, rule, iCol, cm = $grid.jqGrid('getGridParam', 'colModel'),
cmi, control, tagName;
for (i = 0, l = cm.length; i < l; i += 1) {
control = $("#gs_" + $.jgrid.jqID(cm[i].name));
if (control.length > 0) {
tagName = control[0].tagName.toUpperCase();
if (tagName === "SELECT") { // && cmi.stype === "select"
control.find("option[value='']")
.attr('selected', 'selected');
} else if (tagName === "INPUT") {
control.val('');
}
}
}
if (typeof (postData.filters) === "string" &&
typeof ($grid[0].ftoolbar) === "boolean" && $grid[0].ftoolbar) {
filters = $.parseJSON(postData.filters);
if (filters && filters.groupOp === "AND" && typeof (filters.groups) === "undefined") {
// only in case of advance searching without grouping we import filters in the
// searching toolbar
rules = filters.rules;
for (i = 0, l = rules.length; i < l; i += 1) {
rule = rules[i];
iCol = getColumnIndex($grid, rule.field);
cmi = cm[iCol];
control = $("#gs_" + $.jgrid.jqID(cmi.name));
if (iCol >= 0 && control.length > 0) {
tagName = control[0].tagName.toUpperCase();
if (((typeof (cmi.searchoptions) === "undefined" ||
typeof (cmi.searchoptions.sopt) === "undefined")
&& rule.op === myDefaultSearch) ||
(typeof (cmi.searchoptions) === "object" &&
$.isArray(cmi.searchoptions.sopt) &&
cmi.searchoptions.sopt[0] === rule.op)) {
if (tagName === "SELECT") { // && cmi.stype === "select"
control.find("option[value='" + $.jgrid.jqID(rule.data) + "']")
.attr('selected', 'selected');
} else if (tagName === "INPUT") {
control.val(rule.data);
}
}
}
}
}
}
};
UPDATED: The above code is no more needed in case of usage free jqGrid 4.13.1 or higher. It contains the new default option loadFilterDefaults: true of the filterToolbar, which refreshes the values of the filter toolbar and the filter operations (if searchOperators: true option of filterToolbar is ised) if postData.filters and search: true are set (the filter is applied). Free jqGrid refreshes the filter toolbar on jqGridAfterLoadComplete (if loadFilterDefaults: true are set) or if the event jqGridRefreshFilterValues are explicitly triggered.
I know it's an old post - but if you have multiple grids on the same page the above code can add the filter text to the wrong grid.
Changing this in the first loop in refreshSearchingToolbar, from
control = $("#gs_" + $.jgrid.jqID(cm[i].name));
to
control = $("#gview_"+$grid.attr('id')+" #gs_" + $.jgrid.jqID(cm[i].name));
and this in the second loop from
control = $("#gs_" + $.jgrid.jqID(cmi.name));
to
control = $("#gview_"+$grid.attr('id')+" #gs_" + $.jgrid.jqID(cmi.name));
should do the trick.
Kudos to Oleg

Resources