0

Consider the following code:

            $(document).ready(function(){

                var table1 = $("table").eq(0);
                var row_list;
                var rows;
                var x;
                var y;

                $("#mybutton").click(function(){

                    row_list = table1.find("tr");
                    rows = row_list.length;
                    x = $("#field_x").val();
                    y = $("#field_y").val();

                    if(x>rows || y>rows){

                         var num;   
                         if(x>y) num=x;
                         else num=y;
                         var n = num-rows;    
                         var row; table1.find("tr").eq(0).clone();

                         while(1){
                            row = table1.find("tr").eq(0).clone();
                            table1.append(row);
                            n--;
                            if(n===0) break;
                         }

                         n = num-rows;    
                         var td;

                         while(1){
                            td = table1.find("td").eq(0).clone();
                            table1.find("tr").append(td);
                            n--;
                            if(n===0) break;
                         }

                    }

                    var text = $("#text").val();
                    var css = $("#css").val();
                    $("table:eq(0) tr:eq(" + (x-1) + ") td:eq(" + (y-1) + ")").text(text).css("color", css);

                });


                table1.find("td").click(function(){
                    $(this).html("");
                });


            });
            * {
                font: 14px normal Arial, sans-serif;
                color: #000000;
            }
            table {
                margin: 50px auto;
            }
            table, td {
                border: 1px solid #aaa;
                border-collapse: collapse;
            }
            th {
                padding: 10px;
                font-weight: bold;
            }
            td {
                background-color: #eeeeee;
                width: 80px;
                height: 80px;
            }
            table:first-child tr td {
                cursor: pointer;
            }
            td[colspan="4"]{
                text-align:center;
            }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
            <tbody>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </tbody>
        </table>
        <table>
            <thead>
                <tr>
                    <th colspan="4">Fill a field:</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Text: <br/><input type="text" id="text" value=""></td>
                    <td>Field X: <br/><input type="text" id="field_x" value=""></td>
                    <td>Field Y: <br/><input type="text" id="field_y" value=""></td>
                    <td>CSS: <br/><input type="text" id="css" value=""></td>
                </tr>
                <tr>
                    <td colspan="4"><button id="mybutton">Fill</button></td>
                </tr>
            </tbody>
        </table>

What the program does is the following:

The user can choose a field by giving an x-value and a y-value. In this field the content from the input field with label "Text" is displayed. - This part of the program works fine.

If the user chooses an x-value or a y-value larger than the current number of rows (columns), rows and columns are added until the number of rows/columns is equal to the value in the x-(or y-) field. - This part of the program also works fine.

The only functionality that does not work is the following: If the user clicks on one of the non-empty fields in the table, the content of the table is supposed to go back to its natural (empty) state.

To this end, the following function was added to the code (see last couple of lines in the javascript part of the code):

table1.find("td").click(function(){
         $(this).html("");
});

This piece of code basically means: If the user clicks on any box ("td") in the table, the content of this box should disappear.

This is more or less the most simple part of the code. But it's also the one aspect that doesn't work. More precisely: It works for the original boxes, but it doesn't work for any boxes that were added. - And I don't get why it behaved that way.

Syntac
  • 1,687
  • 11
  • 10
Tommy
  • 699
  • 4
  • 11
  • 26

3 Answers3

4

If you are dynamically adding elements to the DOM and expect to be attaching events to them, you should consider using event delegation via the on() function :

// This will wire up a click event for any current AND future 'td' elements
$(table1).on('click', 'td', function(){
     $(this).html("");
});

Simply using click() on it's own will only wire up the necessary event handlers for elements that exist in the DOM at the time of that function being called.

Rion Williams
  • 74,820
  • 37
  • 200
  • 327
  • perfect! Thank you very much for the explanation ... didn't know about that before – Tommy Feb 09 '17 at 02:25
  • Attaching a click handler to the entire table accomplishes the same goal. Even if new rows and cells are added, the handler is on the table, so clicking on those new cells will still have the desired effect. – Scott Schupbach Feb 09 '17 at 02:28
1

You're assigning the event handlers before the user has a chance to input any data. This means that if an additional row or column is added, the new <td>s need event handlers added manually.

