1

I'm calling via ajax additional content where I add a jquery on() function for a click event. Each time I renew the content the event is also set again so at the end it get executed several times. How can I avoid this behavior?

How do I test if the click event is already set on the document?

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<a href="#" class="open-alert">Click</a>
<script>
    // first ajax load
    $(document).on('click', '.open-alert', function () {
        alert('hello world!');
    });

    // second ajax load
    $(document).on('click', '.open-alert', function () {
        alert('hello world!');
    });
</script>

I already try to just the jQuery.isFunction(), but I don't anderstand how to apply it in this case.

wittich
  • 2,079
  • 2
  • 27
  • 50

5 Answers5

4

You can Unbind the click event , if you getting more than one time exectuated.

$(document).unbind('click').on("click", ".open-alert", function () {
  //do stuff here
 });

Or you can also use it

$(document).off("click", ".open-alert").on("click", ".open-alert", function () { 

  });
Asif Raza
  • 971
  • 6
  • 14
3

Using

$(document).on('click', '#element_id', function() {
    //your code
});

Will check the DOM for matching elements every time you click (usually used for dynamically created elements with ajax)

But using

$('#element_id').on('click', function() {
    //your code
});

Will only bind to existing elements.

If you use the 1st example, you only need to call it once, you can even call it before your ajax call since it will recheck for matching elements on each click.

<script>
    $(document).on('click', '.open-alert', function () {
        alert('hello world!');
    });

    // first ajax load
    // second ajax load
    ...
</script>
Mokkun
  • 708
  • 4
  • 14
  • Thx for the clear explanation. I'm aware of this difference, but I need to call the event as I did, because there is another supajax where otherwise the even wouldn't be applied to. – wittich May 10 '17 at 07:26
  • @wittich Like I said $(document).on('click') will check the DOM on each click, you don't have to call the event twice, it will work on any following ajax query. It doesn't bind to a specific element, it looks for element on the DOM on each click, so it will always work even if new elements come after. – Mokkun May 10 '17 at 07:30
  • sorry but I still think your answer isn't the right one for my question. I look more for an answer like the one of [@saeed-ahmadian-masal](//stackoverflow.com/a/43885630/3001970) – wittich May 10 '17 at 13:36
1

jQuery check if event exists on element : $._data( $(yourSelector)[0], 'events' )

this return all of element events such : click , blur , focus,....

Important Note: $._data when worked that at least an event bind to element.

so now:

1.in your main script or first ajax script bind click event on element

<script>
   $(document).on('click', '.open-alert', function () {
      alert('hello world!');
   });
</script>

2. in secound ajax:

var _data =  $._data( $('.open-alert')[0], 'events' );
if(typeof _data != "undefined"){
    var eventClick = $._data( $('.open-alert')[0], 'events' ).click
    var hasEventClick = eventClick != null && typeof eventClick != "undefined";
    if(!hasEventClick){
         $(document).on('click', '.open-alert', function () {
             alert('hello world!');
         });
    }
}
Saeed Ahmadian
  • 1,112
  • 1
  • 10
  • 21
  • That looks like something I was looking for... I'll test it. – wittich May 10 '17 at 07:28
  • yes i know.. this should be work.. see this page : http://stackoverflow.com/questions/1515069/jquery-check-if-event-exists-on-element or this page : http://stackoverflow.com/questions/2518421/jquery-find-events-handlers-registered-with-an-object – Saeed Ahmadian May 10 '17 at 07:32
  • Seems like there is still a problem with your code... I get the error `TypeError: $._data(...) is undefined` see https://jsfiddle.net/g2srgjbj/ – wittich May 10 '17 at 07:44
  • Hmm we're getting closer here, but it is still not working as I want it. There should be not first and second load. Just one and the same snippet which only gets triggered the first time.. Something like that https://jsfiddle.net/ro5q7zaf/ – wittich May 10 '17 at 20:14
1

In case you cannot bind the event to the specific DOM element (which might happen if you use Turbolinks for example) you can use a variable to check whether you set the event or not.

Local scope

var clickIsSet = false;

// any ajax load
$(document).on('click', '.open-alert', function () {
    if ( clickIsSet ) {
        alert('hello world!');
        clickIsSet = true;
    }
});

Global scope

I don't recommend to make clickIsSet global, but in case you are importing/exporting modules you can do that:

// main.js
window.clickIsSet = false;

// any-other-module.js
$(document).on('click', '.open-alert', function () {
    if ( window.clickIsSet ) {
        alert('hello world!');
        window.clickIsSet = true;
    }
});
a.barbieri
  • 2,398
  • 3
  • 30
  • 58
  • I see your idea, but it would only allow to one link, right? – wittich May 10 '17 at 07:46
  • If you want to use it on several link elements you can do it. Just add other classes on the second argument `$(document).on('click', '.first-link, .second-link, .third-link', function () { ... });`. – a.barbieri May 10 '17 at 07:49
0

I get Confuse about your question but as far as understand your question I have three suggestions:

  1. Use Id element (as @Mokun write the answer)
  2. Use Common Function for call functionality instead use through the click event.(Make Sure of function does not overwrite your content by calling).
  3. Use of flag variable (or global variable for your tracking event) in jquery and identify your function call for particular execution.
wittich
  • 2,079
  • 2
  • 27
  • 50
Asav Vora
  • 61
  • 6