DataTables, Ajax Pipelining - php

I'm using DataTables with pipelining. I works great except when I tried to enter an extra column to hold "edit" links. See this table.
Here is a snippet of server_processing.php showing the columns:
/* Array of database columns which should be read and sent back to DataTables.
* Use a space where you want to insert a
* non-database field (for example a counter or static image)
*/
$aColumns = array( 'user','email', );
And here is the clientside:
$(document).ready( function (){
$('#example').dataTable({
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "scripts/server_processing.php",
"fnServerData": fnDataTablesPipeline,
aoColumns: [null, null, {"bSortable": false}]
}).makeEditable({
sUpdateURL: "UpdateData.php",
sAddURL: "AddData.php",
sAddHttpMethod: "POST",
sDeleteURL: "DeleteData.php",
sDeleteHttpMethod: "POST",
aoColumns: [ { } , { } , null ]
});
});
So, why isn't this working?

Just done this exact same thing myself. I like to configure all my columns using aoColumnDefs, as you can add multiple configuration options for columns in one go.
// Disable sorting on the 3rd column
'aoColumnDefs': [{'aTargets': [2], 'bSortable': false}]
Note that aTargets is an array of column indexes you want to apply those settings to. So if you were to add more link columns (e.g. a Delete link), you can turn off sorting on those without rewriting the column definition every time.
// Disable sorting on the 3rd and 4th column
'aoColumnDefs': [{'aTargets': [2,3], 'bSortable': false}]
And, as I was saying, you can add further configuration options for columns in this same array:
// Disable sorting on the 3rd and 4th column and sort 1st column by string
'aoColumnDefs': [
{'aTargets': [2,3], 'bSortable': false}
{'aTargets': [0], 'sType': 'string'}
]

Related

PHP multi-select filter with Ajax post request with DataTables

I'm trying to convert an existing "select" dropdown filter on a table generated via the DataTables library to be able to handle multiple options, and though I think I have it correct on the front-end Javascript, I'm having trouble figuring out how to handle it in the back-end PHP.
The below is from the script in the front-end view, which makes the Ajax Post request:
<script>
function generateTable() {
var oTable = $('#MyData').dataTable({
"aaSorting": [
[1, "desc"]
],
"aLengthMenu": [
[10, 25, 50, 100, 200],
[10, 25, 50, 100, 200]
],
"iDisplayLength": <?= $Settings->rows_per_page ?>,
'bProcessing': true,
'bServerSide': true,
'sAjaxSource': '/my/getData/path',
'fnServerData': function(sSource, aoData, fnCallback) {
// ...SNIP...
aoData.push({
"name": "some_status",
"value": $("#some_status").val()
});
$.ajax({
'dataType': 'json',
'type': 'POST',
'url': sSource,
'data': aoData,
'success': fnCallback
});
},
"aoColumns": [],
}).fnSetFilteringDelay().dtFilter([
// ...SNIP...
{
column_number: 4,
filter_default_label: "[<?= lang('some_status'); ?>]",
filter_type: "multi_select",
data: []
},
// ...SNIP...
], "footer");
}
</script>
I can confirm that the selected values are added to an array by console logging the $("#some_status").val(). So my assumption was that it would be passed to the backend as an array as well, but apparently not.
What actually happens is the first selection goes fine, but any subsequent selection clears the table, and only works if there's a single value selected, leaving me to believe that only the first selection is pushed to the aoData array.
In PHP I have:
$this->load->library('datatables');
$this->datatables
->select("id, date, reference_no, supplier, some_status")
->from('purchases');
$some_status = $this->input->post('some_status');
if ($some_status != '') {
$this->datatables->where('status', $some_status);
}
How do I handle the some_status value if it's an array, or how do I make sure it even is an array after it was pushed toaoData?
Any help will be appreciated!
EDIT:
To clarify, by console logging the result like below returns the correct selection as I add and remove selections from the multi-select dropdown:
console.log($("#some_status").val());
If I select "Top option" from the dropdown, I get:
[
"top_option"
]
When I then select "Another option" as well, I get:
[
"top_option", "another_option"
]
So the JS side is handling the multi-select, but I don't know if the below is correct, as it works only with a single select, nothing more:
$some_status = $this->input->post('some_status');
if ($some_status != '') {
$this->datatables->where('status', $some_status);
}

laravel datatable take long time to load data

