I'm auto-refreshing the content on a site using ajax/json. Using jkey, I trigger some posting to the document, and during this action I want to cancel the original setTimeout that's running ("reloading" at 2 mins) - and then trigger the entire function "content" again to start over after 5 secs. However, I can't seem to stop "reloading" properly, neither call "content" after the given seconds. Can anybody spot the error?
<script>
$(function content(){
function reloading(){
$.ajax({
url: 'api.php',
data: "",
dataType: 'json',
success: function(data)
{
var id = data[0];
_id = id;
var vname = data[1];
var message = data[2];
var timestamp = data[3];
var field1 = data[4];
_field1 = field1;
var val2 = parseInt(field1, 10) ;
_val2 = val2;
$('#output').hide().html( message ).fadeIn("slow");
$('#username').hide().html( vname +":" ).fadeIn("slow");
setTimeout(reloading,120000);
}
});
}
reloading();
});
$(document).jkey('a',function() {
$.post("update.php", { "id": _id} )
$('#output').hide().html( "<i>thx" ).fadeIn("slow");
$('#username').fadeOut("fast");
$('#valg1').fadeOut("fast");
$('#valg2').fadeOut("fast");
clearTimeout(reloading);
setTimeout(content,5000);
});
</script>
The clearTimeout should get the unique "key" that is returned by setTimeout. So when setting, assign the return value to global variable:
window["reload_timer"] = setTimeout(reloading,120000);
Then have this:
clearTimeout(window["reload_timer"]);
You must save the setTimeout() id in order to later clear it with clearTimeout(). Like this:
var timeoutID = setTimeout(function(){someFunction()}, 5000);//this will set time out
//do stuff here ...
clearTimeout(timeoutID);//this will clear the timeout - you must pass the timeoutID
Besides saving the timeout id as mentioned in other posts, your function reloading is created inside function content and since you create no closure to it, it's unreachable from the rest of the program.
$(function content(){
function reloading(){
console.log('RELOADING');
}
reloading();
});
// Can't reach `content` or `reloading` from here
You have to do something like this:
var reloading, content, reloadingTimeoutId, contentTimeoutId;
reloading = function () {
console.log('RELOADING');
$.ajax(
// CODE
success : function (data) {
// CODE
reloadingTimeoutId = setTimeout(reloading, 120000);
}
)
};
content = function () {
reloading();
};
$(document).jkey('a',function() {
// CODE
clearTimeout(contentTimeoutId);
contentTimeoutId = setTimeout(content,5000);
});
It's kinda difficult writing this better not knowing the bigger picture. With this, content will be called after 5 seconds and as long as reloading succeeds it will callback itself every 120 seconds. Please observe that reloading is never cleared this way.
Related
I'm trying to change the value of variable dynamically WHEN an inputfield (text type) value changes.
the inputfield value is dynamic as well.
so, basically, when the inputfield value changes, the variable value should change accordingly.
this is my current code:
$('#map-txt').change(function(e){
var myData = document.getElementById("myText").value;
var myVar = eval("[" + myData + "]");
});
So, the value of the myText is an AJAX result which will be updated every X seconds. works fine.
the value of myVar is the same as the myText value but this only works when I load the page and/or refresh the page?
I'm not entirely sure if it doesn't work because I am mixing jquery with pure javascript or what I am doing is totally wrong.
what i need to do is to change the value of the myVar without page refresh.
any help would be appreciated.
EDIT, THIS IS MY AJAX code:
<script>
$(document).ready(function () {
function load() {
$.ajax({ //create an ajax request to load_page.php
type: "GET",
url: "SOMEPAGE.php",
dataType: "html", //expect html to be returned
success: function (response) {
$("#map-directions").html(response);
var input = document.getElementById("map-directions").innerHTML;
document.getElementById("map-txt").value = document.getElementById("map-directions").innerHTML;
setTimeout(load, 800);
}
});
}
load();
});
</script>
$('#map-txt').change( ... ); only gets triggered on user interaction, not when you update the field via AJAX or anything else.
Just add a $('#map-txt').trigger('change'); to the functionality that does the update via AJAX.
success: function (response) {
$("#map-directions").html(response);
var input = document.getElementById("map-directions").innerHTML;
document.getElementById("map-txt").value = document.getElementById("map-directions").innerHTML;
// trigger the update:
$('#map-txt').trigger('change');
setTimeout(load, 800);
}
Here is a simple suggestion :
1 : initialize the value of myVar so myVar = myData
2 : use a timer to check periodically if the value of myData is changed
code :
// store the initial value of $('#mytext') in the initialValue variable
myVar = $('#myText').val();
setInterval(function(){
if(myVar != $('#myText').val()){
console.log('changed ');
// change the content of the initialValue
myVar = $('#myText').val();
}
},2000);
note here that 2000 is the time to wait and then check the value of $('#myText').val() if it is changed
hope this is what you want
This topic is covered in a few other questions, but I had some difficulty applying the suggested approaches into this use case. I have a checkbox list, where a user can select n sub-sites to publish their post to. since this list could grow to be 100+, I need an efficient way to perform an expensive task on each one. It's okay if it takes awhile, as long as Im providing visual feedback, so I planned to apply an "in progress" style to each checkbox item as its working, then move to the next item int he list once it is successfully published. Also note: I'm working in the WordPress wp_ajax_ hook but the PHP side of things is working well, this is focused on the JS solution.
This code is working right now (console.logs left in for debug), but I've seen multiple warnings against using async: true. How can I achieve a waterfall AJAX loop in a more efficient way?
//Starts when user clicks a button
$("a#as_network_syndicate").click( function(e) {
e.preventDefault(); //stop the button from loading the page
//Get the checklist values that are checked (option value = site_id)
$('.as-network-list').first().find('input[type="checkbox"]').each(function(){
if($(this).is(':checked')){
blog_id = $(this).val();
console.log(blog_id+' started');
$(this).parent().addClass('synd-in-progress'); //add visual feedback of 'in-progress'
var process = as_process_syndication_to_blog(blog_id);
console.log('finished'+blog_id);
$(this).parent().removeClass('synd-in-progress');
}
});
});
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
var result = as_syndicate_to_blog(data);
console.log('end 2nd func');
return true;
}
function as_syndicate_to_blog(data){
$.ajax({
type : "post",
dataType : "json",
async: false,
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id},
success: function(response) {
if(response.type == "success") {
console.log(response);
return response;
} else {
}
},
error: {
}
});
}
Indeed, doing synchronous AJAX request is bad because it will block the browser during the whole AJAX call. This means that the user cannot interact with your page during this time. In your case, if you're doing like 30 AJAX calls which take say 0.5 seconds, the browser will be blocked during 15 whole seconds, that's a lot.
In any case, you could do something following this pattern:
// some huge list
var allOptions = [];
function doIntensiveWork (option, callback) {
// do what ever you want
// then call 'callback' when work is done
callback();
}
function processNextOption () {
if (allOptions.length === 0)
{
// list is empty, so you're done
return;
}
// get the next item
var option = allOptions.shift();
// process this item, and call "processNextOption" when done
doIntensiveWork(option, processNextOption);
// if "doIntensiveWork" is asynchronous (using AJAX for example)
// the code above might be OK.
// but if "doIntensiveWork" is synchronous,
// you should let the browser breath a bit, like this:
doIntensiveWork(option, function () {
setTimeout(processNextOption, 0);
});
}
processNextOption();
Notice: as said by Karl-André Gagnon, you should avoid doing many AJAX requests using this technique. Try combining them if you can, it will be better and faster.
If you can't pass the whole block to the server to be processed in bulk, you could use a jQuery queue. This is using your sample code as a base:
var $container = $('.as-network-list').first();
$container.find('input[type="checkbox"]:checked').each(function(){
var $input = $(this);
$container.queue('publish', function(next) {
var blog_id = $input.val(),
$parent = $input.parent();
console.log(blog_id+' started');
$parent.addClass('synd-in-progress'); //add visual feedback of 'in-progress'
as_process_syndication_to_blog(blog_id).done(function(response) {
console.log(response);
console.log('finished'+blog_id);
$parent.removeClass('synd-in-progress');
next();
});
});
});
$container.dequeue('publish');
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
return as_syndicate_to_blog(data).done(function(){ console.log('end 2nd func'); });
}
function as_syndicate_to_blog(data){
return $.ajax({
type : "post",
dataType : "json",
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id}
});
}
I don't have a test environment for this so you may need to tweak it for your use case.
I'm making a that should get images from database with ajax and then display it with some carousel plugin. Here is how it should work :
Image url is saved to database from admin
frontend script makes a ajax call to a php file and returns all url's from db.
Now when I have all images, the carousel plugin can be applied.
Images are now being displayed one by one.
The trick is that i want to make another ajax call when last image is displayed and repopulate container div with fresh images from database. Here is my code
function get_images(){
var data = {
"function_name" : "get_images",
"args" : ""
};
$.ajax({
type : "POST",
url : "http://localhost/.../functions.php",
data : data,
dataType : "JSON",
success : function(ret){
$(".container").html(ret);
$(".container").carousel(//When last call - function again);
}
});
}
And here is the problem. On ajax success carousel plugin is starting to rotate imgs, and when its finished, the get_images function should be call again. But this function is already in the another function and every time when it makes a call it will be one level deeper. Is there any way of doing this?
The best would be for the carousel to fire an event that it needs more images and listen to that event. You can then retrieve more images and return the new list to the carousel. There are carousel plugins that have all this build in. I often use this one: http://caroufredsel.dev7studios.com/
Maybe in your PHP script:
<?php
if ( isset($_POST['function_name']) ) {
if ( $_POST['function_name'] == 'get_images' ) {
// Get some URLs into an array...
// For the sake of the example we'll manually fill the array
$urls = ['img/image1.png', 'img/image2.png'];
echo json_encode($urls);
}
}
And in your JS:
function Carousel() {
this.getMoreImages();
}
Carousel.prototype.nextImage = function () {
if (this.i < this.images.length) {
this.showImage(); // Implement this.
this.i += 1;
this.spin():
}
else {
this.getMoreImages();
}
}
Carousel.prototype.spin = function () {
var self = this;
setTimeout(function () {
self.nextImage();
}, 5000);
}
Carousel.prototype.getMoreImages = function () {
var self = this;
$.ajax({
type : 'POST',
url : 'http://localhost/.../functions.php',
data : data,
dataType : 'JSON',
success : function (ret) {
self.images = JSON.parse(ret);
self.i = 0;
self.spin();
}
});
}
var myCarousel = new Carousel();
This Carousel object will request an array of images on instantiation, and show each image on a 5-second interval. When all the images have been exhausted, it will automatically make another AJAX call, retrieving images in the same manner as it did originally, and then continue looping through the new images. It will continue in this cycle forever.
I have an input box on which there is an ajax request on every key press. so if i enter word "name" there will be 4 successful request. So i actually want only the latest request of executed. so if i enter word "name" there will be only one request which will be the last one.
and i also have a solution for this (this is a simple example with click method)
JS script
var callid = 1;
function ajaxCall (checkval ){
if(checkval == callid){
$.ajax({
type: 'post',
url: baseurl + "test/call_ajax",
data: {
val: "1"
},
success: function(data) {
console.log(data)
}
});
}
}
function call(){
var send = callid+=1;
setTimeout( function(){ ajaxCall(send) } , 500);
}
html script
<a href="#" onclick="call()" > Call ajax </a>
This is working perfectly. But i was think if there is way to refine it a little bit more.
Any ideas :)
I am sure you are looking some better intent technique for event dispatching.
var eventDispatcher = null;
$('.textbox').keyup(function(){
if(eventDispatcher) clearTimeout(eventDispatcher);
eventDispatcher = setTimeout(function(){
$.ajax({ ... });
}, 300);
});
You could do your ajax inside of a setTimeout. So you don't need to declare and check an additional variable or write another function like call()
$(document).ready(function () {
var timer;
$('#fillMe').keypress(function () {
clearTimeout(timer);
timer = setTimeout(function () {
//replace this with your ajax call
var content = $('#fillMe').val();
$('#result').text('You will only see this if the user stopped typing: ' + content);
}, 1000); // waits 1s before getting executed
});
});
<input type="text" id="fillMe">
<div id="result"></div>
On every keypress event this clears the timeout and immediately creates a new timeout. This means the content of the setTimeout function only gets executed if the user stopped typing for at least 1 second.
Of course 1 second is just the value for the example purpose. You can change it to whatever you want or think is a good time (like 500ms)
See my jsfiddle
setTimeout returns an id that you can store and use to clear the previously set timer:
var timerId;
function call() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
timerId = setTimeout( function() { ajaxCall(send) }, 500);
}
The result of this should be that the ajaxCall method will be called 500ms after the last letter is entered.
i have a simple question, there is a function with parameter emp_id that opens up a form for a chat with different attributes, i want it to be refreshed automatically each 10 sec, now it works a bit wrongly, since there is a parameter emp_id that is can be changed, and once i change it, the chat with messages and form are refreshed double time or triple times :) depend on how many times u change the emp_id, i hope i was clear )) anyway here is the javascript function:
function load_chat(emp_id) {
var url = "#request.self#?fuseaction=objects2.popup_list_chatform"
url = url + "&employee_id=" + emp_id;
document.getElementById('form_div').style.display = 'block'; AjaxPageLoad(url,'form_div',1,'Yükleniyor');
setInterval( function() {
load_chat(emp_id);
},10000);
}
there a list of names, once i click on one of them, this form is opened by this function, but if i click another user, i mean if i change the emp_id, it refreshes, the previous and present form. how do i change it so that it will refresh only the last emp_id, but not all of id's which i've changed
thank you all for the help, i really appreciate it!
This would nicely encapsulate what you're doing. The timer id (tid) is kept inside the closure, so when you call load_chat it will stop the interval if there was one running.
Once the new url is set up, it will start the interval timer again.
var ChatModule = (function() {
var tid,
url;
function refresh()
{
AjaxPageLoad(url, 'form_div', 1, 'Yükleniyor');
}
return {
load_chat: function(emp_id) {
if (tid) {
clearInterval(tid);
}
// setup url
url = "#request.self#?fuseaction=objects2.popup_list_chatform"
url = url + "&employee_id=" + emp_id;
document.getElementById('form_div').style.display = 'block';
// load ajax
refresh();
// set timer
tid = setInterval(refresh, 10000);
}
}
}());
ChatModule.load_chat(123);
Use setTimeout instead. Each time your function is executed, it will set up the next execution (you could also make it conditional):
function load_chat(emp_id) {
... // do something
if (condition_still_met)
setTimeout(function() {
load_chat(emp_id); // with same id
}, 10000);
}
load_chat("x"); // to start
Or you will have to use setInterval outside the load_chat function. You can clear the interval when necessary.
function get_chat_loader(emp_id) {
return function() {
... // do something
};
}
var id = setInterval(get_chat_loader("x"), 10000); // start
// then, somewhen later:
clearInterval(id);