How to restart recursive function in JS using setTimeout and clearTimeout? - javascript

I am trying to build simple chat module in CodeIgniter.
var last_id = 1;
$(document).ready(function(){
loadMsgs();
$("#content").focus();
$("form#chatform").submit(function(){
$.post("<?php echo base_url() ?>index.php/msg/update",{
message: $("#content").val(),
con_id: <?php echo $con['conversation_id'] ?>
}, function(){
$("#content").val("");
$("#content").focus();
loadMsgs();
});
return false;
});
});
function loadMsgs() {
$.getJSON('<?php echo base_url() ?>index.php/msg/backend/<?php echo $con['conversation_id'] ?>/' + last_id, function(json) {
$.each(json, function(i,val){
//console.log(val.id);
if(<?php echo $login_id ?> == val.sender_id){
$("#messagewindow").append('<div class="bubble"><p>' + val.msg + '</p></div>');
} else {
$("#messagewindow").append('<div class="bubble bubble-right"><p>' + val.msg + '</p></div>');
}
});
updateScroll();
var newIndex = json.length-1;
if(typeof(json[newIndex]) != 'undefined'){
last_id = json[newIndex].msg_id;
}
setTimeout('loadMsgs()', 4000);
});
}
function updateScroll(){
var element = document.getElementById("messagewindow");
element.scrollTop = element.scrollHeight;
}
I have function loadMsgs that use $.getJSON to call for controller that grabs last messages from database and then append them to #messagewindow. Last thing in callback is setTimeout so hat is updated every 4 seconds.
On submit action I post new message to controller and in callback call loadMsgs again. As a result of that every time I submit new message additional call is added which is not good.
I tried to clearTimeout adding global variable id, changed var id = setTimeout('loadMsgs()', 4000); and added clearTimeout(id); before calling loadMsgs again after submiting another message. However nothing changes.

If you have a global variable id, and then in your handler you're calling
var id = setTimeout('loadMsgs()', 4000);
you're never touching the global id.
By having var again in your handler, you're defining another (and another...) copy of id, setting a timeout on each. Var defines a NEW variable, and it looks like you're doing that repeatedly. Take out the var in the handler:
clearTimeout(id);
id = setTimeout('loadMsgs()', 4000);

A simple way to solve this, is to pass an argument to loadMsgs when you call it upon submit. Then you test the presence of this argument. If it is present, don't call setTimeout:
$("form#chatform").submit(function(){
// ...
loadMsgs(1);
// ...
});
function loadMsgs(submitting) {
// ...
if (!submitting) setTimeout(loadMsgs, 4000);
// ...
}

What happens if you remove loadMsgs() from the submit action and leave it up to the 4 second JSON to auto-populate the new message?
Maybe use JS to create a dummy container of a new message from the submit but then clear that dummy element when new JSON is captured?

Related

More than 1 ajax function being called at once, PHP, AJAX

