Linking DataTables with sql database using Nodejs - node.js

I hope you can help me because I'm driving mad about this question.
I'm not experienced with Node, Ajax and DataTables, so this is likely a my fault.
I have an html table linked to Datatables. On load document I send a POST request to get data from an MySQL database. If I popolate DataTable with row.add() method all works fine, but if the table grows I could have some slowdowns with this system, so I would like to link the DataTable table with the database so that the program loads only the records to show. Now problem starts.
In my Node file, if I return sql data like so:
res.json(result);
my DataTable shows all the data, but table hasn't right number of record (below the table shows "Showing 0 to 0 of 0 entries (filtered from NaN total entries)" and, even worst, the table has infinite pages, all displaying the same data (the first 10 records).
If instead I return an ajax:
ret = JSON.stringify({
"draw": req.body.draw,
"recordsTotal": result[0]['COUNT(cf)'],
"recordsFiltered": result[0]['COUNT(cf)'],
"data": dati
});
res.send(ret);
DataTables shows the correct number of records in the info line at bottom of table, but no data is displayed.
In console I show the ret object and it seems all right. I'm no idea what to do now.

I resolved!!! It's incredible after near 2 days of attempts.
In html file I put in DataTables ajax :
[...]
dataSrc: 'dati',
[...]
Then in my Nodejs file:
ret = JSON.stringify({
"draw": req.body.draw,
"recordsTotal": result[0]['COUNT(cf)'],
"recordsFiltered": result[0]['COUNT(cf)'],
"dati": dati
});
res.send(ret);
and all works fine.

Related

SAP UI5 to Implement "go to" specific page on the table

I am new to SAP UI5 development. Currently the table is using "growing" and "growingThreshhold", then users can click more to see data of next page. Since we have thousands of data in that table, it takes user time to click more and more again to load next page data. we try to implement a function, that user can enter the page number then click a button and go to the specific page.
<Table id="genTable" growing="true" growingThreshold="60" fixedLayout="false" selectionChange="onHandleSelectChange"
backgroundDesign="Solid" updateFinished="onHandleGeneratorQueueUpdateFinished">
Expected UI:
I added a bar then UI display is good.
<Bar design="SubHeader">
<contentMiddle>
<Input type="Number" id="pageNumber" width="50px"></Input>
<Button id="goToButton" text="Go to" type="Emphasized" press="onHandleGoTo"></Button>
</contentMiddle>
</Bar>
For the backend logic, I refer to below articles, but still doesn't work.
https://blogs.sap.com/2016/12/14/sapui5-pagination-in-sap.m-table-on-button-click-using-odata-service/
https://sapyard.com/advance-sapui5-19-pagination-in-table-control-with-top-and-skip-query-options/
I tried to use read, the it can get the data back from odata service, but the data can't be refreshed in the table.
oModel.read("/ViewQueueSet", {
urlParameters: {
"$top": top,
"$skip": count
},
filters: [new Filter("RoleCode", FilterOperator.EQ, "G")],
useBatch: true,
success: function (tdata) { //successful Read in the server
var json = new JSONModel();
json.setData(tdata);
that.getView().setModel(json,"sapmodel");
sap.ui.core.BusyIndicator.hide();
},
error: function () {
sap.ui.core.BusyIndicator.hide();
}
});
}
also tried to call bindItems
//that.getView().setModel(json,"sapmodel");
//oTable.setModel(json); //JSON is preferred data format
//oTable.bindItems("/results",that.oGenQueueTemplate);
that.getView().byId("genTable").setModel(json);
that.getView().byId("genTable").bindItems("/results",that.oGenQueueTemplate);
Another approach I tried is to use bindItems, it call send the request to odata service, but it doesn't add the parameter top and skip parameter.
oTable.bindItems({
path: "/ViewQueueSet",
model: "sapmodel",
filters: [new Filter("RoleCode", FilterOperator.EQ, "G")],
template: this.oGenQueueTemplate,
// urlParameters: {
// "$top": top,
// "$skip": count
// },
parameters: {
"$top": top,
"$skip": count
}
});
Anyone has any idea about how to implement this functionality?
before I go into detail, please consider using other controls and/or ux patterns. imagine having thousands or millions of elements in backend and user equests to scroll to page 9292929 => for a responsive table (sap.m.Table) you would need to load all elements up to that page. Maybe filtering or some completely different approach could be tha right one.
The correct way to do this is by getting the listbinding and ask it to load more elements. how to ask the binding, may depend on the type of binding as well.
oTable = ... // get a reference on table
oItemsBinding = oTable.getBinding("items");
oItemsBinding.getLength() // will give you total number of elements
oItemsBinding.isLengthFinal() // will tell you if the length is final
oItemsBinding.getCurrentContexts() // will give you array of all loaded contexts.
now a few words to length and the length being final. If you have a binding implementation that knows the total number of objects (e.g. json - since it loads all elements to client, or OData, if cont is implemented in backend) then getLength will tell you the total number of objects.
if the backend doesnt have the count feature implemented, the length becomes final once you reach the end of the list (backend gives you less elements than you require - e.g. top=10,skip=90 returns 10 elements => length 100, not final; top=10,skip=100 returns 4 elements => length=104 becomes final)
Now, you can have a look at various binding implementations. But be aware that there is a lot to consider (direction of growing - upwards/downwards), at least you dont need to think about filtering/sorting - as this is part of the binding.
There is a nice (private) feature in sap.m.Table (or in sap.m.ListBase, to be more precise), which is called GrowingEnablement. you can use it like this:
// dont forget if _oGrowingDelagate is not undefined or similar
oTable._oGrowingDelegate.requestNewPage()
this will load one more page => you could start from reading the implementation of this method if you want to load several pages in one go.
you could also do a simple trick:
// assume you have 20 elements per page (default)
// and want to get to 7th page (elements 121 - 140)
// ckecks for 7th page exists and 7th page not yet loaded are omitted
oTable.setGrowingThreshold(70) // half of 140, so following load will load second page => 71 to 140
oTable._oGrowingDelegate.requestNewPage() // this will load the second page 71 - 140
// once loading is finished (take care of asynchronity)
oItemsBinding.attachEventOnce("dataReceived", function(oEvent){
// reset the growing threshold to 20
oTable.setGrowingThreshold(20)
// scroll to first element of 7th page (index 120, since count starts from 0)
oTable.scrollToInex(120)
})

