Jquery datatable: add rows from database in a loop - javascript

I have a page that makes an Ajax call to a database on page load. It returns a list of companies that the user is following and then iterates the list trough and does another Ajax call to each company, to get some statistics about them. The statistics are then added to a Datatable which is being drawn quite a few times:
var table = $("#example").DataTable();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "../json/stats.aspx?t=followed-companies",
dataType: "json",
success: function (data) {
for (i = 0; i < Object.keys(data).length; i++) {
$.ajax({
type: "POST",
async: true,
contentType: "application/json; charset=utf-8",
url: "../json/stats.aspx?t=company-stats" + "&n=" + data[i]
}).done(function (dataSecondary) {
var stringtest = "<tr><td>" + dataSecondary.Stats1 + "</td>" +
"<td>" + dataSecondary.Stats2 + "</td>" +
"<td>" + dataSecondary.Stats3 + "</td>" +
"<td>" + '<button type="button" id="delete" class="btn btn-danger btn-xs dt-delete">' + "Delete" + "</td></tr>";
table.row.add($(stringtest)).draw();
});
}
},
error: function (xhr) {
console.log('error', xhr);
}
});
I do not have much experience in programming, but I do know that this takes ages to load and so has a very poor performance.
Main question is, can I use the table.draw(); after I have added the rows in that loop? I guess that could save some time. I tried to draw the table after the loop is finished but the table said that there is no data to show.
Second question, is this bad practise (mainly those nested Ajax calls with loops and SQL queries), and should I try to unify as many SQL queries as possible?

JSFiddle example - Get Post Data using ajax and display in .dataTable()
Main question is, can I use the table.draw(); after I have added the rows in that loop?
Yes you can. If you look at the docs of datatables you'll see that the draw() function is made for that.
When you perform an action such as adding or deleting a row, changing
the sorting, filtering or paging characteristics of the table you'll
want DataTables to update the display to reflect these changes. This
function is provided for that purpose.
Second question, is this bad practise (mainly those nested Ajax calls with loops and SQL queries), and should I try to unify as many SQL queries as possible?
Yes it's bad practice to have many calls going to your backend. If you have control over the backend, you should aim to optimise it. For example: When you supply a list of companies, it will return the stats for all those companies specified.
Currently it will especially be a bad experience for those with a slow internet connection e.g. mobile users.
Also, this solution doesn't scale well. Imagine your website taking off and 100s of individuals are using it simultaneously. That means 100 * amount-of-followed-companies calls, while with the suggested it would be 100 calls to the backend for fetching the same data.
Have you also considered the possibility to generate a table using ajax sourced data.
UPDATE:
As for the draw() function that is not working. According to the docs, you provide the data structure without actually building the table with html yourself. Use the data returned instead where columnNameX is the name of the columns you specified. Give this a try in your .done().
var data = {
columnName1: dataSecondary.Stats1
columnName2: dataSecondary.Stats2
columnName3: dataSecondary.Stats3
}
table.row.add(data).draw();
As for generating the button. I haven't worked with them before but you can find more about them here.

Related

Best Practice For Storing/Reusing Ajax Responses

I'm developing a spring boot application where on certain pages I have onclick triggers which use AJAX to make requests to obtain data from my database. For example, when a user clicks on a group in the main menu, AJAX will make a request to pull this group and dynamically display it on the JSP page as follows.
$(document).ready(function () {
$(document).on("click", ".group", function () {
var groupName = $(this).text();
$(".groups").hide();
$.ajax({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
type: "GET",
url: "/viewGroup",
data: {"groupName": groupName},
success: function(result){
var members = result["groupMembers"];
$(".focusContainer").append('<div class="groupView">' +
'<p>'+result["groupName"]+'</p>' +
'</div>');
$.each(members, function(index, value){
$(".groupView").append('<p>Group Members</p>'+
'<p>'+members[index]["username"]+'</p>');
});
$(".groupView").append('<button class="button addButton" id="addFocus" type="button" onclick="addFocus()">Add A Focus</button>'+
'<div class="break"></div>'+
'<button class="button cancelGroup" id="deleteGroup" type="button" onclick="cancelGroup()">Delete Group</button>');
}
})
});
});
Additional buttons are generated (addFocus) which can for example add members or target goals to said group, however these must be retrieved from the database as only members or goals related to these groups should be able to be added to them.
What is the best practice for retrieving this data after the group is initially selected (After the first AJAX request retrieving the Group data)? Should the members/goals of the group be appended into some hidden div and shown when the relevant buttons are clicked? Should I make another AJAX request when the add focus/member button is clicked? Or should the response of the initial request be stored in a global variable and used by the other .onclick triggers? I'm unsure of what issues could be encountered if storing the response globally in my .js file.
Currently I'm doing a new request for each click but I imagine in production this would become very taxing on the server and cause slow speeds. I've also seen a lot of mention about making asynch:false however there appears to be a lot of debate about whether this is a good design choice or not. Any guidance would be appreciated.