I have a working ajax function that when called will display the current time, and then setTimeout for ten seconds before displaying the new time. I call this function when onkeyup is triggered on an text input, and it works. But there is a slight problem. If I type something else in the text input after the ajax function has already been called, it'll call another ajax function, and have two ajax functions running at the same time. For example:
If the first ajax function was called at 3:00:00 when it was triggered, and the second ajax function is called at 3:00:05, that means that there are now two ajax functions running at the same time. The first ajax function will be triggered again at 3:00:10, after the 10 second setTimeout, and the second ajax function will be triggered again at 3:00:15, after its 10 second setTimeout. So the more times you trigger the onkeyup in the text input, the more times the function will be called. I just want 1 function of itself to be running at the same time, not 2, 3, or more. How do I do that? Thanks.
ajax.php
<script type = "text/javascript">
function timeoutAjax(url,type,theName,id,timeout) {
$.ajax({
type: "POST",
url: url,
data: { select: $(type+'[name='+theName+']').val()},
error: function(xhr,status,error){alert(error);},
success:function(data) {
document.getElementById( id ).innerHTML = data;
setTimeout(function() { timeoutAjax(url,type,theName,id,timeout); }, timeout);
}
});
}
</script>
test1.php
<?php
include('ajax.php');
echo "<input type = 'text' name = 'name' onkeyup = 'timeoutAjax(\"test2.php\",\"input\",\"name\",\"output1\",\"10000\")'>";
echo "<div id = 'output1'/>";
?>
test2.php
<?php
$time = date('H:i:s A');
echo $time;
?>
************MORE DETAILS************
echo "<input type = 'submit' name = 'name1' value = 'Reset' onclick = 'timeoutAjax(\"test2.php\",\"input\",\"name1\",\"output1\",\"10000\")'>";
echo "<input type = 'submit' name = 'name2' value = 'Reset' onclick = 'timeoutAjax(\"test2.php\",\"input\",\"name2\",\"output2\",\"10000\")'>";
echo "<div id = 'output1'/>";
echo "<div id = 'output2'/>";
If I understand your question correctly, you actually trying to achieve two things here:
1. Only the last ajax call
After the last key stroke, do some ajax call. Any ajax call that is already busy can be skipped, you are just interested in the last one.
This should not be to hard. jQuery returns an xhr object when you call the ajax function. On that xhr object, you can just call the abort() method to cancel a pending call. (Abort Ajax requests using jQuery)
2. Repeat the ajax call every x time
Right now you set a timeout in your ajax success function that will just repeat the call after a given time. Problem is that when you call your ajax function again from the outside (so not recursively I mean, but by another keystroke or something) you will just create another infinite string of ajax calls. After a while you'll end up with a huge queue of calls that will start to overlap and eat up all your resources.
This can easily be solved by storing the result of that setTimeout in a variable, and calling clearTimeout on that variable each time before you set a new timeout. This way you cancel the old 'queue' and just start a new one.
So enough poor english, let's try to show what I mean by updating your code:
function timeoutAjax(url, type, theName, id, timeout, trigger) {
// abort pending calls
if (trigger.xhr) {
trigger.xhr.abort();
}
// abort queued calls
clearTimeout(trigger.queued);
// make the call
trigger.xhr = $.ajax({
type: "POST",
url: url,
data: {
select: $(type + '[name=' + theName + ']').val()
},
error: function (xhr, status, error) {
alert(error);
},
success: function (data) {
document.getElementById(id).innerHTML = data;
// queue a new call
trigger.queued = setTimeout(function () {
timeoutAjax(url, type, theName, id, timeout, trigger);
}, timeout);
}
});
}
Just one more sidenote. Even with the changes I made to your code, you will be aborting and making a new ajax call on every key stroke. And aborting an ajax call does not automatically mean your server stops handling the request, depnding on what backend you are using. For the simple php script you are using now it is probably fine, but still, it is probably better to wait until the user is done with typing before you make your first call. This is called Debouncing and isn't very hard to implement either: http://davidwalsh.name/javascript-debounce-function
Create a status variable that tracks if the ajax call is running. Set it to false initially. Then when the function is called, check the status; if not running execute the ajax call, set the status var to true, then set it to false again in the success callback:
<script type = "text/javascript">
//Create the status var (This may not be the best place to initialize it). Use your best judgement.
var running = false;
function timeoutAjax(url,type,theName,id,timeout) {
//Check if there is an ajax call in progress. If not execute one.
if(!running)
{
//Change the status to running
running = true;
console.log('In if')
console.log(running)
$.ajax({
type: "POST",
url: url,
data: { select: $(type+'[name='+theName+']').val()},
error: function(xhr,status,error){alert(error);},
success:function(data) {
document.getElementById( id ).innerHTML = data;
setTimeout(function() {
//Set the status to false for the inner function call
running = false;
timeoutAjax(url,type,theName,id,timeout);
//Set the status to true for the outer function call
runnng = true;
}, timeout);
}
});
}
}
</script>
The outer function which triggers the first ajax call and the timeout will only be run once,; however, the inner function will run every ten seconds continuously.
I hope this works for you, If so, please accept this answer. Thanks

how to refresh dynamically generated divs using ajax?