Laravel excel: read specific rows while using collections

Laravel version: 7.x
I have a test data file of 1161 rows, which needs to be uploaded via ajax and rendered in the editable format, in case of validations failed. So I am using Excel::toCollection(...). But, even with this small amount of data, the application hangs for a while, until the rendering is complete.
To handle this situation I reading only 50 rows at a time, validate and append in the form via ajax. However, it has reduced the load and also decrease the rendering time, but each time I have to read the entire file and get the next chuck out of it.
Here is my code:
$arrayPost = request()->only([
'start',
'limit',
]);
$arrayExcel = \Excel::toCollection(new SubscriberImport(), <uploaded_file_path>);
$arrayExcel = array_slice($arrayExcel, $arrayPost['start'], $arrayPost['limit']);
$validated = $this->validateExcel($arrayExcel);
if($validated->fails())
{
# return with error
return view('<form_path>', [
'arrayExcel' => $arrayExcel,
])->withErrors($validated->getMessageBag()->toArray());
}
else
{
...
}
Is there a way to fetch the specific rows from the file.?

TYPO3: Performance issue with pagination

I am currently building some kind of video channel based on an extension I created. It consists of videos and playlist that contains videos (obviously).
I have to create a page which contains a list of videos AND playlist by category. You also can sort those items by date. Finally, the page is paginated with an infinite scrolling that should load items 21 by 21.
To do so, I created on both Video and Playlist repositories a "findByCategory" function which is really simple :
$query = $this->createQuery();
return $query->matching($query->equals('categorie.uid',$categoryUid))->execute()->toArray();
Once I requested the items I need, I merge them in one array and do my sorting stuff. Here is my controller show action :
if ($this->request->hasArgument('sort'))
$sort = $this->request->getArgument('sort');
else
$sort = 'antechrono';
//Get videos in repositories
$videos = $this->videoRepository->findByCategorie($categorie->getUid());
$playlists = $this->playlistRepository->findByCategorie($categorie->getUid());
//Merging arrays then sort it
if ($videos && $playlists)
$result = array_merge($videos, $playlists);
else if ($videos)
$result = $videos;
else if ($playlists)
$result = $playlists;
if ($sort == "chrono")
usort($result, array($this, "sortChrono"));
else if ($sort == "antechrono" || $sort == null)
{
usort($result, array($this, "sortAnteChrono"));
$sort="antechrono";
}
$this->view->assignMultiple(array('categorie' => $categorie, 'list' => $result, 'sort' => $sort));
Here is my view :
<f:widget.paginate objects="{list}" as="paginatedList" configuration="{addQueryString: 'true', addQueryStringMethod: 'GET,POST', itemsPerPage: 21}">
<div class="videos row">
<f:for each="{paginatedList}" as="element">
<f:render partial="Show/ItemCat" arguments="{item: element}"/>
</f:for>
</div>
</f:widget.paginate>
The partial render shows stuff including a picture used as a cover. So I need at least this relation in the view.
This works fine and shows only the items from the category that is requested. Unfortunatly I have a huge performance issue : I tried to show a category that contains more than 3000 records and It takes about one minute to load. It's a little bit long.
By f:debugging my list variable, I see that it contains every records even through it shouldn't be the case (that's the point of pagination...). So the first question is : is there something wrong in the way I did my pagination ?
I tried to simplify my requests by enabling the rawQuery thing ($query->execute(true)) : I get way better performance, but I can't get the link for the pictures (in my view, I get 1 or 0 but not the picture's uid...). Second question : is there a way to fix this issue ?
I hope my description is clear enough. Thanks for your help :-)
When you execute a query, it will not actually fetch the data from the database until the results are accessed. If the paginate widget gets a query result it will add limits and offset to the query and then fetch the data from the database, so you will only get the records that are shown on a page.
In your case you added toArray() after execute(), which accesses the results, so the data is fetched from the database and you get all records. The best solution I can think of is to combine the 2 tables into 1 so you can do it with a single query and don't have to merge and order them in PHP.
As long as you sort the data after the query you have to handle all data (request all records and especially resolve all relations).
Try to sort the data in the query itself (order by), so you could restrict the data to only those records which are needed for the current 'page' (limit <offset>,<number>).
Here a complex query with join and limit could be faster than a full query and filtering in PHP.

