I am using ajaxComplete to run some functions after dynamic content is loaded to the DOM. I have two separate functions inside ajaxComplete which uses getJSON.
Running any of the functions once works fine
Running any of them a second time causes a loop cause they are using getJSON.
How do I get around this?
I'm attaching a small part of the code. If the user has voted, clicking the comments button will cause the comments box to open and close immediately.
$(document).ajaxComplete(function() {
// Lets user votes on a match
$('.btn-vote').click(function() {
......
$.getJSON(path + 'includes/ajax/update_votes.php', { id: gameID, vote: btnID }, function(data) {
......
});
});
// Connects a match with a disqus thread
$('.btn-comment').click(function() {
var parent = $(this).parents('.main-table-drop'), comments = parent.next(".main-table-comment");
if (comments.is(':hidden')) {
comments.fadeIn();
} else {
comments.fadeOut();
}
});
});
Solved the problem by checking the DOM loading ajax request URL
$(document).ajaxComplete(event,xhr,settings) {
var url = settings.url, checkAjax = 'list_matches';
if (url.indexOf(checkAjax) >= 0) { ... }
}
Related
I've implemented a simple AJAX call that is bound to a button. On click, the call takes input from an and forwards the value to a FLASK server using getJSON. Using the supplied value (a URL), a request is sent to a website and the html of a website is sent back.
The issue is the AJAX call seems to run multiple times, incrementally depending on how many times it has been clicked.
example;
(click)
1
(click)
2
1
(click)
3
2
1
Because I am sending requests from a FLASK server to another website, it effectively looks like I'm trying to DDOS the server. Any idea how to fix this?
My AJAX code;
var requestNumber = 1; //done for testing purposes
//RUNS PROXY SCRIPT
$("#btnProxy").bind("click", function() . //#btnProxy is the button
{
$.getJSON("/background_process", //background_process is my FLASK route
{txtAddress: $('input[name="Address"]').val(), //Address is the input box
},
console.log(++requestNumber), //increment on function call
function(data)
{$("#web_iframe").attr('srcdoc', data.result); //the FLASK route retrieves the html of a webpage and returns it in an iframe srcdoc.
});
return false;
});
My FLASK code (Though it probably isn't the cause)
#app.route('/background_process')
def background_process():
address = None
try:
address = request.args.get("txtAddress")
resp = requests.get(address)
return jsonify(result=resp.text)
except Exception, e:
return(str(e))
Image of my tested output (I've suppressed the FLASK script)
https://snag.gy/bikCZj.jpg
One of the easiest things to do would be to disable the button after the first click and only enable it after the AJAX call is complete:
var btnProxy = $("#btnProxy");
//RUNS PROXY SCRIPT
btnProxy.bind("click", function () //#btnProxy is the button
{
btnProxy.attr('disabled', 'disabled');//disable the button before the request
$.getJSON("/background_process", //background_process is my FLASK route
{
txtAddress: $('input[name="Address"]').val(), //Address is the input box
},
function (data) {
$("#web_iframe").attr('srcdoc', data.result); //the FLASK route retrieves the html of a webpage and returns it in an iframe srcdoc.
btnProxy.attr('disabled', null);//enable button on success
});
return false;
});
You can try with preventDefault() and see if it fits your needs.
$("#btnProxy").bind("click", function(e) {
e.preventDefault();
$.getJSON("/background_process",
{txtAddress: $('input[name="Address"]').val(),
},
console.log(++requestNumber),
function(data)
{$("#web_iframe").attr('srcdoc', data.result);
});
return false;
});
Probably you are binding the click event multiple times.
$("#btnProxy").bind("click", function() { ... } );
Possible solutions alternatives:
a) Bind the click event only on document load:
$(function() {
$("#btnProxy").bind("click", function() { ... } );
});
b) Use setTimeout and clearTimeout to filter multiple calls:
var to=null;
$("#btnProxy").bind("click", function() {
if(to) clearTimeout(to);
to=setTimeout(function() { ... },500);
});
c) Clear other bindings before set your calls:
$("#btnProxy").off("click");
$("#btnProxy").bind("click", function() { ... } );
I'm trying to create a PHP page that periodically updates values of several elements on the page. I'm using a host that limits my hits per day, and each hit to any page they're hosting for me counts against my total. Therefore, I'm trying to use JQuery/AJAX to load all of the information that I need from other pages at one time.
I'm calling the following index.php. This method achieves the desired affect exactly the way I want it, but results in three hits (dating.php, dgperc.php, and pkperc.php) every two seconds:
var focused = true;
$(window).blur(function() {
focused = false;
});
$(window).focus(function() {
focused = true;
});
function loadData() {
if (focused) {
var php = ["dating", "dgperc", "pkperc"];
$.each(php, function(index, value) {
$('#'+this).load(this+'.php');
});
}
}
$(document).ready(function() {
loadData();
});
setInterval(function() {
loadData();
}, 2000);
I'm calling the following index1.php. This is where I'm at as far as a method that only results in one hit every two seconds. My workaround is that I have combined the three php pages that I was loading into one, dating1.php. I load this into a div element, #cache, all at once. This element is set to hidden using CSS, and then I just copy its inner HTML into the appropriate elements:
var focused = true;
$(window).blur(function() {
focused = false;
});
$(window).focus(function() {
focused = true;
});
function loadData() {
if (focused) {
var php = ["dating", "dgperc", "pkperc"];
$('#cache').load('dating1.php');
$.each(php, function(index, value) {
$('#'+this+'1').html($('#'+this).html());
});
}
}
$(document).ready(function() {
loadData();
});
setInterval(function() {
loadData();
}, 2000);
Dating1.php will produce different outputs every time it's run, but here is an example of the output:
<span id = "dating">4 years, 7 months, 3 weeks, 10 seconds ago.</span>
<span id = "dgperc">21.9229663059</span>
<span id = "pkperc">22.2121099923</span>
On document ready, index1.php does not function properly: the #cache element isn't filled at all, so the other elements don't get filled either. However, after two seconds, the loadData() function runs again, and then the #cache element is filled correctly, and so are the other elements. For some reason, this isn't a problem on my index.php page at all, and I'm not sure why there's a difference here.
How can I get #cache to load the first time so that the page loads correctly? Or is there a better way to do this?
Each AJAX call is basically a page visit in the background. Like telling your assistant three different times to get you one coffee. Or telling them one to get you three coffees.
If you don't want to combine your three PHP pages into one - thus keeping code separate and easier to maintain. Consider creating one "cache.php" script and inside it:
cache.php:
$outputData = array('dating' => false, 'dgperc' => false, 'pkperc' => false);
foreach($outputData as $file => &$data)
{
//buffer output
ob_start();
//run first script (be smart and file_exists() first)
include_once($file . '.php');
$data = ob_get_clean();
}
//output JSON-compliant for easy jQuery consumption
echo json_encode($outputData);
Then in your javascript:
function loadData() {
if (focused) {
//call ajax with json and fill your spans
$.ajax({
async: true,
cache: false,
dataType: 'json',
success: function(data, textStatus, jqxhr) {
$('#dating').html(data.dating);
$('#dgperc').html(data.dgperc);
$('#pkperc').html(data.dgperc);
// NOTE... do a console.dir(data) to get the correct notation for your returned data
},
url: 'cache.php'
});
}
You are calling cache.php once every two seconds, saving on the 3-hits of calling the php files individually. Using a middle-man file you keep your scripts separate for maintainability.
I've been trying to figure out this issue with my website for a while now--I have a bunch of "stars" a user can click on.
clicking on a star loads a file into a div with information regarding that star. It also loads a button for the players to click and "Take over" the planet. That all is working well and fine, however--I've recently discovered an issue that I'm not quite sure how to handle.
IF a player clicks on multiple stars before reloading the page for whatever reason--when the click to attack/whatever the star--it'll send multiple requests across the server. I at first thought this was something in my coding that was sending all information regarding all the stars, however I've come to realize that it's only the stars that the player has clicked on.
Now--Here is the code:
$.ajaxSetup ({
// Disable caching of AJAX responses
cache: false
});
function loadStatus()
{
$.ajax(
{
url:'world1.php', error: function () { }, dataType:'json',
success: function(data)
{
denial = false;
$('#credits').html(data.credits);
$('#fuelleft').html(data.fuel);
$('#energyleft').html(data.energy);
}
});
}
function currentStarMapURL(URL)
{
$('#starmap').load(URL, {},
function()
{
$('#loader').hide();
fullStarInformation(URL);
starInformation();
setInterval(function() { $('.unknown').effect("highlight",{color:"#800000"}, 1500)});
return false;
}
);
}
/*
purhcase upgrades
*/
/*
Retriever Better Star Info
*/
function fullStarInformation()
{
$(".star").click(
function()
{
$('#planet-bar').empty();
val = this.id;
url = "planet.php?sid="+val;
$('#planet-bar').load(url, {'sid':val},
function()
{
colony(url);
}
);
}
);
}
function colony(url)
{
$('#planet-bar').on("click", "button",
function() {
event.preventDefault();
name = 0;
$(this).hide();
name = $(this).attr('sid');
$.post('purchase.php?mode=planet', {sid: name},
function ()
{
$('#planet-bar').load(url, {}, function () { currentStarMapURL(URL2); })
}
);
$(this).prop('disabled', true);
});
}
I figured at first that the issue was a caching issue, so I added the $.ajaxSetup to the first line, but that didn't seem to change anything.
Then I figured, maybe it's the way the code was being called--I originally had two seperate functions; one for attack, one for colonizing. both of which were being called in the fullStarInformation function, So I moved it all down to one function, i'm still getting the issue.
AFAIK, right now, i may have to rewrite this entire block of code so that the colony function and the starInformation function are separate and not acting upon one another. But I wanted to get a second, third maybe even fourth set of eyes on the code before I go about doing that.
If you are getting multiple ajax calls, chances are you are setting up multiple event handlers.
Just quickly glancing through the code, I would think you should change
function colony(url)
{
$('#planet-bar').on("click", "button", function() { ... } );
To
function colony(url)
{
$('#planet-bar').off("click", "button"); //unbind old event handlers
$('#planet-bar').on("click", "button", function() { ... } );
i have some links in a web page ,what i want to do :
Trigger click event on every link
When the page of every link is loaded , do something with page's DOM(fillProducts here)
What i have tried :
function start(){
$('.category a').each(function(i){
$.when($(this).trigger('click')).done(function() {
fillProducts() ;
});
})
}
Thanks
What you want to do is much more complicated than you seem to be giving it credit for. If you could scrape webpages, including AJAX content, in 7 lines of js in the console of a web browser you'd put Google out of business.
I'm guessing at what you want a bit, but I think you want to look at using a headless browser, e.g. PhantomJs. You'll then be able to scrape the target pages and write the results to a JSON file (other formats exist) and use that to fillProducts - whatever that does.
Also, are you stealing data from someone else's website? Cause that isn't cool.
Here's a solution that may work for you if they are sending their ajax requests using jQuery. If they aren't you're going to need to get devilishly hacky to accomplish what you're asking (eg overriding the XMLHttpRequest object and creating a global observer queue for ajax requests). As you haven't specified how they're sending the ajax request I hope this approach works for you.
$.ajaxSetup({
complete: function(jQXHR) {
if(interested)
//do your work
}
});
The code below will click a link, wait for the ajax request to be sent and be completed, run you fillProducts function and then click the next link. Adapting it to run all the clicks wouldn't be difficult
function start(){
var links = $('.category a');
var i = 0;
var done = function() {
$.ajaxSetup({
complete: $.noop//remove your handler
});
}
var clickNext = function() {
$(links.get(i++)).click();//click current link then increment i
}
$.ajaxSetup({
complete: function(jQXHR) {
if(i < links.length) {
fillProducts();
clickNext();
} else {
done();
}
}
});
clickNext();
}
If this doesn't work for you try hooking into the other jqXHR events before hacking up the site too much.
Edit here's a more reliable method in case they override the complete setting
(function() {
var $ajax = $.ajax;
var $observer = $({});
//observer pattern from addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjquery
var obs = window.ajaxObserver = {
subscribe: function() {
$observer.on.apply($observer, arguments);
},
unsubscribe: function() {
$observer.off.apply($observer, arguments);
},
once: function() {
$observer.one.apply($observer, arguments);
},
publish: function() {
$observer.trigger.apply($observer, arguments);
}
};
$.ajax = function() {
var $promise = $ajax.apply(null, arguments);
obs.publish("start", $promise);
return $promise;
};
})();
Now you can hook into $.ajax calls via
ajaxObserver.on("start", function($xhr) {//whenever a $.ajax call is started
$xhr.done(function(data) {
//do stuff
})
});
So you can adapt the other snippet like
function start(){
var links = $('.category a');
var i = 0;
var clickNextLink = function() {
ajaxObserver.one("start", function($xhr) {
$xhr.done(function(data) {
if(i < links.length) {
fillProducts();
clickNextLink();
} else {
done();
}
});
})
$(links.get(i++)).click();//click current link then increment i
}
clickNextLink();
}
try this:
function start(){
$('.category a').each(function(i){
$(this).click();
fillProducts() ;
})
}
I get ya now. This is like say:
when facebook loads, I want to remove the adverts by targeting specific class, and then alter the view that i actually see.
https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/
Is a plugin for firefox, this will allow you to create a javascript file, will then allow you to target a specific element or elements within the html rendered content.
IN order to catch the ajax request traffic, you just need to catcher that within your console.
I can not give you a tutorial on greasemonkey, but you can get the greasemonkey script for facebook, and use that as a guide.
http://mashable.com/2008/12/25/facebook-greasemonkey-scripts/
hope this is it
This should be quite simple but I'll be darned if I can work it out. Just trying to get a div to display while my ajax is processing and then hide once done (I've put a sleep in there purely to test its working as locally it loads so fast I'm not sure if its working or not)!
The html page has this code in the script: -
$(document).ready(function(){
$("#loadingGIF").ajaxStart(function () {
$(this).show();
});
$("#loadingGIF").ajaxStop(function () {
window.setTimeout(partB,5000)
$(this).hide();
});
function partB(){
//just because
}
var scenarioID = ${testScenarioInstance.id}
var myData = ${results as JSON}
populateFormData(myData, scenarioID);
});
There is then a div in my page like so (which I can see in the source of the page just hidden): -
<div id="loadingGIF" ><img src='${application.contextPath}/images/spinner.gif' height="50" width="50"></div>
The ready code then goes off and calls this: -
function populateFormData(results, scenarioID) {
$table = $('#formList')
for(var i in results){
var formIDX = (results[i]["forms_idx"])
var formID = (results[i]["form_id"])
appendSubTable(formIDX, scenarioID, $table, formID);
}
}
Which references this multiple times calling several AJAX posts: -
function appendSubTable(formIDX, scenarioID, $table, formID) {
var $subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
var url = "**Trust me this bits OK ;) **"
$.post(url, {
formIDX : formIDX, scenarioID : scenarioID, formID :formID
}, function(data) {
$subTable.append(data)
}).fail(function() {
});
}
Any pointers gratefully received...
Interestingly I bunged some alerts into my ajaxstart and stop and neither show up ever so I'm missing something obvious :S When I check the console in firefox I can see that all my POSTs are completing....
You should probably add the Ajaxstart and stop global event handlers to the document node like this
$(document).ajaxStart(function () {
$("#loadingGIF").show();
});
I realized my problem, I needed to register the ajaxstart and stop to the document not the div!
So instead of this: -
$("#loadingGIF").ajaxStart(function () {
$(this).show();
});
I now have: -
$(document).ajaxStart(function () {
$("#loadingGIF").show();
});
I assume this is because its the document that the ajax is running against not the div although my understanding there may not be 100% accurate at least this works so please tell me if I've misunderstood this! :)
#jbl, thanks for this pointer I did this to also leave the notification on screen for a few more moments just to make sure everything is loaded.