Fixed values on sorted column with formatted dates - datatables

I have a table initialised by
document.addEventListener("DOMContentLoaded", function(){
$.fn.dataTable.moment( 'DD MMM Y' );
})
The problem is that my column has both dates and text (only one type of text), i.e. 'ongoing'. The dates have this format: 30 Oct 2020, and I am able to order it correctly thanks to the addition of the $.fn.dataTable.moment( 'DD MMM Y' ); line. If there's only one instance of 'ongoing' among the data, though, the ordering gets messed up and doesn't work. How can I add an exception to the ordering?
I'm looking for something like
"order": [[ 2, "asc" ]], "exception": ["ongoing"]
(very pseudo-code).
Update
I've learned about the absoluteOrder plugin and have implemented like so:
var deadlineType = $.fn.dataTable.absoluteOrder( [
{ value: 'ongoing', position: 'top' }
] );
"columnDefs": [ {
[...]
{ "targets": 2, type: deadlineType } ]
})
It almost works. It puts the 'ongoing' on top. Nevertheless, the data sorting is messed up again, even when using absoluteOrderNumber. Is there an absoluteOrder line specific for dates?

Thanks to kthorngren on the datatables forum I have solved this problem.
This is the working code:
{
"targets": 2,
"render": function (data, type, row) {
if ( type === 'sort' ) {
if (data === 'ongoing') {
return '01 Jan 0001';
}
return data;
}
return data;
}
}

Related

Datatables column.render

I am using datatables and would like to over-ride the contents of a cell depending on the value it contains. I am using '1' to flag true in the underlying database and '0' for false. I am attempting to use the Columndefs render function to do this.
Here is my code..
xample_table = $('#treatment_list').DataTable(
{
select: true,
destroy: true,
"order": [ 0, 'desc' ],
data:json,
columns : [
{'data':'treatment_name'},
{'data':'description'},
{'data':'measured_in'},
{'data':'exclusive'}
],
"columnDefs": [
{
"targets":3,
"data" : "exclusive",
"render": function ( data, type, row ) {
if (type === 'display'){
if (row.exclusive == '0')
{
return 'No';
}
else
return 'Yes';
}
}
}
]
}
);
The problem is I get an erro message from datatables that reads..
DataTables warning: table id=treatment_list - Requested unknown parameter 'exclusive' for row 0, column 3....
Apart from the error message, it is in fact working.
thanks for the advice,but the json was fine and the other variables did not reveal much as I had console logged them before posting here. I did find a solution and am posting it here in case it helps anyone else. This expression works :
"columnDefs": [
{
"render": function ( data, type, row ) {
if (data =='1') {
return "True" ;
}
else{
return "False" ;
}
},
"targets": [3]
}
]
In all of the examples I have found, they often included the name of the column being affected and I think this is what caused the error message , whereas - you really just need to include the "targets" : [n] where 'n' is the column number. Perhaps it depends on how the table is constructed ?
Thanks.

Indexes: Search by Boolean?

