JQuery Prevent Autoclicker

spacepir

New Member
Messages
41
Reaction score
2
Points
0
My online game is going great, but I've spotted a problem that I cant' fix. Repeatedly clicking a button with a JQuery.load() function on it causes the requests to be "stacked".

I've hunted everywhere for a solution, but I can't find one. I need a way of checking if there's already a .load/AJAX request in progress, and if so, abort any others.

Without a solution, people could use auto-clickers in my game, which is something I really don't want. Not even autoclickers, but even someone with an excited finger could stack a bunch of requests which are all thrown at the server at once...

Problem much?

Answers appreciated. Thanks. :)
 

essellar

Community Advocate
Community Support
Messages
3,295
Reaction score
227
Points
63
That's going to get funky no matter how you do it (which is probably why there aren't a whole bunch of "I figured this out in ten minutes" tutorials out there on the web).

The first thought most people are likely to have is that they can just make the request synchronous rather than async, effectively blocking the creation of additional requests until the first request returns and is handled. Then they quickly find out that it blocks everything, not just the next request. Oops!

That leaves two further approaches. One is to set up a global accumulator for request counts (which will allow you to have simultaneous requests in play if they are of different "types"), check the appropriate accumulator before triggering a request, and if the count allows, fire the request and increment the accumulator. Your callback function would decrement the accumulator once the request is answered. You can do more-or-less the same thing by removing and re-adding click event listeners.

The problem in both cases is that it depends on the server always answering with a 200 status, since jQuery natively only monitors the request's onReadyStateChange event for action on a 200 (OK) response. You need to get in there and monitor for failures as well (400- and 500-series error statuses), or the game will permanently block without notifying the user. jQuery has facilities for this monitoring, but you have to set up the error handling conditions. You may want to automatically retry the request a reasonable number of times, give the user a failure indication, or even halt the game (with a failure indication) if responses aren't happening reliably. Either way, you want to clear whatever blocks you're using (decrement the counter or re-attach listeners) once you've determined that the request has permanently failed. (It's much better in general to have the user swearing about how badly the interwebs suck right now than to have them think that your game/application doesn't work at all.)
 

spacepir

New Member
Messages
41
Reaction score
2
Points
0
When you say that it blocks everything, do you mean everything? I don't think it'll be too much hassle if you can only do one thing at a time, it's not a high action RPG, if you know what I mean. A simple war game that requires you to know formulae and do math to get an edge against everyone else.
 

essellar

Community Advocate
Community Support
Messages
3,295
Reaction score
227
Points
63
I mean everything. The JavaScript runtime locks up until a synchronous request is answered, and that usually prevents the DOM from answering the helm as well.
 

cybrax

Community Advocate
Community Support
Messages
764
Reaction score
27
Points
0
What about using the one() function inside the jQuery library?
That would basically disable the button after the initial press by the user so it only fires off a single request.

If that does not help my best guess would be you enter the realm of dynamically creating elements toggling the between click & unbind attributes or using the on() function. So basically the button is locked up till the server replies to the page. Like Essellar said it's not a ten minute tutorial fix and will take some head scratching.
 

spacepir

New Member
Messages
41
Reaction score
2
Points
0
I solved this issue, actually. I'll show you the code, then explain how it works.

Code:
Code:
var loading = false; // Set variable to false on page load.
function load(trgt, urll)
{
	if(!loading) // If a load is NOT already in progress.
	{
                $('#loaderImage').show(); // Show the loading bar.
		loading = true; // Remember that a load is currently in progress.
		$('#'+trgt).load(urll, function(){ // Load the specified container with the specified content.
		$('#loaderImage').hide(); // Hide loading bar.
                loading = false; // Forget that we're loading something.
		update(); // Update the user's stats bar.
		});
	}
}

Ok, I've made some changes after I copied it, so it may not actually work, but it should.

All it really does is checks whether or not something's already being loaded. If it is, then the request is ignored completely. If something isn't being loaded, then it continues on with the request.

To use is, all I do is call the function, and specify what I want to do. It's so simple yet works so well.

Code:
onclick="load('quest_0000000012', 'quest.php?quest=0000000012');"
The above code is generated by my page.php file, which serves the user a page, in this case the quests page, upon request.

But be warned. This offers very little error handling. If the .load function fails, your user is going to be stuck with a loading bar. :| I'll probably build more stuff into this as my game progresses. Progress is slow at the moment.


I rambled on a bit, but I've been up all night and it is almost 6AM, so I can only hope the mass of garbled text above actually helps someone. :redface:
 

essellar

Community Advocate
Community Support
Messages
3,295
Reaction score
227
Points
63
The problem with that approach is that it prevents all actions that use the load() function rather than just a repeat of the action currently being carried out. It may work perfectly in your application, but I just want to point out that this is not a general solution.
 

spacepir

New Member
Messages
41
Reaction score
2
Points
0
The problem with that approach is that it prevents all actions that use the load() function rather than just a repeat of the action currently being carried out. It may work perfectly in your application, but I just want to point out that this is not a general solution.
I'll agree with you on that. I guess you could add more parameters to the function, and check the "priority" of the request. Depending on the priority of the request already in progress, you could have it decide whether or not to carry on, but then things get a little complicated with security, etc. I could easily append the priority by using the "Inspect Element" feature that most browsers have.

More rambling, hehe :redface:.
 
Top