PDA

View Full Version : Fast clicking breaks script



Krabat
01-24-2008, 01:33 PM
First off: I've searched the forum but since I'm not really sure what causes the problem I came back empty handed. Secondly, I spent 15 minutes trying to reformat my code until I realized that it might actually be not that helpful, so I'll try to explain the problem and post some code later if anyone wants to see it.

OK, my setup is approximatly as follows: I've got a set of items, broken up into different categories, each item is represented as a link, the categories are div tags. The user can select one of those items per category, so when he clicks another item in a category where there's already one selected, the previous selected one should deselect and the current one should switch to selected.

To do this every link calls a function called "clicked", to which it hands it's own category number, item number and the state it's currently in (0 for inactive, 1 for active and 2 for selected). If the state is "1" "clicked" knows the user wants to select the item, so it checks if there's a previously selected item in the category, saved in an array "cat".


if (cat[key] != -1)

If it's not "-1" it means there's an item selected, so "clicked" proceeds to deselecting it by calling a function called "changeState" which writes out the new link for the item (with a different call to "clicked"):


featureText = "<a href=\"#\" class=\"active\" onClick=\"clicked(" + key +"," + value + ",1)\">" + features[key][value][0] + "</a>";

It then replaces the innerHTML property of the List Item this item is saved in.

When that's done the function "clicked" proceeds to making the link the user just clicked the selected one, again using "changeState" and saving the item number in the "cat[]" Array.

Now inherently this all works, the user can always select only one item within each category. Unless one link is clicked multiple times in quick succession, or all the links in a category are clicked in quick succession. Then the script stops working insofar as now the user can select all the items within a given category.

I've placed an alert with some variables inside the "clicked" function to find out why that happened and saw to my surprise that the entry for the category in the "cat[]" array, which should either show "-1" if nothing is selected or the number of the selected item, became undefined when clicking the links very fast.

I'm quite at a loss here and would appreciate any input on whether this is a common Javascript problem (with common solutions) or whether this might be a problem within my code (in which case I would post the code later on to see if anyone can spot the error).

Thanks in advance!

jscheuer1
01-25-2008, 06:12 AM
I'd need to see the full code, or perhaps just more of it to be specific, but the concept is pretty clear to me. You need something to prevent subsequent clicks from doing anything until the script has finished carrying out all of the operations that a given click puts into motion. This can often be done with a flag that activates at the beginning of the process and that is deactivated at the end. As long as the flag is active, the user can click away all that he or she wants, but will have to wait until the script is ready, before doing so will have any result.

So let's say you have something like:


<a href="detail_1.htm"
onclick="do_something();return false;"><img
src="icon_1.gif" border="0"></a>

and do_something() is like:


function do_something(){
if(do_something.running)
return;
do_something.running=true;
here is where the actual work of the function will take place
do_something.running=false;
}

Now, if do_something hands off processing to another function or set of functions, the action:


do_something.running=false;

may be placed at the end or ends, if they can branch out various ways, of the train of operations that these functions carry out. Wherever you put it, it should be at that point in the code where it would be safe for the user to start a new do_something(), but also before any return that can end processing - you don't want to end up with do_something being permanently shut off.

Krabat
01-25-2008, 08:07 PM
Thank you for the reply!

Yeah, I guess the code would be usefull after all. I just can't post it right now since I'm not at work but I will do so the first thing I get there on Monday. I'm just gonna have to figure out how to shorten it to the relevant bits... whatever they are. ;-)

But interestingly enough, I thought of doing something like what you suggested, yesterday after I made the post. I'm just not sure if it was the same and if it works in Javascript (would work in any other language I know.)

I had:


<script>
function clicked(value,key,currentState) {
do_something();
}

function changeState(value,key,newState) {
do_something_else();
}
</script>

and I changed it to:


<script>
var goAhead = true;

function clicked(value,key,currentState) {
if (goAhead) {
goAhead = false;
do_something();
goAhead = true;
}
}

function changeState(value,key,newState) {
do_something_else();
}
</script>

with the links calling "clicked" and "clicked" containing multiple calls to changeState all within the if-Block.

Now to test if that actually prevented multiple simultaneous calls to the function I put a slow fade effect in when changing the links and: lo-and-behold: Multiple calls were still possible, the animation started over and over whenever I clicked the link.

So maybe I'm getting wrong how Javascript works? Doesn't a JS function wait for a called function to return before it continues its execution?

Erm.. maybe I should read up on basic JS.

jscheuer1
01-26-2008, 08:26 AM
Yes, that would theoretically work, but it puts a variable into the global scope that doesn't need to be there. By assigning the flag as a property of the function, it is still available to the global scope if needed there, but cannot conflict with any other script, unless said script has an identically named function with an identically named property. Oh, and if its a property, its initial state can be 'falsy' undefined, which is generally better, as well. What you have is turning something off when the function starts to act as the flag, with a property though, it is more natural to turn it on to signify processing is occurring, and more intuitive. These are matters of preference/experience.

The one part that is a little dodgy though is:


function clicked(value,key,currentState) {
if (goAhead) {
goAhead = false;
do_something();
goAhead = true;
}
}

If do_something(); is as it appears to be, a separate function, and if it pauses in its execution, or exits after passing control to yet another function, clicked() may finish before it or before the full chain of events has completed. That's why I said that the resetting of the availability of (in this case clicked), should happen at the end of the function that you pass control off to, or at the end of the chain of functions that take control of the process.

Krabat
01-28-2008, 08:29 AM
Thanks again for the reply! I read your post over the weekend but I didn't want to answer before I got to work and would be able to post the code of my app. I tried to shorten it but then I decided I'd simply attach it as a file. I hope that's okay.

As the file hasn't got any comments I'll describe it a bit. First off: There's a little PHP in it. An array at the beginning of the file is a substitute for a later database. It contains the item categories and within them the items, each with a text, a price and an optional subarray of other items to remove or to add whenever this item is clicked. The other PHP block is simply writing the PHP array to a Javascript array, changing it from an associative multidimensional array to a normal multidimensional array. PHP also writes the array that later becomes undefined, the "cat" array which has a field for every category, containing the information on which item is currently selected.

Then there's the two Javascript functions, clicked and changeState. clicked decides what to do according to the state a link was in when it was clicked and then hand's that over to changeState. clicked is also the function checking the cat array for the currently selected item in a given category and giving it a new value (thus breaking it in the end).

A note on the dojo toolkit functions: I tried removing them but that didn't fix the problem so I left them in.

----

Oh, and regarding your earlier post: So when I set a variable as a property of a function, I can check whether it's true or false before even defining it and it will default to false? That's nice.

And about passing control to other functions: So "clicked" doesn't wait, after calling "changeState", for it to return? Why not? And how can I make it wait? :confused:


Anyway... thanks again for your help. While I'm still not sure how to fix my ugly little programm here I already learned something. Have a nice monday!