I'm having some trouble with FaunaDB Indexes. FQL is quite powerful but the docs seem to be limited (for now) to only a few examples/use cases. (Searching by String)
I have a collection of Orders, with a few fields: status, id, client, material and date.
My goal is to search/filter for orders depending on their Status, OPEN OR CLOSED (Boolean true/false).
Here is the Index I created:
CreateIndex({
name: "orders_all_by_open_asc",
unique: false,
serialized: true,
source: Collection("orders"),
terms: [{ field: ["data", "status"] }],
values: [
{ field: ["data", "unique_id"] },
{ field: ["data", "client"] },
{ field: ["data", "material"] },
{ field: ["data", "date"] }
]
}
So with this Index, I want to specify either TRUE or FALSE and get all corresponding orders, including their data (fields).
I'm having two problems:
When I pass TRUE OR FALSE using the Javascript Driver, nothing is returned :( Is it possible to search by Booleans at all, or only by String/Number?
Here is my Query (in FQL, using the Shell):
Match(Index("orders_all_by_open_asc"), true)
And unfortunately, nothing is returned. I'm probably doing this wrong.
Second (slightly unrelated) question. When I create an Index and specify a bunch of Values, it seems the data returned is in Array format, with only the values, not the Fields. An example:
[
1001,
"client1",
"concrete",
"2021-04-13T00:00:00.000Z",
],
[
1002,
"client2",
"wood",
"2021-04-13T00:00:00.000Z",
]
This format is bad for me, because my front-end expects receiving an Object with the Fields as a key and the Values as properties. Example:
data:
{
unique_id : 1001,
client : "client1",
material : "concrete",
date: "2021-04-13T00:00:00.000Z"
},
{
unique_id : 1002,
client : "client2",
material : "wood",
date: "2021-04-13T00:00:00.000Z"
},
etc..
Is there any way to get the Field as well as the Value when using Index values, or will it always return an Array (and not an object)?
Could I use a Lambda or something for this?
I do have another Query that uses Map and Lambda to good effect, and returns the entire document, including the Ref and Data fields:
Map(
Paginate(
Match(Index("orders_by_date"), date),
),
Lambda('item', Get(Var('item')))
)
This works very nicely but unfortunately, it also performs one Get request per Document returned and that seems very inefficient.
This new Index I'm wanting to build, to filter by Order Status, will be used to return hundreds of Orders, hundreds of times a day. So I'm trying to keep it as efficient as possible, but if it can only return an Array it won't be useful.
Thanks in advance!! Indexes are great but hard to grasp, so any insight will be appreciated.
You didn't show us exactly what you have done, so here's an example that shows that filtering on boolean values does work using the index you created as-is:
> CreateCollection({ name: "orders" })
{
ref: Collection("orders"),
ts: 1618350087320000,
history_days: 30,
name: 'orders'
}
> Create(Collection("orders"), { data: {
unique_id: 1,
client: "me",
material: "stone",
date: Now(),
status: true
}})
{
ref: Ref(Collection("orders"), "295794155241603584"),
ts: 1618350138800000,
data: {
unique_id: 1,
client: 'me',
material: 'stone',
date: Time("2021-04-13T21:42:18.784Z"),
status: true
}
}
> Create(Collection("orders"), { data: {
unique_id: 2,
client: "you",
material: "muslin",
date: Now(),
status: false
}})
{
ref: Ref(Collection("orders"), "295794180038328832"),
ts: 1618350162440000,
data: {
unique_id: 2,
client: 'you',
material: 'muslin',
date: Time("2021-04-13T21:42:42.437Z"),
status: false
}
}
> CreateIndex({
name: "orders_all_by_open_asc",
unique: false,
serialized: true,
source: Collection("orders"),
terms: [{ field: ["data", "status"] }],
values: [
{ field: ["data", "unique_id"] },
{ field: ["data", "client"] },
{ field: ["data", "material"] },
{ field: ["data", "date"] }
]
})
{
ref: Index("orders_all_by_open_asc"),
ts: 1618350185940000,
active: true,
serialized: true,
name: 'orders_all_by_open_asc',
unique: false,
source: Collection("orders"),
terms: [ { field: [ 'data', 'status' ] } ],
values: [
{ field: [ 'data', 'unique_id' ] },
{ field: [ 'data', 'client' ] },
{ field: [ 'data', 'material' ] },
{ field: [ 'data', 'date' ] }
],
partitions: 1
}
> Paginate(Match(Index("orders_all_by_open_asc"), true))
{ data: [ [ 1, 'me', 'stone', Time("2021-04-13T21:42:18.784Z") ] ] }
> Paginate(Match(Index("orders_all_by_open_asc"), false))
{ data: [ [ 2, 'you', 'muslin', Time("2021-04-13T21:42:42.437Z") ] ] }
It's a little more work, but you can compose whatever return format that you like:
> Map(
Paginate(Match(Index("orders_all_by_open_asc"), false)),
Lambda(
["unique_id", "client", "material", "date"],
{
unique_id: Var("unique_id"),
client: Var("client"),
material: Var("material"),
date: Var("date"),
}
)
)
{
data: [
{
unique_id: 2,
client: 'you',
material: 'muslin',
date: Time("2021-04-13T21:42:42.437Z")
}
]
}
It's still an array of results, but each result is now an object with the appropriate field names.
Not too familiar with FQL, but I am somewhat familiar with SQL languages. Essentially, database languages usually treat all of your values as strings until they don't need to anymore. Instead, your query should use the string definition that FQL is expecting. I believe it should be OPEN or CLOSED in your case. You can simply have an if statement in java to determine whether to search for "OPEN" or "CLOSED".
To answer your second question, I don't know for FQL, but if that is what is returned, then your approach with a lamda seems to be fine. Not much else you can do about it from your end other than hope that you get a different way to get entries in API form somewhere in the future. At the end of the day, an O(n) operation in this context is not too bad, and only having to return a hundred or so orders shouldn't be the most painful thing in the world.
If you are truly worried about this, you can break up the request into portions, so you return only the first 100, then when frontend wants the next set, you send the next 100. You can cache the results too to make it very fast from the front-end perspective.
Another suggestion, maybe I am wrong and failed at searching the docs, but I will post anyway just in case it's helpful.
My index was failing to return objects, example data here is the client field:
"data": {
"status": "LIVRAISON",
"open": true,
"unique_id": 1001,
"client": {
"name": "TEST1",
"contact_name": "Bob",
"email": "bob#client.com",
"phone": "555-555-5555"
Here, the client field returned as null even though it was specified in the Index.
From reading the docs, here: https://docs.fauna.com/fauna/current/api/fql/indexes?lang=javascript#value
In the Value Objects section, I was able to understand that for Objects, the Index Field must be defined as an Array, one for each Object key. Example for my data:
{ field: ['data', 'client', 'name'] },
{ field: ['data', 'client', 'contact_name'] },
{ field: ['data', 'client', 'email'] },
{ field: ['data', 'client', 'phone'] },
This was slightly confusing, because my beginner brain expected that defining the 'client' field would simply return the entire object, like so:
{ field: ['data', 'client'] },
The only part about this in the docs was this sentence: The field ["data", "address", "street"] refers to the street field contained in an address object within the document’s data object.
This is enough information, but maybe it would deserve its own section, with a longer example? Of course the simple sentence works, but with a sub-section called 'Adding Objects to Fields' or something, this would make it extra-clear.
Hoping my moments of confusion will help out. Loving FaunaDB so far, keep up the great work :)

Button onClick inside DataTables doesn't show the correct url

I'm displaying all the customer data using DataTables like this:
<script type="text/javascript" src="DataTables/datatables.min.js"></script>
<script>
var theTable = null;
$(document).ready(function() {
theTable = $('#table-customer').DataTable({
"processing": true,
"serverSide": false,
"ordering": true,
"order": [[ 0, 'asc' ]],
"ajax":
{
"url": "http://localhost/myshop/showdata.php",
"type": "GET"
},
"sAjaxDataProp": "data",
"deferRender": true,
"aLengthMenu": [[5, 10, 20, 50],[ 5, 10, 20, 50]],
"columns": [
{ data: "cust_id" },
{ data: "cust_name" },
{ data: "cust_addr" },
{ data: "cust_email" },
{ data: "cust_phone" },
{ data: "cust_photo", sortable: true, render: function (o) { return '<button id="btn1" onclick="displayImage(data)">Show</button>';}
]
});
});
function displayImage(link){
window.alert(link);
}
</script>
All information is displayed properly, except 1 thing: if you click any button on "customer photo" column, instead of showing an alert which shows its URL, nothing happens. Inspecting the page showed me this:
Uncaught ReferenceError: data is not defined
at HTMLButtonElement.onclick (view.html:1)
How to fix this?
The columns.data render function builds a string which is returned:
function (o) { return 'your string here, including data value'; }
You have to (a) concatenate your data variable with the string literals you need; and (b) use the variable name you provided - I will use data instead of o:
function (data) { return 'your string here, including ' + data + ' value'; }
So, if we provide all the possible parameters allowed in the renderer, that becomes:
{
"data": "cust_photo",
"sortable": true,
"render": function(data, type, row, meta) {
return '<button id="btn1" onclick="displayImage(\'' + data + '\')">Show</button>';
}
}
I use \' to ensure the value of the data variable is surrounded in single quotes.
(Note that in your question, the code is also missing a closing }.)
But to avoid potential issues with sorting and filtering, these column data render functions need to account for DataTable's use of orthogonal data.
The type parameter can be used for this:
{
"data": "cust_photo",
"sortable": true,
"render": function(data, type, row, meta) {
if (type === 'display') {
return '<button id="btn1" onclick="displayImage(\'' + data + '\')">Show</button>';
} else {
return data; // type is for sorting or filtering - just use the raw value
}
}
}

Order DataTables by invisible data column using columns.orderData

For my question I have prepared a simple test case at JS Bin.
In a word game I am trying to display the 20 longest words played by a player.
I deliver the data from PostgreSQL to DataTables jQuery plugin in JSON format. It is already sorted by word length and by the date when words were played.
This order is stored as numeric value (1, 2, 3, ...) in the row property of each JSON object:
var dataSet = [
{"row":4,"gid":1,"created":"25.02.2017 14:07","finished":null,"player1":2,"player2":1,"score1":30,"score2":52,"female1":0,"female2":0,"given1":"Abcde3","given2":"Ghijk4","photo1":null,"photo2":null,"place1":null,"place2":null,"word":"ZZ","score":11},
{"row":2,"gid":1,"created":"25.02.2017 14:07","finished":null,"player1":2,"player2":1,"score1":30,"score2":52,"female1":0,"female2":0,"given1":"Abcde3","given2":"Ghijk4","photo1":null,"photo2":null,"place1":null,"place2":null,"word":"BBBBB","score":6},
{"row":3,"gid":1,"created":"25.02.2017 14:07","finished":null,"player1":2,"player2":1,"score1":30,"score2":52,"female1":0,"female2":0,"given1":"Abcde3","given2":"Ghijk4","photo1":null,"photo2":null,"place1":null,"place2":null,"word":"ABC","score":7},
{"row":1,"gid":1,"created":"25.02.2017 14:07","finished":null,"player1":2,"player2":1,"score1":30,"score2":52,"female1":0,"female2":0,"given1":"Abcde3","given2":"Ghijk4","photo1":null,"photo2":null,"place1":null,"place2":null,"word":"XYZXYZXYZ","score":6}
];
Here is my JavaScript code, where I try to sort the column word (column 2) by the invisible column row (column 0):
function renderGid(data, type, row, meta) {
return (type === 'display' ? '<IMG SRC="https://datatables.net/examples/resources/details_open.png"> #' + data : data);
}
function renderGame(data) {
return 'Details for game #' + data.gid;
}
jQuery(document).ready(function($) {
var longestTable = $('#longest').DataTable({
data: dataSet,
order: [[2, 'desc']],
columns: [
{ data: 'row', orderable: false, visible: false },
{ data: 'gid', orderable: false, visible: true, className: 'details-control', render: renderGid },
{ data: 'word', orderable: true, visible: true, orderData: 0 /* order by invisible column 0 */ },
{ data: 'score', orderable: false, visible: true }
]
});
$('#longest tbody').on('click', 'td.details-control', function () {
var img = $(this).find('img');
var tr = $(this).closest('tr');
var row = longestTable.row(tr);
if (row.child.isShown()) {
row.child.hide();
img.attr('src', 'https://datatables.net/examples/resources/details_open.png');
} else {
row.child( renderGame(row.data()) ).show();
img.attr('src', 'https://datatables.net/examples/resources/details_close.png');
}
});
});
However this does not work - the displayed words order is ZZ, BBBB, ABC, XYZXYZXYZ (seemingly unsorted) - while it should be XYZXYZXYZ, BBBB, ABC, ZZ (sorted by row descending):
Why does not sorting work even though I have specified columns.orderData: 0?
And why can't I change ordering by clicking the greyed out arrows (shown by the red arrow in the above screenshot)?
Ok, this seems to be an old bug in dataTables jQuery plugin: the integer argument is not accepted.
I have to change it to an array with the single value:
{ data: 'word', orderable: true, visible: true, orderData: [0] },
and then it works:

format date US 'MM/DD/YYYY" in DataTables

https://communitychessclub.com/examine.php DataTables with moment.js is sorting date as a string, not a date. How can I get a sample date of "08/23/2018" to sort properly? That is, I want to sort "mm/dd/yyyy". I simply can't get this to work.
<script src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js"></script>
<script src="//cdn.datatables.net/plug-ins/1.10.19/sorting/datetime-moment.js"></script>
<script src="js/dataTables.keepConditions.min.js"></script>
<script>
$.fn.dataTable.moment = function ( format, locale ) {
var types = $.fn.dataTable.ext.type;
// Add type detection
types.detect.unshift( function ( d ) {
return moment( d, format, locale, true ).isValid() ?
'moment-'+format :
null;
} );
// Add sorting method - use an integer for the sorting
types.order[ 'moment-'+format+'-pre' ] = function ( d ) {
return moment( d, format, locale, true ).unix();
};
};
</script>
<script>
$(document).ready(function() {
$.fn.dataTable.moment( 'MM/DD/YYYY' );
$('#cccr').DataTable( {
"ajax": "assets/games.ajax",
"pageLength": 25,
"order": [[ 8, "desc" ]],
"columns": [
{ "data": "Date", "width": "7rem", },
{ "data": "Event" },
{ "data": "ECO" },
{ "data": "White" },
{ "data": "WhiteElo" },
{ "data": "Black" },
{ "data": "BlackElo" },
{ "data": "Result" },
{ "data": "game", visible : false }
]
} );
} );
</script>
Found the culprit. It's in the data - following row:
{
"game": "5533",
"Date": "05/1/2010",
"Event": "RCC FIDE RR #2",
"ECO": "C56",
"White": "Nikolayev, Igor (FM)",
"WhiteElo": "2367",
"Black": "Jones, Aaaron",
"BlackElo": "1966",
"Result": "1-0"
},
You have the format DD to read but the date here is of the format D which makes it a different format which ends up messing the table sorting.
Here's a plunkr including above row as is:
http://plnkr.co/edit/eYRVBr8P4g7Ua4Z7K6JG?p=preview
Fixing the above date format, here's a new plunkr:
http://plnkr.co/edit/zPF9LDZjAAZeqXIJ3XOF?p=preview
And as Alan (DataTables author) suggests in this comment:
At the moment the plug-in only supports a single format in each column. If could probably be modified if you needed to support two or more formats in a single column.
Using a common format for all the dates will help you fix the issue.
Hope this helps.