I am generating dynamic divs and need to refresh them every 10 seconds.
Earlier I used meta refresh but didn't like the flickering of page.
I have tried to insert the ajax code but got failed.
below is my code without ajax,please tell me how and where to insert the ajax refresh code.
$(document).ready(function (){
var n = 9;
for(var i=0; i<n; i++){
var div = document.createElement('div');
div.className = "d5";
div.id=i+1;
// alert(div.id);
document.getElementById('container').appendChild(div);
$.ajax({
async : false,
url : 'myapi.php', //the script to call to get data
data : "", //you can insert url argumnets here to pass to api.php for example "id=5&parent=6"
dataType : 'json', //data format
success : function(data){ //on recieve of reply
var Name = data[2];
var subdomain = data[15];
var uniqueid = data[1];
var shop_photo = data[3];
var offer = data[19]; //get id
//var vname = data[1]; //get name
//$('#'+div.id).html("<a href='http://www."+subdomain+".shoppinonline.com'>"+Name+"</a>");
//$('#'+div.id).html("<img class='shopperspic' src='b2b/shop_image/"+uniqueid+"/"+shop_photo+"' alt='' /><a href='http://www."+subdomain+".shoppinonline.com'>"+Name+"</a><br>Special Offer<br><p>"+offer+"</p>");
if(offer == ""){
$('#'+div.id).html("<div class='div1'><img class='shopperspic' src='b2b/shop_image/"+uniqueid+"/"+shop_photo+"' alt='' /></div><div class='div2'><a href='http://www."+subdomain+".shoppinonline.com'>"+Name+"</a></div></div>");
}else{
$('#'+div.id).html("<div class='div1'><img class='shopperspic' src='b2b/shop_image/"+uniqueid+"/"+shop_photo+"' alt='' /></div><div class='div2'><a href='http://www."+subdomain+".shoppinonline.com'>"+Name+"</a></div><div class='div3'>Special Offer<br class='br_special'>"+offer+"</div></div>");
}
}
});
}
});
First, enclose your existing code(loop and the ajax call) in a function. You can then create a setTimeOut loop using recursion and get your function called every 10 seconds .
$(document).ready(function(){
timeout();
function timeout() {
setTimeout(function () {
//Call the function that makes the ajax request
//This code will re-execute after every 10 seconds
timeout();
}, 10000);
}
});
Also, doing async: false, you are actually abusing the very nature of ajax calls. It will block your script until the request has been fulfilled.
Cheers!
Set A timer Of Ten Second And Call Ajax Method Inside That I think This Will Solve Your Problem

Set a delay in a repeating jQuery / Ajax function

