JQuery AJAX call calls URI multiple times, scales with call - javascript

I have an web page I am creating to display information from a database, the page displays 2 tables, one pending table and one history table. The history table is automatically set to the current day's date. So when someone wants to change the date range to see the history, they change the date using a calendar date picker set up in JavaScript.
In this same file, I have an AJAX call that posts the new date filters. The first time it is clicked while on the page, it makes one call, then the second it makes 2 calls, the third it makes 4 calls, and so on making 2^n calls where n is the click number before refreshing the page.
This also happens with the other AJAX call I have happen which is to update the pending table automatically every 6 seconds.
This image is what the network calls look like when running. The code for this call is:
$(document).ready(function() {
//Enable date picker for id startDate
$("#startDate").datepicker();
//Enable date picker for id endDate
$("#endDate").datepicker();
//Set the datepickers to read only so only the calendar can be used to select a date
$("#startDate").attr({
readOnly: false,
style: "background-color:#FFFFFF"
});
$("#endDate").attr({
readOnly: false,
style: "background-color:#FFFFFF"
});
// update function to update pending table
var update = function() {
$.ajax({
url: "pending",
type: "GET",
dataType: "html",
success: function(data) {
//Replace existing table with data returned from query
$('#pendTable').html(data);
move();
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
window.location.href = "";
}
});
};
// automatically updates the pending table every 6 minutes
setInterval(update, 360000);
//On filter change, submit the filters and update the table div
$('.filter').on('change', function() {
var filterValue = $(this).val(),
startDate = document.getElementById('startDate').value,
endDate = document.getElementById('endDate').value;
$.ajax({
url: "postFilters",
async: false,
type: "POST",
data: $('#filters').serialize(),
dataType: "html",
success: function(data) {
//Replace existing table with data returned from query
$('#histTable').html(data);
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
window.location.href = "";
}
});
});
});
Also on my console it shoes that the call is being made multiple times , I have log inside the controllers to notify me when they are called and they are the same number of times it shows up on the network logs of Chrome.
What is wrong with this? I cannot figure it out.

Related

Calling multiple Ajax functions in conjunction with SetInterval

I have a set of printers associated with different devices. Every 20 seconds I check the status of the printers and display their status (offline, online, out of paper, etc.). User can select a device from a "Devices" dropdown and get status of printers associated with that device; the default on page load is "all devices".
So, there are two parts to getting status: get list of printers for selected device; get status for that list of printers.
To do this I use setInterval function within which I call an Ajax function to get the status.
I am having trouble getting two ajax functions (get device's printers and get printers' status) working in conjunction with setInterval. Getting the list of printers needs to be done once (or until device is changed), getting status needs to be done every 20 seconds.
I think using promise is the way to do it (I could be wrong) but it doesn't work properly. I need some expert assistance.
This is what I have tried but it seems both ajax functions are executed every 20 seconds.
var statusParameters;
var printers = [];
var mpeName;
var v;
var pm;
function printer(idn, hostName, ipAddress) {
this.IDN = idn;
this.HostName = hostName;
this.IPAddress = ipAddress;
}
$(document).ready(function () {
statusParameters = {
interval: 20000,
interval_id: 0,
intervalDetail_id: 0,
};
...
mpeName = ''; // denotes all printers; when user selects a device this value changes
fetchStatusData();
statusParameters.interval_id = setInterval(function () {
fetchStatusData()
}, statusParameters.interval);
// Get list of printers for selected device
pm =
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: 'Services/ps.asmx/GetPrinterMappingCfg',
cache: false,
data: JSON.stringify({ MPEName: mpeName }),
}).done(function (result) {
jResult = JSON.parse(result.d);
$.each(jResult, function (index, value) {
var p = new printer(value.IDN, value.Hostname, value.IPAddress);
printers.push(p);
});
}).fail(function (jqXHR, textStatus, errorThrown) {
alert(textStatus + ' - ' + errorThrown + '\n' + jqXHR.responseText);
});
})
function fetchStatusData() {
// I tried to put the above "pm" right here too
$.when(pm)
.done(function (r1) {
$.each(printers, function (index, value) {
var currPrinter = value;
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: "Services/ps.asmx/GetPrinterStatus",
cache: false,
//data: "",
data: JSON.stringify({ PrinterIPAddress: currPrinter.IPAddress }),
}).done(function (result) {
// initial display or updating of status info
}).fail(function (jqXHR, textStatus, errorThrown) {debugger
...
});
});
printers.length = 0; // because every 20 sec. it retrieves printer list!
}).fail(function (jqXHR, textStatus, errorThrown) {debugger
...
});
The problem I am trying to solve is I want the retrieving of list of printers to be done once, or until user selects a different device not every 20 seconds. It is a waste to keep getting the same printer list every 20 seconds.
Also, the way it is now, on initial page load it does not display printers and their status but will after 20 seconds. It will print on initial load if I move "pm" inside of "fetchStatusData" function.
Update
I think I might not have explained what I am trying to do properly. Basically, this is what I am after:
Given list of devices in a dropdown list, with "All Devices" selected on page load
Get list of printers for selected device from dropdown
Repeat the following every 20 seconds
Get status of each printer in list of printers
When user selects a new device, get list of printers again
I was thinking another way might be to create a array of "device" objects, each having an array of printer objects in addition to other properties like DeviceID, etc.
This is done only once on document.ready(). Then when a new device is selected, I already have the list of printers and can get it that way. Still would get stuck in setInterval portion of it.

