Jquery Datatables render multiple functions - javascript

I am using the datatables plugin for jQuery however I am having issues with the render function:
I have a string that contains some html elements in a column, I do not want the html elements to render in the table so I use the function $.fn.dataTable.render.text()
I also only want this data to be a preview as the string can be incredibly long therefore I am using an ellipsis function $.fn.dataTable.render.ellipsis(40)
The ellipsis function is defined here:
// https://datatables.net/manual/data/renderers#Text-helper
$.fn.dataTable.render.ellipsis = function (cutoff) {
return function (data, type, row) {
if (type === 'display') {
var str = data.toString(); // cast numbers
return str.length < cutoff ?
str :
str.substr(0, cutoff - 1) + '…';
}
// Search, order and type can use the original data
return data;
};
};
Would it be possible to combine these functions in any way?
The closest solution to my problem is this found on the datatables forum.
This is exactly what I want to do however it does not work as d = renderArray[r](d, type, row, meta); is not a function.
Thanks in advance.
Edit:

The mRender function is passed the data for the whole row. So, you can access any property you want to access render multiple function using datatables
{
mData: "bar",
mRender: function(data, type, val) {
switch (type) {
case 'display':
return '' + data.bar + '';
break;
// optionally, add case statements for 'sort', 'filter', and 'type'
default:
return data.bar;
break;
}
}
}

Related

Slice function in .csv

I have a .csv file that I am pulling into d3 and transforming to work for my assignment. I have one column that has the elements as percentages "xx.x%". I would like to remove the percentage sign, so that I am left with just "xx.x" for each element in that column. I know the slice() function needs to be used, and that I will be taking the values from 1 - length-2, but I'm not sure how to write the function. I'll include the other cleanup code so that you can get a feel for the file I'm working with. Thank you!!
function cleanup(raw_data) {
// remove unneeded columns
var data = [];
raw_data.forEach(function(obj){
if (obj["County"] == "Dutchess" && obj["Month"] == 12)
data.push(obj)
});
data.forEach(function(obj) {
delete obj["2012 Census Population"];
delete obj["Population 18+ Estimate"];
delete obj["OPO"];
delete obj["Location"];
delete obj["Month"];
delete obj["County"];
delete obj["Chart Month"];
});
data.sort(function (a,b) {
return a["Year"] > b["Year"];
});
return data;
}
Have you tried:
data.forEach(function(obj) {
obj["yourCol"] = obj["yourCol"].slice(0, -1);
});

tablesorter.js multiple textExtraction

Using tablesorter.js to sort table columns.
I have one column with images, so I used textExtraction to get image alt value to do sorting.
Now I want to use textExtraction to sort other columns with commas and currency symbols.
Independently, both will work but I am not able to get both of them working.
Tablesorter has an example that I am not able to adapt.
textExtraction: {
0: function(node, table, cellIndex){ return $(node).find("strong").text(); },
1: function(node, table, cellIndex){ return $(node).find("div").text(); },
2: function(node, table, cellIndex){ return $(node).find("span").text(); },
3: function(node, table, cellIndex){ return $(node).find("em").text(); },
4: function(node, table, cellIndex){ return $(node).find("a").text(); },
'.date' : function(node, table, cellIndex){ return $(node).find("u").text(); }
}
I modified my code as follows:
$(document).ready(function($){
$("#cardSort").tablesorter(
{
initWidgets: true,
textExtraction: {
0: function(s){
if($(s).find('img').length == 0) return $(s).text();
return $(s).find('img').attr('alt');
},
1: function(s){
return $(s).text().replace(/[,$£€]/g,'');
}
}
}
);
}
);
This appears to be same as the tablesorter example eg it is using the numbered function method. But in this format neither work.
Any ideas on how to have both textExtraction functions?
Edit to add: this is TableSorter Version 2.0.5b
It sounds like you might still be using the original version of tablesorter (v2.0.5)... setting the textExtraction as an object doesn't work on that version, you'll need to use my fork of tablesorter.
Update: If you must use v2.0.5, then try the following:
textExtraction: function(node) {
var $cell = $(node),
text = $cell.text();
switch(node.cellIndex) {
case 0:
return $cell.find('img').length ? $cell.find('img').attr('alt') : text;
case 1:
return text.replace(/[,$£€]/g,'');
default:
return text;
}
}
Note: This method won't work as expected when there are colspans within the tbody.

