3

So I have a regular onclick event attached to a few buttons, each function that handles the onclick event does something different (so I can't reuse the same function for both events).

element1.onclick = function() {
    if(this.classList.contains('disabled') {
        return false;
    }
    // For example make an AJAX call
};

element2.onclick = function() {
    if(this.classList.contains('disabled') {
        return false;
    }
    // For example hide a div
};

I'm writing duplicate code for this 'disabled' class check, I want to eliminate this by hooking in some common onclick check then fire the regular onclick event if that check passes.

I know the below won't work but I think it will illustrate what I'm trying to do:

document.addEventListener('click', function() {
    // 1. Do the disabled check here
    // 2. If the check passes delegate the event to the proper element it was invoked on
    // 3. Otherwise kill the event here
});

I'm not using any JavaScript library and I don't plan to, in case someone comes up with 'Just use jQuery' type answers.

EDIT: Had to pass boolean third argument to addEventListener as true and everything is fine.

jbaranski
  • 1,214
  • 2
  • 15
  • 21

3 Answers3

4

Use event capturing, like so:

document.addEventListener('click', function(event) {
    if (/* your disabled check here */) {
      // Kill the event
      event.preventDefault();
      event.stopPropagation();
    }

    // Doing nothing in this method lets the event proceed as normal
  },
  true  // Enable event capturing!
);
broofa
  • 37,461
  • 11
  • 73
  • 73
  • I already tried this, this is the same as my example that I said didn't work. Because I have the onclick already attached to the existing elements and it always fires first for whatever reason. – jbaranski Dec 10 '12 at 13:50
  • Are you calling stopPropagation()? That's what prevents the event from propagating "down" to your button, where the onclick handler fires. – broofa Dec 10 '12 at 13:51
  • Note: event.preventDefault() is not strictly necessary in this case since vanilla button elements don't have default behaviors. But the `preventDefault()` call is commonly paired with `stopPropagation()` because there are lots of similar cases where elements do have default behaviors you want to prevent (e.g. link elements or input[type=`submit`] elements, etc.) – broofa Dec 10 '12 at 14:05
  • These events are all on link elements so in my case the preventDefault() call is necessary, but thanks for the info. – jbaranski Dec 10 '12 at 14:10
3

Sounds like you need to set the capture flag to true and then use .stopPropagation() on the event if a certain condition is met at the target, f.ex:

document.addEventListener('click', function(e) {
    if ( condition ) {
        e.stopPropagation();
        // do soemthing else, the default onclick will never happen
    }
}, true);​​​​​​​​​​​​​​​​​​​​​​

Here is a demo: http://jsfiddle.net/v9TEj/

David Hellsing
  • 106,495
  • 44
  • 176
  • 212
1

You can create a generic function that receives a callback:

//check everything here
function handleOnclick(callback) { 
    if(this.classList.contains("disabled")) {
       return false;
    } else {
     callback(); //callback here
    }
}

//and now on every onclick, just pass the custom behavior

element1.onclick = function() {
   handleOnClick(function() { 
        console.log('element1 onclick fire'); // For example hide a div
    });
};


element2.onclick = function() {
   handleOnClick(function() { 
        console.log('element2 onclick fire'); // For example ajax request
    });
};

Edit Based on your latest comment, let me know if this rewrite works for you... only one biding this time.

element1.customFunction = function() {
   handleOnClick(function() { 
        console.log('element1 onclick fire'); // For example hide a div
    });
};

element2.customFunction = function() {
   handleOnClick(function() { 
        console.log('element2 onclick fire'); // For example ajax request
    });
};

document.addEventListener('click', function() {
   //1. grab the element
   //2. check if it has the customFunction defined
   //3. if it does, call it, the check will be done inside
};
Deleteman
  • 8,500
  • 6
  • 25
  • 39
  • I still have to call handleOnClick in every event, which I don't want to do. You have the right idea though, will play around with something like this. Thanks. – jbaranski Dec 10 '12 at 13:47
  • No what I really wanted was to not write any validation code at all in the onclick event, but have it done somewhere else and then only fire the onclick event if that other validation passes. But with your example I learned something new today and can use this pattern later on, so thanks for your input. – jbaranski Dec 10 '12 at 14:05
  • Glad to help, but just as a side note, the validation on my code is done on the handleOnclick function, not on the onclick event... just saying. – Deleteman Dec 10 '12 at 14:07
  • You are correct maybe my comment wasn't clear, anyway I appreciate the input, this is a cool way of handling this situation. – jbaranski Dec 10 '12 at 14:13