22

I have an input field, which has two event handlers bound to it.

Validate & AutoSave

Obviously I want to validate before I save. If validation fails, the "invalid" class is added to the input and autosave will check for that class before it proceeds.

This works well enough, but is there a way to guarantee Validate runs before Autosave in all cases?

1

5 Answers 5

14

If you use JQuery to bind your events, it guarantees that handlers are fired in the same order that they were bound. Otherwise the order is officially undefined.

If you cannot use JQuery or a similar framework you can easily simulate this by using your own custom even binding, where your generic handler is a function which keeps an array of functions and calls them in order.

Sign up to request clarification or add additional context in comments.

1 Comment

an example would have been a great answer
9

Normally you'd have the Save event handler call Validate() which will return true if everything is fine and ready to be saved.

function onSaved() {
  if (!validate()) {
    // set class
    return;
  }

  // do the save
}

Comments

2

Already answered - but just to add this piece of knowledge, the order of event handlers can not be relied upon. It may in any given implementation be predictable, but this can change from one (Javascript) implementation to the next and/or over time. The only thing certain is that they all will be executed - but not in what order.

Note that the situation is similar when there is an event handler for a DOM object and another one for the same event for a child or parent - which of those is executed first is not always clear as well. See http://www.quirksmode.org/js/events_order.html

Comments

1

Why not attach just one handler -- Validate -- and call AutoSave from inside it?

For an answer to your question that isn't also a question, see this post or this one or this one.

3 Comments

because they represent separate modules, which may or may not occur together. Writing them as a single function (which is obvious) has the effect of over coupling the code.
I disagree. They are coupled, as evidenced by the fact that you want one to occur only after the other runs. Putting them together in one function doesn't create that coupling. It acknowledges it. (Secondly, just because you call them both inside some function doesn't mean that they have to always be called in that way. They can each still be written in a way that preserves their independence.)
I know this is forever ago but to add to this, you could rename Validate to ValidateAndAutoSave to better imply its intended use because it looks like validation implies autosaving but autosaving can happen independently with no implied association.
-1

It's an old question, but I'm surprised nobody suggested placing your two callbacks in a single wrapper and only registering the wrapper as the event handler callback:

const input = document.querySelector('input');
input.addEventListener('input', ()=>{
    validate();
    autoSave();
});

function validate(){
    // Set `invalid` class if invalid.
}
function autoSave(){

    // Abort if input invalid.
    if (input.classList.contains('invalid') === true){
        window.alert("You suck at inputting. I'm not saving this.");
        return;
    }
    
    // Perform auto-save...
}

2 Comments

Seems like the accepted answer, but with extra steps..
@Wimanicesir The accepted answer places the call to autoSave inside validate. Wrapping the functions keeps them separate while ensuring they're called sequentially.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.