DataTables custom detection plug-in and sorting order

i'm trying to implement a function on Datatables that has to look up the table data, do a regex and then, if it returns true, then, when i click on the header to sort data, it will sort it by the last 5 digits, ignoring the letters that comes up in the beginning of the string.
i have the following code
$.fn.dataTable.ext.oSort['custom'] = function (settings, col) {
return this.api().column(col, {order: 'index'}).nodes().map(function (td, i) {
var string= $(td).html();
return $.trim(string.substr(string.length - 4));
});
}
$.fn.dataTable.ext.type.detect.push(
function (value) {
var test = (/PT\d/).test(value);
return test ? 'custom' : null;
}
);
this is for a custom data that has lots of trash in the beggining, like country code and stuff, but the data order is only by the last 5 digits.
i've been searching all over i'm having a hard time to understand and debug. Debuguing the detect works, if 1 put an alert, it gives-me true when it hits the colum with the values i want, but the custom sorting doesn't work, can anybody help?
hope i'm clear about it
thanks
actualy i solved it myself.
the problem was that DataTables needs to make the entire column return true, so, if the regex fails in any value in the same column it fails.
$.fn.dataTable.ext.type.detect.unshift(
function (d) {
var pt = (/^PT\d/).test(d);
var es= (/^ES\d/).test(d);
var en= (/^EN\d/).test(d);
if (pt || es|| en) {
return 'custom'
} else {
return false;
}
}
);
$.fn.dataTable.ext.type.order['custom-pre'] = function (string) {
return $.trim(string.substr(string.length - 4));
};
so this is my last code used and it works just fine.
i'm posting it so anybody with the same problem can have a clue to solve some future problem :)

Backbone.js collection comparator sort by multiple fields?

this.col = Backbone.Collection.extend({
model: M,
comparator: function(item) {
return item.get("level");
}
});
This above code sorts items by level. I want to sort by level, then by title. Can I do that? Thanks.
#amchang87's answer definitely works, but another that I found worked is simply returning an array of the sortable fields:
this.col = Backbone.Collection.extend({
model: M,
comparator: function(item) {
return [item.get("level"), item.get("title")]
}
});
I haven't tested this in multiple browsers yet as I think it relies on JS' behavior in sort order for arrays (based on their contents). It definitely works in WebKit.
String concatenation works fine when sorting multiple fields in ascending order, but it didn't work for me because 1) I had to support asc/desc per field and 2) certain fields were number field (i.e., I want 10 to come after 2 if it is ascending). So, below was a comparator function I used and worked OK for my needs. It assumes the backbone collection has a variable assigned with 'sortConfig', which is an array of JSON objects with field name and sort order direction. For example,
{
"sort" : [
{
"field": "strField",
"order": "asc"
},
{
"field": "numField",
"order": "desc"
},
...
]
}
With the JSON object above assigned as 'sortConfig' to the collection, the function below will make Backbone sort by strField in ascending order first, then sort by numField in descending order, etc. If no sort order is specified, it sorts ascending by default.
multiFieldComparator: function(one, another) {
// 'this' here is Backbone Collection
if (this.sortConfig) {
for (var i = 0; i < this.sortConfig.length; i++) {
if (one.get(this.sortConfig[i].field) > another.get(this.sortConfig[i].field)) {
return ("desc" != this.sortConfig[i].order) ? 1 : -1;
} else if (one.get(this.sortConfig[i].field) == another.get(this.sortConfig[i].field)) {
// do nothing but let the loop move further for next layer comparison
} else {
return ("desc" != this.sortConfig[i].order) ? -1 : 1;
}
}
}
// if we exited out of loop without prematurely returning, the 2 items being
// compared are identical in terms of sortConfig, so return 0
// Or, if it didn't get into the if block due to no 'sortConfig', return 0
// and let the original order not change.
return 0;
}
Returning an array is not consistent if you need to sort descending and some ascending...
I created a small set of functions which can be used to return the relevant comparison integer back to Backbone Comparator function:
backbone-collection-multisort
The main thing is that Backbone sorts by a single relative value of one item to another. So it's not directly possible to sort twice in a single collection but I'd try this.
this.col = Backbone.Collection.extend({
model: M,
comparator: function(item) {
// make sure this returns a string!
return item.get("level") + item.get("title");
}
});
What this will do is return a string of like "1Cool", "1title", "2newTitle" ...
Javascript should sort the strings by the numerical character first then each character afterwards. But this will only work as long as your levels have the same amount of digits. IE "001title" vs "200title". The main idea though is that you need to produce two comparable objects, line a number or string, that can be compared to each other based on one criteria.
Other solution would be to use underscore to "groupby" your level then use "sortby" to manually sort each level group then manually replace the underlying collection with this newly created array. You can probably setup a function to do this whenever the collection "changes".
"inspired" in hyong answer.
This also allows you to change the data before compare it, valueTransforms is an object, if there is an attribute in that object that has a function, it will be used.
/*
* #param {Object} sortOrders ie:
* {
* "description": "asc",
* "duedate": "desc",
* }
* #param {Object} valueTransforms
*/
setMultiFieldComparator: function(sortOrders, valueTransforms) {
var newSortOrders = {}, added = 0;
_.each(sortOrders, function(sortOrder, sortField) {
if (["asc", "desc"].indexOf(sortOrder) !== -1) {
newSortOrders[sortField] = sortOrder;
added += 1;
}
});
if (added) {
this.comparator = this._multiFieldComparator
.bind(this, newSortOrders, valueTransforms || this.model.prototype.valueTransforms || {});
} else {
this.comparator = null;
}
},
_multiFieldComparator: function(sortOrders, valueTransforms, one, another) {
var retVal = 0;
if (sortOrders) {
_.every(sortOrders, function(sortOrder, sortField) {
var oneValue = one.get(sortField),
anotherValue = another.get(sortField);
if (valueTransforms[sortField] instanceof Function) {
oneValue = valueTransforms[sortField](oneValue);
anotherValue = valueTransforms[sortField](anotherValue);
}
if (oneValue > anotherValue) {
retVal = ("desc" !== sortOrder) ? 1 : -1;
} else if (oneValue < anotherValue) {
retVal = ("desc" !== sortOrder) ? -1 : 1;
} else {
//continue
return true;
}
});
}
return retVal;
},

