4

I have a situation where I am using the data attribute named data-command in many instances throughout a specific section of a site and instead of binding tons of separate click events I decided to just use the one and use a switch such as:

$('[data-command]').on('click', function(event) {

    // Prevent default click action
    event.preventDefault();

    // Get command
    var command = $(event.target).data('command');

    switch (command) {
        // Do stuff...
    }

    // Prevent default click action (IE 8)
    return false;

});

However it has just become an issue when trying to get it to work on data loaded via AJAX.

This obviously works..

$('#existing_element').on('click', '[data-command]', function(event) {

...but since it is supposed to work on many different pages in that section of the site the above wouldn't work on all pages.

I could just make sure to give a specific id to the parent wrapper where I load all my ajax data, but that would mean making two separate binding events with a bunch of the same code.

I also could do this to cover all bases..

$(document).on('click', '[data-command]', function(event) {

...but that's probably not such a wise idea binding an element to the document.

Edit: Html data is being loaded into the DOM via jQuery's html method.

Any clean way I can handle this or should I just create two different binding events to handle each situation?

Brett
  • 19,449
  • 54
  • 157
  • 290
  • Can you add the code of AJAX and how you're adding elements in the DOM – Tushar Sep 25 '15 at 13:22
  • `..but that's probably not such a wise idea binding an element to the document.` - why exactly? – raina77ow Sep 25 '15 at 13:23
  • @raina77ow http://stackoverflow.com/questions/12824549/should-all-jquery-events-be-bound-to-document - What I got out of that is that it should be avoided. – Brett Sep 25 '15 at 13:25
  • 1
    "I could just make sure to give a specific id to the parent wrapper…, but that would mean making two separate binding events…" Why would this require two events? Wouldn't this work: `$('').on('click', '[data-command]', function(event) {…})` – gfullam Sep 25 '15 at 13:26
  • @Brett "should be avoided" != "must never be done". It sounds like it would be acceptable in your circumstance. – gfullam Sep 25 '15 at 13:27
  • 1
    Isn't your case the same as ... `when the objects you are capturing events on are dynamically created/removed and you still want to capture events on them without having to explicitly rebind event handlers every time you create a new one`? – raina77ow Sep 25 '15 at 13:27
  • @Tushar Updated with how the html it being loaded into the DOM. – Brett Sep 25 '15 at 13:28
  • @gfullam No, because I normally want to *directly* bind to `[data-command]` and not delegate. The parent wrapper I mentioned was for the ajax parent only. – Brett Sep 25 '15 at 13:31
  • @raina77ow For the second scenario (ajax based), yes. – Brett Sep 25 '15 at 13:32

1 Answers1

2

Event delegation is the best approach to bind events on dynamically created elements. Since you don't want to use event delegation, use following approach to bind events.

$('[data-command]').off('click').on('click', clickHandler);

// Somewhere in the same scope
function clickHandler(e) {
    // Handle click event here
}

Add this after the dynamically created elements are added using html().

off('click') will first unbind the click event handlers that are applied previously and then on('click', will bind the click handler on all the elements matching selector.


Edit

This seems to be repeating the same code again and again. Can't I keep it DRY?

Yes, you can keep the code DRY and clean by creating a function to bind events and call the same function when you want to bind event.

function clickHandler(e) {
    // Handle click event here
}

function bindEvent() {
    $('[data-command]').off('click').on('click', clickHandler);
}

$(document).ready(bindEvent);

...

$.ajax({
    ...
    success: bindEvent
....
Tushar
  • 85,780
  • 21
  • 159
  • 179
  • Isn't this basically just binding the elements twice as you're saying to add this code to the page via `html`? I'm trying to figure out a way everything can be binded in the same thing. – Brett Sep 25 '15 at 13:39
  • @Brett This will not bind the event twice for the element, the previous bound event if first removed and then new event is bound. To do the same thing for all elements only once you'll need to use event delegation. – Tushar Sep 25 '15 at 13:41
  • Sorry, bad choice of words. What I meant by twice is having the same code twice rather than being bound twice. Like I could easily bind it with and without event delegation, but that just means repeating code, which is what I would be doing with this method. – Brett Sep 25 '15 at 13:44
  • @Brett Kindly check the update and let me know your comments – Tushar Sep 25 '15 at 13:51