I am trying to add a delay to a repeatable query.
I found out that .delay is not the one to use here. Instead, I should go with setInterval or setTimeout. I tried both, without any luck.
Here's my code:
<?php
include("includes/dbconf.php");
$strSQL = mysql_query("SELECT workerID FROM workers ORDER BY workerID ASC");
while($row = mysql_fetch_assoc($strSQL)) {
?>
<script id="source" language="javascript" type="text/javascript">
$(setInterval(function ()
{
$.ajax({
cache: false,
url: 'ajax2.php',
data: "workerID=<?=$row['workerID'];?>",
dataType: 'json',
success: function(data)
{
var id = data[0]; //get id
var vname = data[1]; //get name
//--------------------------------------------------------------------
// 3) Update html content
//--------------------------------------------------------------------
$('#output').html("<b>id: </b>"+id+"<b> name: </b>"+vname);
}
});
}),800);
</script>
<?php
}
?>
<div id="output"></div>
The code works fine, it outputs the result as asked. It's just loads without the delay. The timout and / or interval doesn't seem to work.
Anybody knows what I am doing wrong?
I've never understood why people always add their AJAX requests in intervals rather than letting the successful AJAX calls just call themselves, all the while risking severe server load through multiple requests and not just making another call once you had a successful one come back.
In this light, I like to write solutions where the AJAX calls just call themselves on completion, something like:
// set your delay here, 2 seconds as an example...
var my_delay = 2000;
// call your ajax function when the document is ready...
$(function() {
callAjax();
});
// function that processes your ajax calls...
function callAjax() {
$.ajax({
// ajax parameters here...
// ...
success: function() {
setTimeout(callAjax, my_delay);
}
});
}
I hope this makes sense! :)
Update:
After reviewing this again, it's been brought to my attention that there was also a problem in the PHP code in the original question that I needed to clarify and address.
Although the script above will work great in creating a delay between AJAX calls, when added to the PHP code in the original post the script will just be echo'd out as many times as the number of rows the SQL query selects, creating multiple functions with the same name and possibly making all AJAX calls simultaneously...not very cool at all...
With that in mind, I propose the following additional solution - create an array with the PHP script that may be digested by the JavaScript one element at a time to achieve the desired result. First, the PHP to build the JavaScript array string...
<?php
include("includes/configuratie.php");
$strSQL = mysql_query("SELECT workerID FROM tWorkers ORDER BY workerID ASC");
// build the array for the JavaScript, needs to be a string...
$javascript_array = '[';
$delimiter = '';
while($row = mysql_fetch_assoc($strSQL))
{
$javascript_array .= $delimiter . '"'. $row['workerID'] .'"'; // with quotes
$delimiter = ',';
}
$javascript_array .= ']';
// should create an array string, something like:
// ["1","2","3"]
?>
Next, the JavaScript to digest and process the array we just created...
// set your delay here, 2 seconds as an example...
var my_delay = 2000;
// add your JavaScript array here too...
var my_row_ids = <?php echo $javascript_array; ?>;
// call your ajax function when the document is ready...
$(function() {
callAjax();
});
// function that processes your ajax calls...
function callAjax() {
// check to see if there are id's remaining...
if (my_row_ids.length > 0)
{
// get the next id, and remove it from the array...
var next_id = my_row_ids[0];
my_row_ids.shift();
$.ajax({
cache : false,
url : 'ajax2.php',
data : "workerID=" + next_id, // next ID here!
dataType : 'json',
success : function(data) {
// do necessary things here...
// call your AJAX function again, with delay...
setTimeout(callAjax, my_delay);
}
});
}
}
Note: Chris Kempen's answer (above) is better. Please use that one. He uses this technique inside the AJAX routine. See this answer for why using setTimeout is preferable over setInterval.
//Global var
is_expired = 0;
$(function (){
var timer = setInterval(doAjax, 800);
//At some point in future, you may wish to stop this repeating command, thus:
if (is_expired > 0) {
clearInterval(timer);
}
}); //END document.ready
function doAjax() {
$.ajax({
cache: false,
url: 'ajax2.php',
data: "workerID=<?=$row['workerID'];?>",
dataType: 'json',
success: function(data) {
var id = data[0]; //get id
var vname = data[1]; //get name
//--------------------------------------------------------------------
// 3) Update html content
//--------------------------------------------------------------------
$('#output').html("<b>id: </b>"+id+"<b> name: </b>"+vname);
}
}); //END ajax code block
} //END fn doAjax()
I've devised a a wrapper method which adds a custom delay on-top of the default $.ajax method. This is a way to have (on all jQuery ajax calls) a delay, throughout your entire app.
Very handy in simulating real-life random latency.
(function(){
$._ajaxDelayBk = $.ajax; // save reference to the "real" ajax method
// override the method with a wrapper
$.ajax = function(){
var def = new $.Deferred(),
delay = typeof $.ajax.delay == 'undefined' ? 500 : $.ajax.delay,
delayTimeout,
args = arguments[0];
// set simulated delay (random) duration
delayTimeout = setTimeout(function(){
$._ajaxDelayBk(args)
.always(def.resolve)
.done(def.resolve)
.fail(def.reject)
}, delay);
def.abort = function(){
clearTimeout(delayTimeout);
};
return def;
}
})();
USE EXAMPLE:
// optional: set a random delay to all `ajax` calls (between 1s-5s)
$.ajax.delay = Math.floor(Math.random() * 5000) + 1000;
var myAjax = $.ajax({url:'http://whatever.com/API/1', timeout:5000})
.done(function(){ console.log('done', arguments) })
.fail(function(){ console.log('fail', arguments) })
.always(function(){ console.log('always', arguments) })
// Can abort the ajax call
// myAjax.abort();
var takeInput=true;
$('#searchDrug').on('input',function() {
if(!takeInput){return false;}
takeInput=false;
var timer = setTimeout(function() {
$.ajax({
type: 'POST',
url: "{{route('AjaxSearchDrug')}}",
data: {
_token: '<?php echo csrf_token() ?>',
'searchkeyword': searchkeyword,
},
success: function (data) {
//do some logic then let keys be effective once more
takeInput=true;
}
});
}, 700);

How can I pass a function variable in jquery?

This is my html form I am using.
<label>Your Username:</label><input id="username" name="username" type="text" onchange="return ajax ('username');" />
This is my ajax checking file in php.
if ($_REQUEST['username']) {
$q = $dbc -> prepare("SELECT username FROM accounts WHERE username = ?");
$q -> execute(array($_REQUEST['username']));
if (strlen($_REQUEST['username']) < 3) {
echo '<div class="error">Has to be at least 3 characters</div>';
}
elseif ($q -> rowCount() > 0) {
echo '<div class="error">Username already taken</div>';
}
else {
echo '<div class="success">Username available</div>';
}
}
And my jquery ajax request...
function ajax (input) {
var val = $('#'+input).val();
$('.loading').fadeIn().delay(100);
$.post("ajax.php", {
username: val,
},
function (response) {
$('.error, .success').hide();
setTimeout(function(){
$('.loading').hide();
finishAjax(input, response);
}, 1000);
});
return false;
}
function finishAjax(id, response) {
$('#'+id).after(response).fadeIn(2000);
}
On my form I call the ajax request with the variable username.
In my ajax.php the correct validation of the username takes place if the request is named username.
I would like to display the variable input in place of username in the jquery code so I can use this script for other validations and pass the variable as email, or password and the script will still run as the value of input will be what it needs to be.
If that makes sense.
Thanks for your time.
var data = {};
data[input] = $('#' + input).val();
$.post("ajax.php", data, function() {...
and
finishAjax(input, response);
check input arg wat ll u get then proceed.....
remove semicolon near to
{username: $('#' + input).val(),}
as ,{ username: $('#' + input).val()},
u ll get o/p
You're declaring val to be the value of "input", but never using it. All the usages of username should have access to that variable val, so use it. Unless I'm misunderstanding your question, something like this (only changed one line):
function ajax(input) {
var val = $('#' + input).val();
$('.loading').fadeIn().delay(100);
$.post("ajax.php", {
username: val,
}, function (response) {
$('.error, .success').hide();
setTimeout(function () {
$('.loading').hide();
finishAjax('username', response);
}, 1000);
});
return false;
}
Before you call $.post create an empty object.
var data = {};
Use the parameter of the function as the index for the object.
data[input] = val;
In your $.post call use that object instead of the anonymous object literal.
$.post("ajax.php", data, function ...);
If you do things the way you're describing, though, you need to make sure you manage all these parameters you pass in properly. Are you sure that your PHP script is able to handle all the different possible values you may pass into the ajax function?

getJSON callback not happening

I have looked at similar queries here, but I can't seem to apply them to my problem. I am pretty new to jquery, so I may be doing something dumb.
I have a simple getJSON test:
$(document).ready(function() {
$(".testurl").click(function() {
// do a json call
var url="testjson.php";
var rc=$.getJSON(
url,
{parm1: "P1", parm2: "P2", parm3: "P3"},
function(data){
alert("callback function inline");
});
var x = 1;
});
});
that calls a really simple script:
header("Content-Type: application/json");
echo "{\"results\": [";
$arr = array();
$arr[] = "{\"fld1\": \"result1\", \"fld2\": \"result2\", \"fld3\": \"result3\"}";
echo implode(", ", $arr);
echo "]}";
that returns valid JSON (I checked on JSON lint)
The var rc that I use to receive the result of the request has the following values:
getResponseText \"{\"results\": [{\"fld1\": \"result1\", \"fld2\": \"result2\", \"fld3\": \"result3\"}]}\""
getReadyState 4
getStatus 200
Why does the callback function not fire?
If the click handler is attached to an anchor element then maybe the ajax call doesn't have time to execute before redirecting to a different page. Try adding a return false to the click callback:
$(".testurl").click(function() {
// do a json call
// ...
return false;
});
The $.getJSON call is just assigned to a variable, it is not being called.

Categories

Resources