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
Related
I've been trying to make a simple site, and I can't quite wrap my head around some of the things said here, some of which are also unrelated to my situation.
The site has a form with 3 input boxes, a button, and a list. The info is submitted through a separate PHP file to a MySQL database, once the submit button is clicked. I'm supposed to make the list (it's inside a div) update once the info is successfully sent and updated in the database. So far I've made it work with async:false but I'm not supposed to, because of society.
Without this (bad) option, the list doesn't load after submitting the info, because (I assume) the method is executed past it, since it doesn't wait for it to finish.
What do I exactly have to do in "success:" to make it work? (Or, I've read something about .done() within the $.ajax clause, but I'm not sure how to make it work.)
What's the callback supposed to be like? I've never done it before and I can get really disoriented with the results here because each case is slightly different.
function save() {
var name = document.getElementById('name');
var email = document.getElementById('email');
var telephone = document.getElementById('telephone');
$.ajax({
url: "save.php",
method: "POST",
data: { name: name.value, email: email.value, telephone: telephone.value },
success: $("List").load(" List")
});
}
Thank you in advanced and if I need include further info don't hesitate to ask.
From this comment
as far as i know the success function will be called on success you should use complete, A function to be called when the request finishes (after success and error callbacks are executed). isnt that what you want ? – Muhammad Omer Aslam
I managed to solve the issue simply moving the $.load clause from the success: option to a complete: option. (I think they're called options)
I haven't managed error handling yet, even inside my head but at least it works as it should if everything is entered properly.
Thanks!
(Won't let me mark as answered until 2 days)
I would first create an AJAX call inside a function which runs when the page loads to populate the list.
window.onload = populatelist();
function populatelist() {
$.ajax({
type: "POST",
url: "list.php",
data: {function: 'populate'},
success: function(data) { $("#list").html("data"); }
});
}
Note: #list refers to <div id="list> and your list should be inside this.
I would then have another AJAX call inside a different function which updates the database when the form is submitted. Upon success, it will run the populatelist function.
function save() {
var name = document.getElementById('name');
var email = document.getElementById('email');
var telephone = document.getElementById('telephone');
$.ajax({
type: "POST",
url: "list.php",
data: {function: 'update', name: name.value, email: email.value, telephone: telephone.value },
success: function() { populatelist(); }
});
}
list.php should look like this:
<?php
if($_POST['function'] == "populate") {
// your code to get the content from the database and put it in a list
}
if($_POST['function'] == "update") {
// your code to update the database
}
?>
I will show you piece of solution that I use in my project. I cannot say it is optimal or best practices, but it works for me and can work for you:
PHP:
function doLoadMails(){
//initialize empty variable
$mails;
$conn = new mysqli($_POST['ip'], $_POST['login'], $_POST['pass'], $_POST['db']);
// Check connection
if ($conn->connect_error) {
die("");
}
//some select, insert, whatever
$sql = "SELECT ... ... ... ";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row, j is counter for rows
$j =0;
while($row_a = $result->fetch_assoc()) {
//for each row, fill array
$mails[$j][0] = $row_a["name"] ;
$mails[$j][1] = $row_a["mail"] ;
$mails[$j][2] = $row_a["language"] ;
$j++;
}
}
//if $mails has results (we added something into it)
if(isset($mails)){
echo json_encode($mails);/return json*/ }
else{
//some error message you can handle in JS
echo"[null]";}
}
and then in JS
function doLoadMails() {
$.ajax({
data: { /*pass parameters*/ },
type: "post",
url: "dataFunnel.php",
success: function(data) { /*data is a dummy variable for everything your PHP echoes/returns*/
console.log(data); //you can check what you get
if (data != "[null]") { /*some error handling ..., in my case if it matches what I have declared as error state in PHP - !(isset($mails))*/ }
}
});
Keep in mind, that you can echo/return directly the result of your SQL request and put it into JS in some more raw format, and handle further processing here.
In your solution, you will probably need to echo the return code of the INSERT request.
I created "omarkasec" as a function and I get car brands from database via ajax and I added at the select element this car brands as options via ajax --> success.
But I can't set a value this select element.
I tried this codes for set value:
$('select[name=marka]').val('Lada');
$('select[name=marka] option[value=Lada]').prop('selected', true);
$('select[name=marka] option[value=Lada]').attr('selected', 'selected');
this codes don't work. But if I add alert(""); in "omarkasec" function the codes do work and if I remove alert(""); the codes don't work.
<div id="marka" class="gizle" >
Marka: <br>
<select name="marka" onchange="omodelsec()" size="10" ></select>
</div>
<script language='javascript' type='text/javascript'>
function omarkasec() {
$.ajax({
type: "POST",
url: "aracsor.php",
dataType: "json",
data: {
otomobilmodelyili : $("select[name=modelyili]").val(), //This work, because i created php.
},
success: function(donen){
$("#marka").removeClass("gizle");
$("#model").addClass("gizle");
$("#yakit").addClass("gizle");
$("#sanziman").addClass("gizle");
$("#cekis").addClass("gizle");
$("#kasatipi").addClass("gizle");
$("select[name=marka]").empty();
$.each(donen, function (index, otomarka) {
$("select[name=marka]").append($("<option>", {
text : otomarka,
value : otomarka,
}));
});
},
});
//if I add here alert(""); The following code works.
}
</script>
<script language='javascript' type='text/javascript'>
omarkasec();
$('select[name=marka]').val('Lada');
alert($('select[name=marka]').val()); //if I add alert(""); this code work but if I remove alert(""); this code get null value.
</script>
Ajax calls are asynchronous. Your code executes the $.ajax() call passing it a call back function, but that call back function is not executed at that very moment.
The execution immediately proceeds with the statement after $.ajax() but at that moment the content has not been loaded.
However, if you perform an alert(), the call back might eventually be triggered while the alert dialog is open, and thus content is loaded by your call back function. If you then close the popup, any code following it will find the content is there.
One way to solve this, is to use the return value of the $.ajax call, which is a promise, and chain a then call to it:
function omarkasec(oncomplete) {
return $.ajax({
// ^^^^^^
type: "POST",
url: "aracsor.php",
dataType: "json",
data: {
otomobilmodelyili : $("select[name=modelyili]").val(),
},
success: function(donen){
$("#marka").removeClass("gizle");
$("#model").addClass("gizle");
$("#yakit").addClass("gizle");
$("#sanziman").addClass("gizle");
$("#cekis").addClass("gizle");
$("#kasatipi").addClass("gizle");
$("select[name=marka]").empty();
$.each(donen, function (index, otomarka) {
$("select[name=marka]").append($("<option>", {
text : otomarka,
value : otomarka,
}));
});
},
});
}
// provide (anonymous) callback function to the `then` method:
omarkasec.then(function () {
// this code will only be executed when content is loaded:
$('select[name=marka]').val('Lada');
alert($('select[name=marka]').val());
});
You have a race condition. You are calling omarkasec() and not waiting for it to finish to execute the select.val() action. When you add the alert it "works" because it gives the code some extra time to complete the ajax call an fill the values. When you alert it, the values are already filled.
All your code that depends on the result from the ajax call must be inside the success callback.
i found out my JS sends POST method twice to my PHP file, thats why i keep getting double/repetitive results from my PHP.
This JS event, upon .keyup() will execute an ajax.
$(document).ready(function() {
var getUrl = $('#url');
var youtube = regex here
var web = regex here
getUrl.keyup(function() {
if (youtube.test(getUrl.val())) {
var youtube_url = getUrl.val().match(youtube)[0];
$.ajax ({
type:"POST",
url:"getyoutube.php",
data: {youtube_url:youtube_url},
success: function(html) { $('.echotest').append(html); }
}); }
else if (web.test(getUrl.val())) {
var extracted_url = getUrl.val().match(web)[0];
$.post("curl_fetch.php?url="+ extracted_url, {
}, function(response){
$('#loader').html($(response).fadeIn('slow'));
$('#cur_image').val(1);
});}
});
});
the data will be received by getyoutube.php and should only print json result of a particular youtube video once.
//some code ommitted
$youtube ="https://gdata.youtube.com/feeds/api/videos/'.$matches[0].'?v=2&alt=jsonc";
$curl = curl_init($youtube);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$return = curl_exec($curl);
curl_close($curl);
$test = json_decode($return, true);
print_r($test);
i cant seem to figure out why my AJAX post keeps sending POSTS method twice
Couple of things to try:
1) Make sure you bind and unbind your key up event
2) Use a global variable to make sure only one ajax request gets sent at once
i.e.:
var ajaxrequest = false; //GLOBAL
function getyoutubedata(){
if(ajaxrequest != false){
return;
}
ajaxrequest = $.ajax ({
type:"POST",
url:"./includes/getyoutube.php",
data: {youtube_url:youtube_url},
success: function(html) { $('.echotest').append(html); ajaxrequest = false; }
});
}
Btw thing to note the youtube api supports jsonp callbacks so you might want to consider doing this through that
3) Try to check if the content of the input field has changed even before calling the above function
You should show us the code with the .keyup() event, probably that's the place of an error. The event handler could execute a wrapper function for the ajax, instead of the ajax directly. For example, if you the keyup event is triggered, try to check if the input content has changed. If so, run ajax, if not - do nothing.
coverted this
$.ajax ({
type:"POST",
url:"getyoutube.php",
data: {youtube_url:youtube_url},
success: function(html) { $('.echotest').append(html); }
}); }
to this.
$.post("./includes/getyoutube.php?url="+ youtube_url, {
}, function(response){
$('.echotest').append(response);
});
POST method is now being executed once. although i cant really explain technically why it worked.
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);
I have button which post values of form to url but during post i want to capture that value into my database too.
So on button click i made new thread of ajax and paused by while loop so user can not redirect due to post of form.
But problem is program not responding in while loop and not posting ajax call.
function btnSubmitId_Onclick() {
window.setTimeout(function () {
var FirstName = $(txtFirstNameId).val()
var Email = $(txtEmailId).val()
AJAXPost( //Url
"Signup"
, //Data
{Ip: Ip, CustomerKey: CustomerKey, FirstName: FirstName, Email: Email }
, //Success
function (data) {
response2 = true;
}
, //error
function (xhr, textStatus, errorThrown) { }
);
}, 0);
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while (response2 == false)
}
var response2 = false;
You really shouldn't do that. Active waiting is likely to block the whole browser or at least the current tab.
Put all code that needs to run after the request succeeded in the success callback.
Since you apparently want to both submit the form normally and use AJAX (why?!), the solution is rather simple: prevent the original submit from being handled by the browser by calling e.preventDefault() (e being the first argument passed to the jQuery event handler) and after the AJAX request succeeded .submit() the form. To avoid the AJAX request from being sent again you might need to unbind the submit event handler or set a variable after the AJAX request completed.