I am trying to display database table to laravel datatable using below code but laravel datatable taking long time to load data.
I have approx 700000 records in database. How to decrease time of load data?
Code
web.php
Route::get('home', 'HomeController#index')->name('home');
HomeController.php
public function index()
{
$campaigns = TonicData::select('campaign')->distinct()->get();
if (request()->ajax()) {
$data = \DB::table('tonic_data')
->whereNotNull('subid4')
->where('subid4', '!=', '')
->select('subid4')
->groupBy('subid4')
->selectRaw('sum(view) as sum_of_views, sum(term_view) as sum_of_term_views,
sum(add_click) as sum_of_add_click, sum(revenue_usd) as sum_of_revenue,
(sum(revenue_usd)/sum(view)*1000) as rpm')
->when((request()->has('selectedCampaign') && request()->get('selectedCampaign') != ''), function ($query) {
$query->whereIn('campaign', request()->get('selectedCampaign'));
})
->when((request()->has('selectedDateRange') && request()->get('selectedDateRange') != ''), function ($query) {
$query->whereBetween('day_date', [request()->get('selectedDateRange')['fromDate'], request()->get('selectedDateRange')['toDate']]);
});
return DataTables::of($data)
->addIndexColumn()
->make();
}
return view('dashboard', compact('campaigns'));
}
dashboard.blade.php
<script type="text/javascript">
$(document).ready(function() {
$('#datatable').dataTable({
responsive: true,
processing: true,
serverSide: true,
ajax: '{{ route('home') }}',
columns: [
{data: 'DT_RowIndex', orderable: false, searchable: false},
{data: 'subid4', name: 'subid4'},
{data: 'sum_of_views', name: 'sum_of_views', searchable: false},
{data: 'sum_of_term_views', name: 'sum_of_term_views', searchable: false},
{data: 'sum_of_add_click', name: 'sum_of_add_click', searchable: false},
{data: 'sum_of_revenue', name: 'sum_of_revenue', searchable: false},
{data: 'rpm', name: 'rpm', searchable: false}
]
});
});
</script>
sql code
query 1:
select count(*) as aggregate
from ( SELECT `subid4`,
sum(view) as sum_of_views,
sum(term_view) as sum_of_term_views,
sum(add_click) as sum_of_add_click,
sum(revenue_usd) as sum_of_revenue,
(sum(revenue_usd)/sum(view)*1000) as rpm
from `tonic_data`
where `subid4` is not null
and `subid4` != ?
group by `subid4`
) count_row_table
query 2:
select `subid4`, sum(view) as sum_of_views, sum(term_view) as sum_of_term_views,
sum(add_click) as sum_of_add_click, sum(revenue_usd) as sum_of_revenue,
(sum(revenue_usd)/sum(view)*1000) as rpm
from `tonic_data`
where `subid4` is not null
and `subid4` != ?
group by `subid4`
limit 10 offset 0
Thanks in advance!
To summarize the discussion, as your query try to get all 700k records at once, no wonder it takes a long time.
Al though you are showing only a limited number of records while rendering the page, technically query gets all records on page load itself.
Action Required
Minimize the below section:
->selectRaw('sum(view) as sum_of_views, sum(term_view) as sum_of_term_views,
sum(add_click) as sum_of_add_click, sum(revenue_usd) as sum_of_revenue,
(sum(revenue_usd)/sum(view)*1000) as rpm')
Instead of sum up all these values on the fly, maintain a separate table and store all these values when any record gets altered in the tonic_data. There are callback functions as per this answer.
Instead of datatables use laravel pagination and sorting which will perform on server side that controls loading the huge data on page load.
try to implement date based or other possible filters.
Looks like Laravel is running the same query twice -- once to get a row count, once to get the first 10 rows.
Because of the GROUP BY, the LIMIT 10 has little effect on the speed. This is because it must gather lots of rows, then do the grouping, and only finally deliver 10 rows.
The first query (to get the count) could be simplified and greatly sped up by changing to
select count(DISTINCT subid4) as aggregate
from `tonic_data`
where `subid4` is not null
and `subid4` != ?
and having
INDEX(subid4)
Or forego of the count (if Laravel lets you do that).
Please provide SHOW CREATE TABLE tonic_data; I may have further tips.
First of all I suggest looking into your query performance and try to optimize your query.
Secondly jquery datatables plugin has a feature (named as pipeline) to cache number of pages to reduce ajax calls. So this way let's say on first request if you have cached 10 pages, then it won't make another request to server until the 11th page is accessed and this goes on.
So on client side your ajax will be updated to
<script type="text/javascript">
$(document).ready(function() {
$('#datatable').dataTable({
responsive: true,
processing: true,
serverSide: true,
ajax: $.fn.dataTable.pipeline({
url: '{{ route('home') }}',
pages: 20 // number of pages
})
});
});
</script>
For more help on pipeline, please refer https://datatables.net/examples/server_side/pipeline.html

Data table sorting is not working properly

friend please help me...
i am facing problem regarding data table sorting when i click on sort button in asc its show some rendom id like first row id is 20 second row is 18 like that
var dataTable = $('#users').DataTable( {
"bProcessing": true,
"aLengthMenu": [[10,25,50,1000000,], [10,25,50,"All",]],
"bProcessing": true,
"serverSide": true,
"language": {
searchPlaceholder: "Enter Card Number"
},
"dom": 'lfrtip',
"ajax":{
url :"response.php",
type: "post",
}
Are you using serverside sorting? if yes then make sure the field which you want sorting must be INT datatype or relevant to numeric datatype in database.

can't add data to jqGrid from php within json format

Hello StackOverFlow nation . I'm trying to add information to jqGrid , which is retrieved from MySQL database. I've two files => index.html and data.php (both in the same directory)
index.html source =>
<script type="text/javascript">
$(function(){
$("#jqGrid_tb").jqGrid({
url: "data.php",
datatype: "json",
sortable: true,
height: "auto",
colNames: ["Name","Surname","Birth Year","Famous Film"],
colModel: [
{name: "name", index: "name", width: "150"},
{name: "surname", index: "surname", width: "150"},
{name: "b_year", index: "year", width: "150"},
{name: "film", index: "film", width: "200"}
],
rowNum: 5,
rowList: [5,10,15],
viewrecords: true,
pager: $("#pager"),
caption: "Famous Actors",
}).navGrid("#pager");
});
</script>
<div id="grid">
<table id="jqGrid_tb"></table>
<div id="pager"></div>
</div>
data.php source =>
include ("JSON.php");
$json = new Services_JSON();
$con = new mysqli("host","user","pswd","db");
if (!$con->connect_errno){
if ($r = $con->query("SELECT * FROM actors")){
while ($row = $r->fetch_assoc()){
$info[] = array(
"name" => $row[name],
"surname" => $row[surname],
"b_year" => $row[b_year],
"film" => $row[film],
);
}
$r->free();
}
}
echo $json->encode($info);
if (isset($con)){
$con->close();
}
jqGrid is shown without any information in index.html file , also when opening data.php file information is successfully encoded into JSON format , whats wrong I can't understand . Please help , thanks ...
Your response format is wrong. You can go to jqGrid Demos page where you will find a sample for PHP/MySQL after expanding Loading Data and then choosing JSON Data.
The proper format of data should look like this:
{
"total": "1",
"page": "1",
"records": "2",
"rows": [
{ "name": "Robert", "surname": "De Niro", "b_year": "1943", "film": "Once Upon A Time In America" },
{ "name": "Al", "surname": "Pacino", "b_year":"1971", "film": "Scent Of A Woman"}
]
}
Where:
total --> total count of pages
page --> current page number
records --> total count of records
rows --> the rows of data
Also if you want rows to be objects, you need to disable repeatitems in jqGrid jsonReader options:
$("#jqGrid_tb").jqGrid({
...
jsonReader: { repeatitems: false }
});
It is also adviced for rows to have unique id for later reference.
You should include
jsonReader: {
repeatitems: false,
root: function (obj) { return obj; },
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.length; }
}
as additional option of jqGrid is you don't want to change format of input data. Moreover you should specify which values should assign jqGrid as id attribute of the row. You can include additional id property as additional property of every returned item or you can add key: true property to the column (in colModel) which contains unique values. For example if you can guarantied that the values from "name" are already unique then you can include key: true property in definition of "name" column.
Additionally you can consider to use loadonce: true option of jqGrid. In the case the full data of the grid will be loaded at once and the sorting, paging and searching (filtering) of data will be implemented by jqGrid on the client side without needs to implement some additional code on the server side. You should don't use the option in case of large number of rows (many hundred or many thousand rows) in the grid.

filter the exact word in datatables

I am using datatables plugin in my php script. For searching, I have a drop down box having two values "Active" and "Inactive". When I am searching by "Active" word, then it is showing the records, containing "Active" as well as "Inactive". I know this is happening only for that particular word("Active").
Then how to stop this wild cards search for this drop down box.
My code is like:
$("#example").dataTable().columnFilter(
{
"aoColumns": [
null,null,null,null,
{
type: "select",
values: [ 'Active', 'Inactive' ]
},
null ]
});
Datatables have default option of search being caseinsensitive, so try to put the following while initialising your datatable.
$("#example").dataTable(
{
"bCaseInsensitive": false,
});

Categories