Alternately, you can add a single click handler to the entire table:

table1.click(function (ev) { $(ev.target).html(''); }

The ev.currentTarget property will be the <table> element because that's the element the event handler is registered to, but the ev.target property will be the <td> element that you're looking for.

Here's a JSFiddle to experiment with.

Scott Schupbach
  • 1,284
  • 9
  • 21
1

Hey there here's what I thought the answer might be,

HTML File:

<!DOCTYPE html>
<html lang="de-DE">
    <head>
        <meta charset="UTF-8" />
        <style>
            * {
                font: 14px normal Arial, sans-serif;
                color: #000000;
            }
            table {
                margin: 50px auto;
            }
            table, td {
                border: 1px solid #aaa;
                border-collapse: collapse;
            }
            th {
                padding: 10px;
                font-weight: bold;
            }
            td {
                background-color: #eeeeee;
                width: 80px;
                height: 80px;
            }
            table:first-child tr td {
                cursor: pointer;
            }
            td[colspan="4"]{
                text-align:center;
            }

            .pre-height {
                min-height: 80px;
            }
        </style>
    </head>
    <body>
        <table>
            <tbody>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td class="pre-height"></td>
                    <td class="pre-height"></td>
                    <td class="pre-height"></td>
                    <td class="pre-height"></td>
                </tr>
            </tbody>
        </table>
        <table>
            <thead>
                <tr>
                    <th colspan="4">Fill a field:</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Text: <br/><input type="text" id="text" value=""></td>
                    <td>Field X: <br/><input type="text" id="field_x" value=""></td>
                    <td>Field Y: <br/><input type="text" id="field_y" value=""></td>
                    <td>CSS: <br/><input type="text" id="css" value=""></td>
                </tr>
                <tr>
                    <td colspan="4"><button id="myButton">Fill</button></td>
                </tr>
            </tbody>
        </table>

        <script src="jquery.min.js"></script>
        <script src="jack.js"></script>

    </body>
</html>

JACK.JS file:

window.onload = function() {

'use strict';

/**
 * Appends 'n' number of rows to the table body.
 *
 * @param {Number} n - Number of rows to make.
 */
var makeRows = function(n) {
    let tbody= document.getElementsByTagName("table")[0].getElementsByTagName("tbody")[0],
        tr = document.querySelector("table:first-of-type tbody tr");

    for (let i = 0; i < n; i++) {
        let row = Node.prototype.cloneNode.call(tr, true);
        tbody.appendChild(row);
    }
};

/**
 * Appends 'n' number of cells to each row.
 *
 * @param {Number} n - Number of cells to add to each row.
 */
var makeColumns = function(n) {
    let addNCells = (function(n, row) {
        for (let i = 0; i < n; i++) {
            let cell = Node.prototype.cloneNode.call(td, true); 
            row.appendChild(cell);
        }
    }).bind(null, n);

    let tbody= document.getElementsByTagName("table")[0].getElementsByTagName("tbody")[0],
        td = document.querySelector("table:first-of-type tbody tr td"),
        rows = document.querySelectorAll("table:first-of-type tbody tr");

    rows.forEach(function(row) {
        addNCells(row);
    });
};



    document.getElementById("myButton").addEventListener("click", () => {
        let x = document.getElementById("field_x").value,
            y = document.getElementById("field_y").value;

        makeColumns(x);
        makeRows(y);
    });


    /**
     * Newly added code
     */
    (function() {
      let table = document.querySelector("table");
      // We will add event listener to table.
      table.addEventListener("click", (e) => {
          e.target.innerHTML = "";
          e.target.style.backgroundColor = "orange";
      });
    })();

  };

Edit: And I didn't even answer the question completely. You might wanna attach event listener to the nearest non-dynamic parent so that click event will bubble up and you can capture that, check the code under the comment newly added code.

hungryWolf
  • 391
  • 1
  • 3
  • 15
  • Well most part of it, It's not complete but I thought this part might be the crucial one and I did it all in vanilla, nice and clean – hungryWolf Feb 09 '17 at 03:30