2

I'm new to Javascript. I want to add onclick events to table rows. I'm not using JQuery.

I loop thru the rows and use a closure to make sure I have the state of the outer function for each row. The looping works. Using alerts, I see the function being assigned for each iteration. But when I click the row, no alert is displayed. Below is the HTML and code that can be loaded.

Why are the table row events not working?

<!doctype html>
<html lang="en">
<body>
<script>
function example4() {
    var table = document.getElementById("tableid4");
    var rows = table.getElementsByTagName("tr");
    for (var i = 0; i < rows.length; i++) {
        var curRow = table.rows[i];
        //get cell data from first col of row
        var cell = curRow.getElementsByTagName("td")[0];
        curRow.onclick = function() {
            return function() {
                alert("row " + i + " data="+ cell.innerHTML);
            };
        };
    }
}
function init() { example4(); }
window.onload = init;   
</script>
<div>
Use loop to assign onclick handler for each table row in DOM. Uses Closure.
    <table id="tableid4" border=1>
      <tbody>
        <tr><td>Item one</td></tr>
        <tr><td>Item two</td></tr>
        <tr><td>Item three</td></tr>
      </tbody>
    </table>
</div>
</body>
</html>
Evan Davis
  • 35,493
  • 6
  • 50
  • 57
Alex_B
  • 1,651
  • 4
  • 17
  • 24
  • 1
    You're returning a function within a function. This would require for another function within the `onclick` to call the returned function. – jeremy Dec 26 '12 at 18:00
  • This question really has nothing to do with closures. – Evan Davis Dec 26 '12 at 18:06
  • @Mathletics: I'm using closures because I want the event to return the row that was clicked. On an earlier version of the code, I kept getting row 3 always being returned. My understanding is that closures will solve this problem. – Alex_B Dec 26 '12 at 18:13
  • You understand correctly – mplungjan Dec 26 '12 at 18:38

3 Answers3

9

This seem to be the canonical way

DEMO

function example4() {
    var table = document.getElementById("tableid4");
    var rows = table.rows; // or table.getElementsByTagName("tr");
    for (var i = 0; i < rows.length; i++) {
        rows[i].onclick = (function() { // closure
            var cnt = i; // save the counter to use in the function
            return function() {
              alert("row"+cnt+" data="+this.cells[0].innerHTML);
            }    
        })(i);
    }
}
window.onload = function() { example4(); }​

UPDATE: @ParkerSuperstar suggested that the i in (i) is not needed. I have not tested this but his fiddle seems to work.

mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • @mplungian: I'm trying to understand how this works. You've done two things. 1) You've enclosed the outer function in parens and added a parameter i. 2) You saved i as cnt in the outer function, so now the inner function sees cnt. I don't understand why the inner function doesn't see i. – Alex_B Dec 26 '12 at 18:45
  • That is exactly what a closure does. The first function takes a copy that stays static inside the inner function – mplungjan Dec 26 '12 at 18:46
1

I'm not quite sure why you're using a closure here, could you be a bit more elaborate?

The reason you're not seeing the desired alert is because within the onclick function, you're returning another function. I.e:

window.onload = function() {
    return function() {
        alert("Closure... why?");
    };
};

Something like this won't really work because you're never calling the nested function... try it without using the closure, or comment explaining why you want a closure because you're explanation didn't make much sense to me.

jeremy
  • 9,965
  • 4
  • 39
  • 59
  • I want to eventually return the row information when the row is clicked. I thought the way I nested a return f() inside a function makes the inner function close over the scope of the outer function's variables, thus giving me access to the row information. I wanted the alert to show me that information. – Alex_B Dec 26 '12 at 18:16
0

You just have to remove an extra function and script will be like this

<script>
 function example4() {
    var table = document.getElementById("tableid4");
cells = table.getElementsByTagName('td');

 for (var i=0,len=cells.length; i<len; i++){
 cells[i].onclick = function(){
    alert(this.innerHTML);

}
 }
}
 function init() { example4(); }
 window.onload = init;   
 </script>
zafus_coder
  • 4,451
  • 2
  • 12
  • 13