Bring selected rows to the top from the Jqgrid

I am using jqgrid in 'multiselect' mode and without pagination. When the user selects individual records by using mouse click, is there any way that I can bring those selected records to the top of the grid?
Thanks in advance for your help.
After small discussion with you in comments I could reformulate your question so: "how one can implement sorting by multiselect column?"
The question find is very interesting so I invested some time and could suggest a solution in case of jqGrid which hold local data (datatype which is not 'xml' or 'json' or which has 'loadonce: true' option).
First of all the working demo which demonstrate my suggestion you can find here:
The implementation consist from two parts:
Making selection as part of local data. As the bonus of the selection will be hold during paging of local data. This feature is interesting independent on the sorting by multiselect column.
The implementation of sorting by multiselect column.
To implement of holding selection I suggest to extend local data parameter, which hold local data with the new boolean property cb (exactly the same name like the name of the multiselect column). Below you find the implementation:
multiselect: true,
onSelectRow: function (id) {
var p = this.p, item = p.data[p._index[id]];
if (typeof (item.cb) === "undefined") {
item.cb = true;
} else {
item.cb = !item.cb;
}
},
loadComplete: function () {
var p = this.p, data = p.data, item, $this = $(this), index = p._index, rowid;
for (rowid in index) {
if (index.hasOwnProperty(rowid)) {
item = data[index[rowid]];
if (typeof (item.cb) === "boolean" && item.cb) {
$this.jqGrid('setSelection', rowid, false);
}
}
}
}
To make 'cb' column (multiselect column) sortable I suggest to do following:
var $grid = $("#list");
// ... create the grid
$("#cb_" + $grid[0].id).hide();
$("#jqgh_" + $grid[0].id + "_cb").addClass("ui-jqgrid-sortable");
cbColModel = $grid.jqGrid('getColProp', 'cb');
cbColModel.sortable = true;
cbColModel.sorttype = function (value, item) {
return typeof (item.cb) === "boolean" && item.cb ? 1 : 0;
};
UPDATED: The demo contain a little improved code based on the same idea.
If you have the IDs of the row(s) you can do a special sort on server side by using following command for e.g. MySQL:
Select a,b,c
FROM t
ORDER BY FIND_IN_SET(yourColumnName, "5,10,44,29") DESC
or
ORDER BY FIELD(yourColumnName, "5") DESC

Categories