Datatables custom filtering with server side - datatables

I'm using DataTables and also using server side processing (Django).
I have a seperate textfield in which I use it to custom filter data in the DataTable after the table has been rendered already.
The following works just fine (I want to custom filter columns):
var table = $('#problem_history').DataTable( {
"bJQueryUI": true,
"aaSorting": [[ 1, "desc" ]],
"aoColumns": [
// various columns here
],
"processing": true,
"serverSide": true,
"ajax": {
"url": "/getdata",
"data": {
"friend_name": 'Robert'
}
}
} );
So on the page load (initial load of the DataTable) it filters for 'Robert' just fine. But now I want to programmatically change the data to filter for "friend_name" == "Sara"
I already tried the following, the filteredData has a correct filtered object but the table itself does not redraw with the new filter.
var filteredData = table.column( 4 ).data().filter(
function ( value, index ) {
return value == 'Sara' ? true : false;
}
);
table.draw();
I also tried this but no luck:
filteredData.draw();
How can I achieve this?
Thank you for your help.

Here is a very nice explanation on how to do it:
https://datatables.net/reference/option/ajax.data
I am currently using this code:
"ajax": {"url":"/someURL/Backend",
"data": function ( d ) {
return $.extend( {}, d, {
"parameterName": $('#fieldIDName').val(),
"parameterName2": $('#fieldIDName2').val()
} );
}
}
You call it by doing the following:
$('#myselectid').change(function (e) {
table.draw();
});
If you want to submit by clicking on the button, change the .change to .click and make sure that ID is pointing to button's id in a HTML

You've almost got it. You just need to assign the filter var to
the data parameter that's passed in the datatables request:
"ajax": {
"url": "/getdata",
"data": {
"friend_name": $('#myselectid').val();
}
}
And to filter the data, just call draw() on the select change event
$('#myselectid').change(function (e) {
table.fnDraw();
});

For Basic searches, you should use the search() API:
// Invoke basic search for 'a'
dt.search('a', false)
For more complex queries, you can utilize searchBuilder backend by intercepting the ajax call through an open API. Here are some searchBuilder examples:
// Basic example:
// . (searchable_fields contains 'a'
// AND (office = Tokyo AND Salary > 100000)
// )
$('#problem_history').on('preXhr.dt', function(e, settings, data){
data['searchBuilder'] = {
'criteria': [
{'data': 'Office', 'origData': 'office', 'type': 'string'
,'condition': '='
,'value': ["Tokyo"], 'value1': "Tokyo"
}
,{'data': 'Salary', 'origData': 'salary', 'type': 'num'
,'condition': '>'
,'value': [100000], 'value1': 100000
}
]
,'logic': 'AND'
}
})
// Complex example:
// . (searchable_fields contains 'a'
// AND (
// (office = Tokyo AND Salary > 100000)
// OR (office = London AND Salary > 200000)
// )
// )
$('#problem_history').on('preXhr.dt', function(e, settings, data){
data['searchBuilder'] = {
'criteria': [
{'criteria': [
{'data': 'Office', 'origData': 'office', 'type': 'string'
,'condition': '='
,'value': ["Tokyo"], 'value1': "Tokyo"
}
,{'data': 'Salary', 'origData': 'salary', 'type': 'num'
,'condition': '>'
,'value': [100000], 'value1': 100000
}
]
,'logic': 'AND'
}
,{'criteria': [
{'data': 'Office', 'origData': 'office', 'type': 'string'
,'condition': '='
,'value': ["London"], 'value1': "London"
}
,{'data': 'Salary', 'origData': 'salary', 'type': 'num'
,'condition': '>'
,'value': [200000], 'value1': 200000
}
]
,'logic': 'AND'
}
]
,'logic': 'OR'
}
})
SearchBuilder Logic Types:
=
!=
contains
starts
ends
<
<=
>
>=
between
null
!null
SearchBuilder data value blocks:
value: [<val>] seems to always equal value1
value2: For upper bounds of 'between' logic where value1 would be lower bounds

Related

suitescript 2.0 unable to search inventorydetails subrecord from saved search data