Displaying Image as a result of operations with Flask and AJAX

I'm currently working on a project, in which an explainable AI library for CNN image recognition (https://github.com/albermax/innvestigate) is meant to be implemented in a web-service. Now, I found a good looking template, which involved general image recognition back- & frontend, based on Flask (https://github.com/OkanKY/keras-flask-webapp).
I managed to implement the library, but do not manage to display the resulting plot-image on the web-service. This is what I tried:
Python/Flask Code:
#app.route('/predictResNet50', methods=['GET', 'POST'])
def predictResNet50():
if request.method == 'POST':
file_path = get_file_path_and_save(request)
...
plt.savefig(file_path[:-4] + explainer + "Plot.jpg")
fullPlotFilename = file_path[:-4] + explainer + "Plot.jpg"
...
return fullPlotFilename
By that, the plot image is perfectly stored in the static/images library. The corresponding JavaScript code, which invokes the API, looks like this:
$.ajax({
type: 'POST',
url: '/predictResNet50',
data: form_data,
contentType: false,
cache: false,
processData: false,
async: true,
success: function (data) {
// Get and display the result
$('.loaderResNet50').hide();
// $('#resultResNet50').fadeIn(600);
// $('#resultResNet50').text(' Result: ' + data1);
$('#plotResNet50').show();
$('#plotResNet50').html('<img src="' + data + '">');
console.log('ResNet50 Success!');
},
});
Before the modifications, the result of the prediction was displayed (out-commented part). Now, the plot image is supposed to be displayed. Ideally, the result plus the prediction would be the goal, but for now, the plot would be sufficient. But this does not work for some reason. The correct value is returned to the API call in JS, but only the image adress, not the actual image is presented.
HTML Script:
<div id="plotResNet50">
</div>
Could somebody tell me, what I'm missing? Since I'm not too experienced with JQuery, help would be greatly appreciated!!
Link to the current GitLab Repo can be provided, if the stated information is not sufficient.
The function html() is not the appropriate function to be used if you intend to add an element to HTML using JQuery.
Instead use:
$('#plotResNet50').prepend('<img src="' + data + '">')

Wikipedia API search -- Retrieve same index of each array with forEach?

I'm working on a project for freeCodeCamp and I've been stuck on this part all day. I'm pulling data from the Wikipedia API and I'm able to work with it, yet I'm not sure how the syntax should look for what I'm trying to achieve. Here is a link to an example of the data I'm working with. Wikipedia API Search.
Now, in my HTML I have a bootstrap modal that appears after the user inputs something into a form, with a listed group inside with the returned data from the search.
This is the code I have so far.
$(document).ready(function () {
$('#searchForm').on('submit', function(e) {
e.preventDefault();
$('#wikiSearch').modal('show');
var usersearch = document.getElementById('userinput').value;
var apiURL = "https://en.wikipedia.org/w/api.php?
action=opensearch&search="
+ usersearch + "&format=json&callback=?";
$.ajax({
url: apiURL,
contentType: "application/json; charset=utf-8",
dataType: 'json',
type: 'GET',
success: function (data) {
data[1].forEach(function(item) {
$('#results').append("<tr><td><a href='#'>"+item+"</a></td></tr>")
});
data[2].forEach(function(item) {
$('#brief').append("<tr><td>"+item+"</td></tr>")
})
}
});
});
});
For each group in my modal of my HTML I want to display 1 result from the search. I figured I would be able to use a nested forEach but it's not returning the results I wanted. I've tried using map, and also tried creating a long nested for loop and feel like I might be doing more harm than good when it comes to learning since I'm only getting confused now lol. Thanks for any input.
To show the first row from the search results use the first key of the nested array:
$('#results').append("<tr><td><a href='#'>" + data[1][0] + "</a></td></tr>")
$('#brief').append("<tr><td>" + data[2][0] + "</td></tr>")
Don't forget to add a check for the possible undefined value inside the data array.