jQuery - Add row to datatable without reloading/refreshing

I'm trying add data to DB and show these data in same page using ajax and jQuery datatable without reloading or refreshing page. My code is saving and retrieving data to/from database. But updated data list is not showing in datatable without typing in search box or clicking on table header. Facing same problem while loading page.
Here is my code
//show data page onload
$(document).ready(function() {
catTable = $('#cat_table').DataTable( {
columns: [
{ title: "Name" },
{ title: "Level" },
{ title: "Create Date" },
{ title: "Status" }
]
});
get_cat_list();
});
//save new entry and refresh data list
$.ajax({
url: 'category_save.php',
type: 'POST',
data:{name: name,level: level},
success: function (data) {
get_cat_list();
},
error: function (data) {
alert(data);
}
});
//function to retrieve data from database
function get_cat_list() {
catTable.clear();
$.ajax({
url: 'get_category_list.php',
dataType: 'JSON',
success: function (data) {
$.each(data, function() {
catTable.row.add([
this.name,
this.level,
this.create_date,
this.status
] );
});
}
});
}
The solution is here - for DataTable server side data source enabled
.draw() will cause your entire datatable to reload, say you set it to show 100 rows, after called .row().add().draw() > datatable will reload the 100 rows again from the server
I wasted an hour trying to find any solution for this very old question, even on DataTable official support there is no good solution suggested ...
My solution is
1- call .row().add()
2- do not call .draw()
3- your row must have an Id identifier to use it as a selector (check the rowId setting of the datatable)
4- after calling .row().add(), the datatable will have the row added to it's local data
5- we need to get this row from datatable object and transform it to HTML using the builtin method .node()
6- we gonna prepend the result HTML to the table :)
All that can be done in two lines of code
var rowData = someRowCreatedByAnAjaxRequest;
myDataTableObject.row.add(rowData);
$("#myTable-dt tbody").prepend(myDataTableObject.row(`tr#${rowData.Id}`).node().outerHTML)
Thanks ☺
From the documentation,
This method will add the data to the table internally, but does not
visually update the tables display to account for this new data.
In order to have the table's display updated, use the draw() method, which can be called simply as a chained method of the row.add() method's returned object.
So you success method would look something like this,
$.each(data, function() {
catTable.row.add([
this.name,
this.level,
this.create_date,
this.status
]).draw();
});

Calling a function on JQUERY success