I have created one saved search, and I am fetching data from by suitescript and here is the demo data response which I am getting this result from saved search response
{
"results": [
{
"recordType": "itemreceipt",
"id": "2572118",
"values": {
"trandate": "2021-3-25",
"type": [
{
"value": "ItemRcpt",
"text": "Item Receipt"
}
],
"tranid": "RCV123",
"salesrep": [
{
"value": "16018",
"text": "MXZ"
}
],
"entity": [
{
"value": "16993",
"text": "ABC"
}
],
"memo": "",
"amount": "1218.00",
"location": [
{
"value": "1",
"text": "XYZ"
}
],
"inventoryDetail.inventorynumber": [
{
"value": "10504",
"text": "3566044578"
}
]
}
}
]
}
AND I AM USING BELOW CODE TO MAKE FILTER BY inventoryDetail.inventorynumber FIELD WHICH IT MENTIONED IN SAVED SEARCH RESPONSE DATA AND IT THROWS ERROR "An nlobjSearchFilter contains invalid search criteria: inventoryDetail.issueinventorynumber."
but if I used tranid instead of inventoryDetail.issueinventorynumber then it does not throw the error, why I can not filter by inventoryDetail.inventorynumber I am trying since two days but no luck, please help me guys
/**
* #NApiVersion 2.1
* #NScriptType Restlet
* #NModuleScope Public
*/
/*
------------------------------------------------------------------------------------------
Script Information
------------------------------------------------------------------------------------------
Name:
Saved Search API
ID:
_saved_search_api
*/
var
log,
search,
response = new Object();
define( [ 'N/log', 'N/search' ], main );
function main( logModule, searchModule ) {
log = logModule;
search = searchModule;
return { post: postProcess }
}
function postProcess( request ) {
try {
var searchObj = search.load( { id: 1234 } );//saved search id
// Copy the filters from rs into defaultFilters.
var defaultFilters = searchObj.filters;
// below code works
defaultFilters.push(search.createFilter({
name: "tranid",
operator: search.Operator.IS,
values: ["RCV123"]
}));
// but this code does not works and it throws error "An nlobjSearchFilter contains invalid search criteria: inventoryDetail.issueinventorynumber."
/*defaultFilters.push(search.createFilter({
name: "inventoryDetail.inventorynumber",
operator: search.Operator.IS,
values: ["3566044578"]
}));*/
searchObj.filters = defaultFilters;
searchObj.filters = defaultFilters;
response.results = [];
var resultSet = searchObj.run();
var start = 0;
var results = [];
do {
results = resultSet.getRange( { start: start, end: start + 1000 } );
start += 1000;
response.results = response.results.concat( results ) ;
response.count =results.length;
} while ( results.length );
return response;
} catch( e ) {
log.debug( { 'title': 'error', 'details': e } );
return { 'error': { 'type': e.type, 'name': e.name, 'message': e.message } }
}
}
issueinventorynumber is not a valid search Column on the inventorydetail record. You are probably looking for inventorydetail.inventorynumber. You can reference the Search Columns section for the Inventory Detail within the Records Browser.
Be aware that Search Column names are not always the same as the field ID in the UI, as is the case here. The ID in the UI is issueinventorynumber, while the ID for the Search Column is inventorynumber.
Finally I found the solution
var transactionSearchObj = search.create({
type: "transaction",
filters:
[
["formulatext: {inventorydetail.inventorynumber}","contains","30124578547"]
],
columns:
[
search.createColumn({name: "trandate", label: "Date"}),
search.createColumn({name: "type", label: "Type"}),
search.createColumn({name: "tranid", label: "Document Number"}),
search.createColumn({name: "salesrep", label: "Sales Rep"}),
search.createColumn({name: "memo", label: "Memo"}),
search.createColumn({name: "amount", label: "Amount"}),
search.createColumn({name: "location", label: "Location"}),
search.createColumn({
name: "itemid",
join: "item",
label: "Name"
}),
search.createColumn({
name: "inventorynumber",
join: "inventoryDetail",
label: " Number"
})
]
});
return transactionSearchObj.run().getRange( { start: 0, end: 0 + 1000 } );

vue-good-table custom sorting

I am using vue-good-table and have the following code so far:
<vue-good-table :columns="columns" :rows="rows"
styleClass="vgt-table condensed striped bordered"
:sort-options="sortOptions"
:search-options="searchOptions"
:select-options="selectOptions"
#on-selected-rows-change="selectionChanged">
</vue-good-table>
sortOptions: {
enabled: true,
initialSortBy: { field: "date", type: "desc" },
}
columns() {
return [
{
label: "Name",
field: "name",
},
{
label: "CreationDate",
field: "date",
type: "date",
formatFn: function (value) {
return value != null ? moment(value).format('YYYY-MM-DD') : null;
},
sortFn(x, y) {
x = moment(x);
y = moment(y);
return x.unix() < y.unix() ? -1 : x.unix() > y.unix() ? 1 : 0;
},
},
]
}
Sorting works fine so far, and there are three states: 'asc', 'desc' and 'none'.
However i would like to achieve the following:
When clicking the column header and the current sorting type is 'none' for any of the columns, i would like to have the data sorted as defined in the initialSortBy property in the sortOptions. So sorted by date in desc order.
I tried using the #on-sort-change event but don't really know how to proceed further as i am quite new to Vue.
onSortChange(params) {
console.log('on-sort-change:');
console.log(params[0].field)
console.log(params[0].type)
if (params[0].type == 'none') {
console.log("default sort")
//TODO sort data as defined in initial sort
}
}

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
}
}
}

YADCF custom_func not calling custom function

