Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to addEventListener to table cells

I'want to add an eventListener to the table cells so each time a table cell is clicked to execute a function .

var getDaysInMonth = function (year, month) {
    return new Date(year, month, 0).getDate();
}



var calendar = {
    month: function () {
        var d = new Date();
        return d.getMonth() + this.nextMonth;
    },

    year: function () {
        var y = new Date();
        return y.getFullYear();
    },

    nextMonth: 1,
    
    cellColor: 'white',
    
}



var loopTable = function () {
    var daysInMonth = getDaysInMonth(calendar.year(), calendar.month());
    var table = document.getElementById('myTable');
    var rows = table.rows;
    var l = 1;
    var month = calendar.month();
    var year = calendar.year();
    var firstDay = new Date(year + "-" + month).getDay();
    var currentDay = new Date().getDay();
    var dayOfMonth = new Date().getDate();

 
    for (let i = 1; i < rows.length; i++) {

        if (rows[i] == rows[1]) {

            var k = 1;

            for (let j = firstDay; j < rows[i].cells.length; j++) {

                if (k === dayOfMonth && calendar.nextMonth === 1) {
                    rows[i].cells[j].style.backgroundColor = calendar.cellColor;
                

                }

                if (k <= daysInMonth) {
                    rows[i].cells[j].innerHTML = k;
                    k++
                }

            }
        } else {
            for (let j = 0; j < rows[i].cells.length; j++) {
                if (k === dayOfMonth && calendar.nextMonth === 1) {
                    rows[i].cells[j].style.backgroundColor = calendar.cellColor;
                }
                if (k <= daysInMonth) {
                    rows[i].cells[j].innerHTML = k;
                    k++
                }
            }
        }
    }
}

loopTable();
clickCell();

function monthTitle() {

    var monthsArray = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'];
    monthNum = calendar.month();
    var monthName = monthsArray[calendar.month() - 1] + '' + calendar.year();
    var title = document.getElementById('calendarTitle');
    var nextArrow = document.getElementById('nxt');
    var leftArrow = document.getElementById('prev');

  
    if (monthName === ('Dec.' + '' + calendar.year())){
        xmas();
    }
    if (monthNum >= 12) {
        nextArrow.className += ' inactiveLink';
    } else if (monthNum <= 1) {
        leftArrow.className += ' inactiveLink';
    } else {
        nextArrow.classList.remove('inactiveLink');
        leftArrow.classList.remove('inactiveLink');
    }

    title.innerHTML = '';
    var titleNode = document.createTextNode(monthName);
    title.appendChild(titleNode);


}
monthTitle();

function nextMonth() {
    clearTable();
    calendar.nextMonth += 1;
    monthTitle();
    loopTable();
}

function previousMonth() {
    clearTable();
    calendar.nextMonth -= 1;
    monthTitle();
    loopTable();
}

function clearTable() {
    var table = document.getElementById('myTable');
    var rows = table.rows;

    for (var i = 1; i < rows.length; i++) {
        cells = rows[i].cells;
        for (var j = 0; j < cells.length; j++) {
            if (cells[j].innerHTML = '') {
                cells[j].style.display = 'none';
            }
            cells[j].innerHTML = '';
            cells[j].style.backgroundColor = '#D9534F';
            cells[j].style.emptyCells = 'hide';
        }
    }
}

var next = document.getElementById('nxt');
var previous = document.getElementById('prev');
var table = document.getElementById('myTable');
var cell = table.rows;
next.addEventListener('click', nextMonth);
previous.addEventListener('click', previousMonth);



function clickCell() {
    var row = document.getElementById('myTable').rows;
    
    for (var i = 0; i < row.length; i++) {
        for (var j = 0; j < row[i].cells.length; j++ ) {
  					
            row[i].cells[j].addEventListener('click', function(){
  					console.log('click');
            })
        }
    }
}
clickCell();
body {
            background-color: rgb(0, 121, 191);
        }
        
        table {
            width: 50%;
            background-color: #D9534F;
            border: 1px solid white;
            padding: 10px;
            padding-bottom: 20px;
            font-size: 25px;
            border-radius: 25px;
            position: relative;
            margin: auto;
        }
        
        td {
            border: 1px solid white;
            text-align: center;
            font-weight: 600;
            font-size: 20px;
            padding: 20px;
        }
        
        th {
            height: 50px;
        }
        
        .calArrows {
            text-decoration: none;
            color: white;
            font-size: 35px;
        }
        
        #nxt {
            font-size: 30px;
            position: absolute;
            top: 0;
            right: 25%
        }
        
        #prev {
            font-size: 30px;
            position: absolute;
            top: 0;
            left: 25%;
        }
        
        #calendarTitle {
            font-family: 'Indie Flower', cursive;
            font-weight: 600;
            font-size: 25px;
            color: white;
        }
        
        .inactiveLink {
            cursor: not-allowed;
            pointer-events: none;
             
        }
        
        #myTable {
            empty-cells: hide;
        }
        
        .xmasDec {
            width: 90%;
            height: 70%;
            position: absolute;
            top: -10%;
            left: 5%;
        }
        
        #calWraper {
            position: relative;
        }
        
        #myCan {
            position: absolute;
            top: 0;
            left: 10%;
            width: 90%;
            height: 70%;
            opacity: 0, 5;
        }