how to get the totalRecords to display during the pagination

Im using the datatables plugin for pagination.
I'm trying to get my server-side pagination working, however to start with, im facing the issue of not been able to display the totalRecords entires in the 'Showing 1 to 15 of 15 entries' text. im using this to display all the records:
var resultsTable = tableEl.dataTable( {
"aaData": tableData,
"aoColumns": tableColumns,
"aaSorting": [[1,'asc']],
// "bServerSide": true,
"processing": true,
"serverSide": true,
"sAjaxDataProp": "api/1.0/accounts",
"bProcessing": true,
"pagingType": "simple_numbers",
"bLengthChange": false,
"bAutoWidth": false,
"bScrollCollapse": true,
"iTotalRecords": 34,
"iTotalDisplayRecords":15,
"iDisplayLength": 15
} );
but it still shows me 'Showing 1 to 15 of 15 entries' instead of 'Showing 1 to 15 of 34 entries'. Any idea what im i missing here?Thanks, in advance!
My understanding is that iTotalRecords and iTotalDisplayRecords are values that are returned from the server, not values that you set during initialisation.
Can you add the code that generates the server-side data? How are you actually paging that source data?
In your accounts method, you should be returning a json object that looks something like this:
return Json(new
{
param.sEcho,
iTotalRecords = totalRecords,
iTotalDisplayRecords = totalFilteredRecords,
aaData = result
}, JsonRequestBehavior.AllowGet);
Where iTotalRecords is the total, unfiltered record count and iTotalDisplayRecords is the filtered record count. result contains 15 rows of data because at this point you will have already performed the paging query using the datatable parameters iDisplayStart and iDisplayLength to generate the data. You now have all the information to correctly display the page when you return this json object to the datatable.

Dgrid-OnDemandGrid Virtualscrolling

I am using Dgrid OndemandGrid with Jsonrest store.On scrolling,I am taking 40 records from the database.
var grid= new OnDemandGrid({
store: jsonstore,
columns: Layout,
minRowsPerPage : 40,
maxRowsPerPage : 40,
loadingMessage: "Loading data...",
noDataMessage: "No results found."
}, "grid");
On first time ,I am getting the response Header as
Content-Range items=0-39/132
.On further scrolling ,the response Header is
Content-Range items=38-78/132 instead of 40-79/132.
Can someone tell me how to get the response as 40-79/132 , 80-119..etc..
Add queryRowsOverlap: 0 to the object you're passing to the grid constructor.
queryRowsOverlap defaults to 1, and is the reason the queries overlap. This property is intended to counteract issues with dojo/store/Observable "dropping" items at page boundaries, though it isn't a perfect solution.

Resources