I have a database field that contains either integer 1 (representing the value 'document') or integer 2 (representing the value 'email') and I use datatables to format/display these integers as the words 'document' or 'email' within the table column. I would therefore like to use YADCF to be able to select 'document' or 'email' and have datatables filter the resultset accordingly.
Link to screen shot of table column.
I have used the custom_func feature as follows (code stripped down for brevity), but regardless of all other aspects of the datatable looking and working correctly, with a filter selector looking as expected and holding the selected value, and no console errors, my custom function is not being called. I have tried manually calling the custom function immediately before initialising YADCF, to check the scope, and it is being called just fine. Can anyone see anything obviously wrong please?
$(document).ready(function() {
function customFilterDocEmail(filterVal, columnVal) {
alert('customFilterDocEmail called');
var found;
if (columnVal === '') {
return true;
}
switch (filterVal) {
case 'doc':
found = columnVal === '1';
break;
case 'email':
found = columnVal === '2';
break;
default:
found = 1;
break;
}
if (found !== -1) {
return true;
}
return false;
}
})
var table = $('#table').DataTable({
serverSide: true,
processing: true,
ajax: {
url: '/api/datatables/getJson/doctext/doctexts',
type: 'POST',
data: function(d) {d.CSRFToken = '****';}
},
stateSave: true,
responsive: true,
pageLength: 25,
order: [[0, 'asc']],
columns: [
{ data: 'txt_type', width: '10%' },
{ data: 'txt_title' },
{ data: 'txt_name', width: '20%' },
{ data: 'link', orderable: false, width: '5%' },
],
}
});
yadcf.init(table, [
{ column_number: 0, filter_type: 'custom_func', custom_func: customFilterDocEmail,
data: [{ value: 'doc', label: 'Document' }, { value: 'email', label: 'Email' }] },
{ column_number: 1, column_data_type: 'text', filter_type: 'text', filter_delay: 500, filter_default_label: '', },
{ column_number: 2, column_data_type: 'text', filter_type: 'text', filter_delay: 500, filter_default_label: '', },
], 'footer');
YADCF Version: 0.9.3.beta.11
DataTables Version: 1.10.16
UPDATE: I haven't a clue what I'm doing wrong above, but I have come up with a little hack that saves having to use 'custom_func' and a custom filter. I've used the standard 'select' filter type but intercepted the filter string within the filter() method of my DatatablesSSP script thus:
$str = $requestColumn['search']['value'];
// returned search values for doctext 'txt_type' are Document/Email, so we need to map these to 1/2.
if ($column['db'] == 'txt_type') {
if ($str == 'Document') { $str = '1'; }
if ($str == 'Email') { $str = '2'; }
}
This works a treat :)
You have to place the customFilterDocEmail function outside of the $(document).ready block so it will be global and yadcf will see it

ExtJs4+: can calculated model field be editable?

My model has two data fields: persistent and calculated:
Ext.define('My.model.Value', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
{ name: 'id', type: 'auto' },
{ name: 'percentage', type: 'float' }, // values in 0..1 range
{ name: 'percentageDecimal', type: 'float', persist: false,
calculate: function(v) {
v = v.percentage;
return Ext.isNumber(v) ? v * 100.0 : v;
}
}
]
});
The percentageDecimal field is used in a grid and it is editable.
Question: how can I change my model to automatically update percentage field everytime the percentageDecimal is updated?
I use ExtJs 5.0.1.
I used #adaskos' suggestion as follows:
Ext.define('My.model.Value', {
extend: 'Ext.data.Model',
idProperty: 'id',
fields: [
{ name: 'id', type: 'auto' },
{ name: 'percentage', type: 'float' }, // values in 0..1 range
{ name: 'percentageDecimal', type: 'float', persist: false,
calculate: function(v) {
v = v.percentage;
return Ext.isNumber(v) ? v * 100.0 : v;
}
}
],
set: function (fieldName, value, options) {
if (Ext.isString(fieldName)) {
// single field update
if (fieldName === 'percentageDecimal') {
this.set('percentage', Ext.isNumber(value) ? 0.01 * value : value);
return;
}
} else {
// multiple fields update
if (Ext.isDefined(fieldName.percentageDecimal)) {
var data = Ext.clone(fieldName);
data.percentage = Ext.isNumber(data.percentageDecimal)
? 0.01 * data.percentageDecimal
: data.percentageDecimal;
delete data.percentageDecimal;
this.set(data);
return;
}
}
this.callParent(arguments);
}
});
I don't know if they added an automated way to do this in 5.0.1, but you can always override the set method and whenever an update occurs to percentageDecimal, you recalculate the percentage.
An alternative I prefer: if you expect enough updates but all you want is to display it in a grid, you can remove the extra computed field from the model and set your column with dataIndex: 'percentageDecimal' and change its renderer function to display it as you like (as a decimal).
Like below:
... , { text: 'Percentage', dataIndex: 'percentageDecimal'
, renderer: function (v) {
return Ext.isNumber(v) ? v * 100.0 : v;
}
}
You should use the config options depends to have this updated automatically!
And use the function convert instead of calculate (not sure if it work with calculate, i need to test)
See http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.data.field.Field-cfg-depends