<body>
    <canvas class="myCan" width="100" height="100"></canvas>
    <div id="calWraper">
        <table id="myTable">
            <caption id="calendarTitle">Test</caption>
            <tr>
                <th>Sun</th>
                <th>Mon</th>
                <th>Tue</th>
                <th>Wed</th>
                <th>Thur</th>
                <th>Fri</th>
                <th>Sat</th>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
            </tr>
        </table>
        <canvas id="myCan" width="200" height="200" style="background-color: transparent"></canvas>
            <a href="#" id="prev" class="calArrows"><i class="fa fa-arrow-left" ></i></a>
        <a href="#" id="nxt" class="calArrows"><i class="fa fa-arrow-right" ></i></a>



    </div>



</html>

I tried by creating a function that it will loop through rows and cells and add the eventListener to each . But it seems that its not working , its working on random instances which is really strange behavior . Here is the function i create:

function clickCell() {
    var row = document.getElementById('myTable').rows;
 for (var i = 0; i < row.length; i++) {
        for (var j = 0; j < row[i].cells.length; j++ ) {
                    console.log(row[i].cells[j].innerHTML);
            row[i].cells[j].addEventListener('click', function(){
                    console.log('click');
            })
        }
    }
}
like image 621
Christodoulou Andreas Avatar asked Sep 21 '17 10:09

Christodoulou Andreas


2 Answers

It seems your canvas is overlapping your table. Because of that td elements in your table are never clicked.

You will need to add CSS property pointer-events:none to your canvas.

#myCan {
    ...
   pointer-events: none;
}

This way it won't block table from being clicked anymore.

You can also add event listeners to your cells way simpler:

document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", function() {
    // Here, `this` refers to the element the event was hooked on
    console.log("clicked")
}));

That creates a separate function for each cell; instead, you could share one function without losing any functionality:

function clickHandler() {
    // Here, `this` refers to the element the event was hooked on
    console.log("clicked")
}
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", clickHandler));

Some browsers still don't have forEach on the HTMLCollection returned by querySelectorAll, but it's easily polyfilled:

if (!HTMLCollection.prototype.forEach) {
    Object.defineProperty(HTMLCollection.prototype, "forEach", {
        value: Array.prototype.forEach
    });
}

If you have to support truly obsolete browsers that don't have Array.prototype.forEach, see the polyfill on MDN.

like image 170
Krzysztof Atłasik Avatar answered Sep 22 '22 02:09

Krzysztof Atłasik


This is a case for event delegation: Hook the click event on the table (or table body), not individual cells, and then determine which cell was clicked by looking at event.target and its ancestors.

Simplified example:

document.querySelector("#my-table tbody").addEventListener("click", function(event) {
  var td = event.target;
  while (td !== this && !td.matches("td")) {
      td = td.parentNode;
  }
  if (td === this) {
      console.log("No table cell found");
  } else {
      console.log(td.innerHTML);
  }
});

Live Copy:

document.querySelector("#my-table tbody").addEventListener("click", function(event) {
  var td = event.target;
  while (td !== this && !td.matches("td")) {
      td = td.parentNode;
  }
  if (td === this) {
      console.log("No table cell found");
  } else {
      console.log(td.innerHTML);
  }
});
table, td, th {
  border: 1px solid #ddd;
}
table {
  border-collapse: collapse;
}
td, th {
  padding: 4px;
}
<table id="my-table">
  <thead>
    <tr>
      <th>First</th>
      <th>Last</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Joe</td>
      <td>Bloggs</td>
    </tr>
    <tr>
      <td>Muhammad</td>
      <td>Abdul</td>
    </tr>
    <tr>
      <td>Maria</td>
      <td>Gonzales</td>
    </tr>
  </tbody>
</table>

Note that instead of the loop you could use the new (experimental) closest method on elements:

var td = event.target.closest("td");

...but A) It's still experimental, and B) It won't stop when it reaches the tbody, so in theory if you had nested tables, would find the wrong cell.

If you need to support browsers that don't have Element.prototype.matches, in this specific case you could use td.tagName !== "TD" instead of !td.matches("td") (note the capitalization).

like image 36
T.J. Crowder Avatar answered Sep 18 '22 02:09

T.J. Crowder