views:

436

answers:

7

Is there a possible way to synchronize events in javascript?

My situation is following: I have a input form with many fields, each of them has a onchange event registered. there is also a button to open a popup for some other/special things to do in there.

My requirement is, that the onchange event(s) are finished before I can open the popup.

Any ideas how I can achieve that without using setTimeout?

EDIT: further explanation of requirements:

To clarify my situation I try to detail what I'm doing.

I got a form with some input items (order entry matrix form, e.g. article, serial#, count). Every time user changes data in one of the fields an ajax call is triggered by an onchange event to validate the user input and read additional data (e.g. presetting/formating one of the other fields). These ajax calls are heavy and cost time, so I have to avoid duplicate validations. There is also a button which opens a popup which gives the user an other form to change data he entered before line by line, so it is absolutely necessary that all validations are done before this popup is opened. At the moment I try to synchronize the onchange events and the popup opening using setTimeout (popup isn't opened before all validations are done), which causes problems at my customers site because these popups are trapped by the popup blocker. So I need to open my popups without getting stopped by some popup blocker (IE 6/7/8).

Because of my matrix-form I just can't validate all input items before opening the popup, I need to validate only those which have been changed and are not validated yet (should be at most 1).

+2  A: 

It sounds like you are doing form validation, with an automatic popup when the form has been fully completed. To do that, you write a single validation function in javascript that checks every field on the form. You can fire this function from each of your OnChange events, and have the function open the popup when the entire form successfully validates.

Consider checking out jQuery, when you have a little free time.

http://jquery.com/

Robert Harvey
Theoretically possible, but i have to ensure, that only those values are validated that have changed. thats because the field validations are moderatly complex functions which get some additional values via ajax from the database.addionally, if i validate all fields in every onchange trigger, i would double validate them.
rag
I suppose you could pass in the name of the control that is changing to your function, and run it through a case statement.
Robert Harvey
yes, true, good idea.but: who is executing the code?what i mean is: i want the onchange to be execute if user changes some value and leaves the field OR hits the button.in the first case just the field validation should be done, in the second case (button) a popup should be opened.
rag
onblur should fire for the field if the user tabs out OR clicks the button.
Robert Harvey
to understand this right: you suggest using onchange to set a variable to a input-item name and onblur to check which item has to be validated. at the end of the validate part set the variable back to null. in the onclick of the button i check if any field has to be validated, do this validation and open the popup (if validate succeeded).
rag
To clarify, let's say the user changes a field, and then clicks the button. At the moment that he clicks the button, the OnChange event will fire for that field, and then the OnClick event will fire for the button. Does that make sense?
Robert Harvey
So you can use the OnChange event to validate the field and set a flag for that field, and use the OnClick event on the button to check the flags to make sure all of the fields were validated, and open your popup.
Robert Harvey
A: 

If you set a global variable and use setTimeout to check if it is set properly. Depending on how complex the situation is you can either use a boolean, two booleans, a number that increments, or even an object. Personally I would proly use an object as that way I know which one hasn't fired yet. something like
var isDone = {username: 0, password: 0, password2: 0};

Ballsacian1
i'm using setTimeout at the moment, but get problems with popup blockers this way.so no setTimeout allowed....
rag
A: 

Let assume by input fields you are meaning only text inputs and not any checkboxes or comboxes( I'm guessing you are trying to make a sort of auto-completion). My advice is to use onkeyup and onkeydown.

var keypressed = false;

function onkeydown( )
{
   keypressed = true;
}

function onkeyup( )
{
  keypressed = false;
  setTimeout( function()
              { 
                 if (!keypressed) 
                    show_popup();
                 else 
                    setTimeout( this.calee,1000)
               }, 1000 );
}
Artem Barger
not sure how onkeyup/down can help me. this thing is about field validation with fetching of additional data with ajax. all this should be finished, before the popup is opened by the user clicking on a button.
rag
In order to see all the picture and what exactly you are trying to do and which part of your solution fails, please provide more details and all restriction you have.
Artem Barger
+1  A: 

you can set up a little callback to your onchange events to insure that all of your validation occurs before the popup.

function onChange(callback)
{
    // Do validation

    // Call the callback
    callback();
}

function showPopup()
{
    // Show the popup
}

Then on your onchange call just call

onChange(showPopup);
Jon Erickson
A: 

Set flags (variables) for each group of validations.

  • Initiate the flag at 0.
  • Set the flag to 1, when validation is complete for the group.
  • When the user pops the button, if all flags are 1, popup the window.

The callback that Jon mentioned would solve the problem of "what do you do if they are not yet all validated?"


EDIT: Added after clarification:

Have you considered adding the popup button, via DOM methods (easy) (or innerHTML, if you like), after everything is validated? That way, there is no option shown before its time. :D

Also, do you test if a popup is blocked? If it is, you could branch to either a notice to the user that their blocker is blocking the editor; or to loading your editor into an iframe automatically; or to loading the editor to the main page via DOM methods (appending documentFragment, etc.).

Some blockers give users the option to block even popups generated from clicking on links (which were traditionally off limits to blockers). I would think you would benefit from some kind of a backup method, or at least a warning system in place regardless.

HTH

Fran Corpier
for usability reasons, i'd rather not show/hide the button or add it, but rather change the look. this way, the user knows there IS something but that there is still stuff to do before it comes available. works best with additional clarifying text (set the button to readonly and the text to "please wait while stuff is processed")
Schnalle
A: 

i don't think i have completely understood your question, but here are some thoughts on solving problems you may have :)

first, i'd deactivate the popup-opening button when the ajax call is sent. then, when the requested data arrives and all validation is done, activate it again. you can do this with a counter: increment it for every sent request, decrement it as soon data arrives and validation is completed. activate the popup opening button when data arrives and the counter is zero. this prevents the user from clicking the popup opening button while there are still validation requests pending.

you can use the same technique for the input fields themselves: lock the input fields that await validation by setting them to readonly, unlock them when everything is done.

to prevent problems when the user changes form values while the ajax call hasn't yet returned, you have several options:

  • use a timer for sending the request: everytime an onchange event is fired, wait x seconds before sending the request. if another onchange event happens before the ajax request is sent, reset that timer. this way, several onchange events withing a certain timeframe trigger just 1 ajax request. this helps reducing load.

  • you can calculate and store checksums for every position, so if an onchange event is fired, calculate the checksums again and compare them. this way you know which parts really have been changed, avoiding unnecessary validation requests.

also, never bet on time (if i understood the settimeout stuff right). x seconds may be enough under normal circumstances, but in the worst case ...

Schnalle
A: 

We needed something similar for a wizard where some steps required AJAX validation. The user wouldn't be allowed to close the wizard by clicking Finish if there were any pending validations. For this we simply had a counter for pending validations, and a flag to signal if the user was wishing to close the wizard. The basic algorithm was:

  • If a new AJAX validation is initiated, increment the "pending" count.
  • When an AJAX validation returns, decrement the "pending" count.
  • If, upon decrementing, the pending count reaches zero, check the "finish" flag; if it is set, finish the wizard.
  • When the user clicks Finish, check the "pending" count; if it's zero, finish the wizard; it it's non-zero, set the "finish" flag.

This way, synchronization can be handled with just two variables ("pending", "finish").

I strongly advise against using multiple flags for each different AJAX operation; a state machine usually gets out of hand when states are tracked with multiple state variables. Try to avoid it unless it's absolutely necessary.

I also don't suggest using setTimeout to arbitrarily wait until desired conditions are met. With the counter approach above, your code will act on changing conditions, as soon as they change.

Ates Goral