Sachin
Sachin

Reputation: 18747

jQuery function gets called twice for each click

Setup:

I have written a jQuery function to update table cells of table_2, when a row in table_1 is clicked. Here is what I have written:

    <script type="text/javascript">
        $("tr").live('click',function() {
            var host = $(this);
            alert('A row in table 1 is clicked!');

            var count = host.find("td").eq(2).text();
            $("#myTable_2 tr:eq(0) td:eq(1)").text(count);
            $("#myTable_2 tr:eq(1) td:eq(1)").text(5);
        });
    </script>

The Problem:

When I step-through this function using FireBug, I can see the cell data in myTable_2 is being changed. BUT, for every click, the function is executed twice. I can see the alert box appearing twice for each click.

Can somebody tell me why does this happen? And how to avoid this?

Upvotes: 11

Views: 18614

Answers (5)

Skeletor
Skeletor

Reputation: 3403

Some elements may have the same properties (class name, tag name ect.) wich you may overlook. This can cause such a conflict. In the example below the "tr" element is used as the selector for the alert, but the script has two nested "tr" elements that contain the "text" target. Thus, with a single click you get an alert fired for each (from inside out) "tr" element seperately. This is called bubbling. You could simply use stopPropogation() to stop the bubbling.

$("tr").live('click',function() {
    alert('A row in table 1 is clicked!');
    event.stopPropogation();
});

<table>
  **<tr>**
    <td>    
      <table id="myTable_1">
        **<tr>**
         <td>Test</td>
        **</tr>**
      </table>
    </td>
  **</tr>**
</table>

http://jsfiddle.net/6UmpY/97/

Upvotes: 0

jenson
jenson

Reputation: 1

It is because $("tr").live('click',function() {}); ^^^^^ has 2 counts in the html. To ensure .live () or .delegate() is executed once, the selector in $(selector).delegate() is better to be "$(table[name=users])" rather than $('td') or $('tr')

Upvotes: 0

Paulo Almeida
Paulo Almeida

Reputation: 2199

just simply avoid the propagation of the click

$("tr").live('click',function() {

        ...

        $( event.toElement ).one('click', function(e){ e.stopImmediatePropagation(); } );
    });

Upvotes: 12

Rob W
Rob W

Reputation: 348972

Either of the following:

  1. The clicked row is inside another row (two rows are clicked). (example)
  2. The code you've shown is executed twice (example).

To solve this, make your selector more specific. If you're using jQuery 1.7+, use .on instead of live: http://jsfiddle.net/6UmpY/3/

$(document).on("click", "#myTable_1 > tbody > tr", function() {
    // This selector will only match direct rows of the myTable_1 table

Note: Using .on instead of live did not solve the problem.
Using a more specific selector did fix the issue.
If you love live, the following would also work: http://jsfiddle.net/6UmpY/4/

$("#myTable_1 > tbody > tr").live("click", function() {

Upvotes: 11

thecodeparadox
thecodeparadox

Reputation: 87073

assume table_1 is the id of first table.

$("#table_1 tbody").on('click','tr', function() {
            var host = $(this);
            alert('A row in table 1 is clicked!');

            var count = host.find("td").eq(2).text();
            $("#myTable_2 tr:eq(0) td:eq(1)").text(count);
            $("#myTable_2 tr:eq(1) td:eq(1)").text(5);
        });

NOTE: live() has been deprecated, so write like above. you code execute twice because tr selector belongs to both tables and event bind twice.

You can also use delegate():

$("#table_1 tbody").delegate("tr", "click", function(){
     var host = $(this);
     alert('A row in table 1 is clicked!');
     var count = host.find("td").eq(2).text();
     $("#myTable_2 tr:eq(0) td:eq(1)").text(count);
     $("#myTable_2 tr:eq(1) td:eq(1)").text(5);
});

Upvotes: 3

Related Questions