I have a custom function that I have defined and then I subsequently call when the the page loads. I need the function to run when the page loads because it is populating a group selectlists:
<!---Populate Custom Service Description select lists --->
<script type="text/javascript">
function PopulateSelectLists(){
// Important: Must append the parameter "&returnformat=json"
$.ajax({
url: 'cfcs/get_descriptions.cfc?method=getDescriptions&returnformat=json'
, dataType: 'json'
, success: function(response){
$.each(response.DATA, function(I, row){
// get value in first column ie "description"
var description = row[0];
// append new option to list
$("#descriptionDD1").append($('<option/>', {
value: description,
text : description
}));
$("#descriptionDD2").append($('<option/>', {
value: description,
text : description
}));
$("#descriptionDD3").append($('<option/>', {
value: description,
text : description
}));
$("#descriptionDD4").append($('<option/>', {
value: description,
text : description
}));
});
},
error: function(msg){
console.log(msg);
}
})
}
$(document).ready(PopulateSelectLists);
</script>
I am trying to call my custom function PopulateSelectLists() when another AJAX call successfully completes so I can refresh my selectlists but it never seems to call my function:
<!---Script to add new description to DB --->
<script>
$(function(){
//Add a new note to a link
$("#addDescriptionForm").submit(function(){
// prevent native form submission here
$.ajax({
type: "POST",
data: $('#addDescriptionForm').serialize(),
url: "actionpages/add_descriptions_modal.cfm",
success: function() {
PopulateSelectLists(); //Call Function to refresh selectlist
$("#addDescriptionResponse").append( "Successfully added description." );
}
});
return false;
});
});
</script>
Where am I going wrong here?
In the problematic case, does the request actually return successfully? Inspect the response with Firebug or Fiddler or whatever dev toolbar you are using. It may be that there is a server error, a connection error, or any other reason that can drop the request, so it is not successful.
You can also look into using the complete handler: http://api.jquery.com/jquery.ajax/.

pass paremeter through .load from previous ajax call

Tearing my hair out on this one.... sure it just the structure of my function.
Basically I make a Ajax call within an Ajax loaded tab. The call made within writes a record to the Database and returns a value. I can alert the value fine but when I try to use it as a data parameter in my .load() call it doesn't get passed?
As they are in the same success function I just thought (Stupidly?) that I could easily reference it!
$('#convert-2-booking').click(function(e) {
var quoteid = $(this).attr("title");
$.ajax({
type: "POST",
url: 'tabs/convert-2-booking.asp?Planner_ID='+$('#convert-2-booking').attr("title")+'',
data: quoteid,
cache: false,
dataType: "html",
success: function(responseText){
var ajax_load = "<img class='loading' src='images/load.gif' alt='loading...' />";
var loadUrl = "tabs/booking.asp";
bookingid = responseText;
//above gets correct returned id.
$("#bookingtab").html(ajax_load).load(loadUrl, { 'bookingid': bookingid } ); // not here though :(
alert(bookingid) // alerts the correct id here too!
setTimeout(function() {
     
// move to bookings tab after 3 seconds
$("#tabs").tabs( "option", "active", 3 );
// load correct record into tab
}, 3000);
},
error: function(responseText){
alert("NOT:"+responseText);
//alert(responseText);
$("#tabs").tabs( "option", "active", 2 ); //load previous tab itself if returns error..
},
});
});
Try passing it via "booking.asp?bookingid=..."
Like this:
.load(loadUrl+"?bookingid="+bookingid)
It's a workaround tho; I'm not sure why load() doesn't do the same thing thru your array... Maybe it's because you only check GET variables on server side and load() gives you POST...?
ended up deciding to store the id in a session for the few seconds i need it. Not ideal, but a workaround for now, and enough to allow me to demo to my client.

Chrome issue - chat lines return multiple times