Post HTML Table to Controller

I have a form where users can dynamically add entries to a html table from a dropdownbox. Each entry is added as its own row. This is fairly easily done in javascript:
function addProduct(int type) {
var product = getProduct(type); // The method just fetches the product from the database
$('selectedProductsTable').append("<tr><td>" + product.Name +"</td><td>" + product.Quantity + "</td></tr>")
}
In a second step the contents of the table need to be posted to the controller for further processing. What is the general best practice to get the products i've added as table rows? I could iterate over the rows of the selectedProductsTable but that seems somewhat error prone.
On the other hand i would be open to another way to persist the selected items so that i can post them to the controller. Unfortunately saving them in the session or in the tempData is also not a good option since the selection takes place completely in javascript.
Only INPUT and SELECT elements get posted back to the server, so you need to store each value in hidden fields to make it back. You can use the index-based approach to post back an array, which works well. See this post.
I wrote up a blog post about dynamic client-side lists, which might be helpful. It uses Kendo Core but that would not be required.
In your method addProduct populate array with data about products:
var products=[];
function addProduct(int type) {
var product = getProduct(type); // The method just fetches the product from the database
products.push(product)
$('selectedProductsTable').append("<tr><td>" + product.Name +"</td><td>" +
product.Quantity + "</td></tr>")
}
and later send it with ajax:
$.ajax({
url: 'your url',
type: 'POST',
dataType: 'json',
success: function (data) {
//TODO
},
data: JSON.stringify(products)
});

multiple ajax calls is causing mixed datasets

I've been developing a phonegap application which uses jQuery Mobile for it's main structure.
When the site/app runs, it executes a number of ajax calls to get the latest data to the app. For example, a list of items is gathered for the homepage, whilst other lists of other items are gathered for other pages.
What I am finding is that every now and then there is a mixup in data.
As a random (but applicable) example:
Query 1 - get names and photos of people
Query 2 - get names and photos of cities/locations
In each of the ajax calls, instead of using (data, status) I have renamed the data object to a unique identifier hoping this would resolve the issue.
Then, on my $.each function I have ensured that the iterator has a different name too, so instead of (i, item) it might be (i, personitem) and (i, cityitem)
The Issue
Despite my best attempts to get this data to not have any possibility of crossover, I'm finding that (to keep with the current example) - photos of people will show up on the cities page, and photos of cities will show up on the users page.
This is also an intermittent issue. Sometimes it won't happen at all, other times it will happen a lot or only a little bit.
I hope I have explained myself clearly. Thank you in advanced to anyone willing to help! I'm all out of ideas :-(
==================
UPDATE
My main question is if anyone knows what might cause data-mixups in such queries.
My queries all look like this:
$.ajax({
url: 'get_cities.php?country='+country,
dataType: 'jsonp',
jsonp: 'jsoncallback',
timeout: 5000,
success: function(citydata, status){
if(citydata.length == 0){
$('#somediv').append('no data to show');
}
$.each(citydata, function(i,cityitem){
var content = '<img src="'+cityitem.image+'" />'
+'<p>'+cityitem.name+'</p>';
$('#somediv').append(content);
}
});
At this point I believe #mason81 was correct with his suggestion.
I removed all of the:
jsonp: 'jsoncallback',
in my code, and then updated my PHP files to use
echo $_GET['callback'] . '(' . json_encode($records) . ');';
instead of
echo $_GET['jsoncallback'] . '(' . json_encode($records) . ');';
I originally also placed &callback=? into my URL's but from reading the jQuery Ajax documentation it should automatically assign a random unique callback to each call as long as you are using dataType: jsonp without manually specifying a callback parameter.
If this fails I'll still consider this the correct answer, I'll probably just have to go through and either assign unique callback parameters to each request or ammend my URL's with &callback=? as mentioned above.
Thanks everyone for their input!

Categories