I wrote a little chat plugin that i'll need to use on my site. It works with a simple structure in HTML, like this:
<div id="div_chat">
<ul id="ul_chat">
</ul>
</div>
<div id="div_inputchatline">
<input type="text" id="input_chatline" name="input_chatline" value="">
<span id="span_sendchatline">Send</span>
</div>
There's a 'click' bound event on that Span element, of course. Then, when the user inserts a message and clicks on the "Send" span element, there's a Javascript function with calls an Ajax event that inserts the message into the MySQL database:
function function_write_newchatline()
{
var chatline = $('#input_chatline').val();
$.ajax
({
type: "POST",
url: "ajax-chat-writenewline.php", //1: ok, 0: errore
data: ({'chat_line': chatline}),
dataType: "text",
cache: false,
success: function(ajax_result)
{
function_get_newchatlines();
}
});
}
And, in case the message is successfully inserted into DB, it calls a function to read new lines and put them in HTML structure i posted before:
function function_get_newchatlines()
{
$.ajax
({
type: "POST",
url: "ajax-chat-loadnewlines.php", //1: ok, 0: errore
data: '',
dataType: "text",
cache: false,
success: function(ajax_result) //example of returned string: 'message1>+<message2>+<message3'
{
//explode new chat lines from returned string
var chat_rows = ajax_result.split('>+<');
for (id_row in chat_rows)
{
//insert row into html
$('#ul_chat').prepend('<li>' + chat_rows[id_row] + '</li>');
}
$('#span_sendchatline').html('Send');
}
});
}
Note: 'ajax_result' only contains html entities, not special chars, so even if a message contains '>+<', it is encoded by the php script called with Ajax, before being processed from this JS function.
Now, comes the strange behaviour: when posting new messages Opera, Firefox and even IE8 works well, as intended, like this:
But, when i open Chrome window, i see this:
As you can see, in Chrome the messages are shown multiple times (increasing the number each time, up to 8 lines per message). I checked the internal debug viewer and it doesn't seem that the "read new lines" function is called more than one time, so it should be something related to Jquery events, or something else.
Hope i've been clear in my explanation, should you need anything else, let me know :)
Thanks, Erenor.
EDIT
As pointed out by Shusl, i forgot to mention that the function function_get_newchatlines() is called, periodically, by a setInterval(function_get_newchatlines, 2000) into Javascript.
EDIT2
Here's is a strip of the code from the PHP file called by Ajax to get new chat lines (i don't think things like "session_start()" or mysql connection stuff are needed here)
//check if there's a value for "last_line", otherwise put current time (usually the first time a user logs into chat)
if (!isset($_SESSION['prove_chat']['time_last_line']) || !is_numeric($_SESSION['prove_chat']['time_last_line']) || ($_SESSION['prove_chat']['time_last_line'] <= 0))
{
$_SESSION['prove_chat']['time_last_line'] = microtime(true);
}
//get new chat lines
$result = mysql_query("select * from chat_module_lines where line_senttime > {$_SESSION['prove_chat']['time_last_line']} order by line_senttime asc; ", $conn['user']);
if(!$result || (mysql_num_rows($result) <= 0))
{
mysql_close($conn['user']); die('2-No new lines');
}
//php stuff to create the string
//....
die($string_with_chat_lines_to_be_used_into_Javascript);
Anyway, i think that, if the problem was this PHP script, i would get similar errors in other browsers, too :)
EDIT4
Here's the code that binds the click event to the "Send" span element:
$('#span_sendchatline').on('click', function()
{
//check if there's already a message being sent
if ($('#span_sendchatline').html() == 'Send')
{
//change html content of the span element (will be changed back to "send"
//when the Ajax request completes)
$('#span_sendchatline').html('Wait..');
//write new line
function_write_newchatline();
}
//else do nothing
});
(Thanks to f_puras for adding the missing tag :)
I would do one of the following:
option 1:
stop the timer just before the ajax call in function_write_newchatline() and start the timer when the ajax call returns.
function function_write_newchatline()
{
var chatline = $('#input_chatline').val();
stop_the_timer();
$.ajax
({
type: "POST",
url: "ajax-chat-writenewline.php", //1: ok, 0: errore
data: ({'chat_line': chatline}),
dataType: "text",
cache: false,
success: function(ajax_result)
{
function_get_newchatlines();
},
complete: function() {
start_the_timer();
}
});
}
option 2:
Not call function_get_newchatlines() at all in the success event of the ajax call. Let only the timer retrieve the chat entries.
function function_write_newchatline()
{
var chatline = $('#input_chatline').val();
$.ajax
({
type: "POST",
url: "ajax-chat-writenewline.php", //1: ok, 0: errore
data: ({'chat_line': chatline}),
dataType: "text",
cache: false,
success: function(ajax_result)
{
// do nothing
}
});
}
I think there is some race condition between the function_get_newchatlines() that is called after a chat entry is added by the user and the periodical call of function_get_newchatlines() by the timer.
option 3:
Use setTimeout instead of setInterval. setInterval can mess things up when the browser is busy. So in the end of the setTimeout function call setTimeout again.

Categories