Add Event Handler in JScript - javascript

In the function, editCell(), which is called in response to an onclick event of an HTML table cell, I am trying this:
var tbl = [valid table ref];
var row = tbl.insertRow(-1); // insert at end.
var newCell = row.insertCell(-1);
newCell.className = "tblItems newItem";
newCell.innerHTML = "  Click to add a property item...";
newCell.onclick = "editCell(this);";
to create a new, 1-cell row at the bottom of the table, where hte new cell is as if it had been created with:
...
<tr>
<td class="tableItems newItem" onclick="editCell(this);">
  Click to add a property item...
</td>
</tr>
...
But the onclick is not being raised (or the function ref doesn't respond when it is).
A co-worker says to use:
newCell.onclick = function () {
editIt(this);
}
but it seems that "...(this)..." will refer to the running context.
What is the right way to add a function the takes an argument, to a newly-created cell reference in JScript?
Must work as far back as IE 8, but only needs to target IE.

newCell.addEventListener('click', editCell, false);
Or in older IE versions:
newCell.attachEvent('onclick', editCell, false);
This explains why using addEventListener is better than onclick.

.setAttribute("onclick","editCell(this);");

this will refer to newCell. However, you are trying to call the wrong function (editIt instead of editCell)
newCell.onclick = function () {
editCell(this);
}

Related

Why JavaScript Performs "click" event, when I don't click on the item?

I added eventListener on DOM object using JS, but this listeners triggers, as soon as page is loaded and it doesn't have sense, when I'm clicking on this item.
This is my code, where I'm adding eventListener to the item:
let table = document.getElementById('data_table' + deal);
for (let r = 0, n = table.rows.length; r < n; r++) {
table.rows[r].cells[2].addEventListener("click", logThis(this));
}
and my function which should be execute on item click, looks like this:
function logThis(me) {
console.log(me);
}
When browser renders page, clicking is performing itself, without my interference.
Please, if anyone here knows, why it happens, write the answer.
EDIT
When I'm clicking, on table cell, nothing happens
Adding my comment as an aswer here to help other beginners get into this issue.
Here you have mixed both addEventListener signature and the way you add onclick handlers in HTML.
When you attach an eventListener using JS, you dont have to invoke the function(ie no need to use the parenthesis). So your code will be like this:
table.rows[r].cells[2].addEventListener("click", logThis);
When you attach an event handler from HTML you do this:
<td onclick="logThis()">Click me</td> Here you need to pass the string with function invocation.
I had the same problem. You need to create a function in the addEventListener and than call your method.
table.rows[r].cells[2].addEventListener("click", function () {logThis(this)});
function logThis(me) {
console.log(me);
}
That should do the trick.
You can also use a global event listener on your table with event delegation
document.querySelector('#my-Table').onclick =e=>{
if ( e.target.tagName.toLowerCase() != 'td') return
if ( e.target.cellIndex !=2 ) return
console.clear()
console.log('=>', e.target.textContent , ' is clicked !')
}
table { border-collapse: collapse}
td { border: 1px solid grey; padding: .3em .5em;}
<table id="my-Table">
<tbody>
<tr><td>aa</td><td>bb</td><td>cc</td><td>dd</td></tr>
<tr><td>ee</td><td>ff</td><td>gg</td><td>hh</td></tr>
<tr><td>ii</td><td>jj</td><td>kk</td><td>ll</td></tr>
</tbody>
</table>
<p> this get click only on row 2 ( cc / gg / kk ) </p>
Despite founding of issue, why my code wasn't working, (I was invoking function) I still was not able to add eventListener to the DOM element. So, I tried to set attribute to this element using JavaScript and now it works. I'm afraid, that this is not best solution, but It is still kinda way to accomplish my aim.
let table = document.getElementById('data_table' + deal);
for (let r = 0, n = table.rows.length; r < n; r++) {
table.rows[r].cells[2].setAttribute("onclick", "logThis(this)");
}

Need help translating this JQuery code back to raw Javascript

I'm currently having trouble understanding what's going on with this code
$("#table").on("click", ".plusRow", function(event){
var name = this.getAttribute("table-data");
tableData.addData(name, 0, 1);
displayTable();
});
I understand that the first part should go something along the lines of
document.getElementById("table").addEventListener("click", function(event)
but im having trouble understanding where the ".plusRow" class should go, is it added onto the eventlistener? or how would this code be better translated back to regular Javascript.
This code snippets binds a listener on a single element (the table) and delegates it to its children which means that it will only run the event handler when it bubbles up to one or multiple elements that match the predicate (having a "plusRow" class).
With event delegation you could do:
let table = document.getElementById('table');
table.addEventListener('click', event => {
const elem = event.target;
if (elem.classList.contains('plusRow')) {
const name = elem.getAttribute("table-data");
tableData.addData(name, 0, 1);
displayTable();
}
});
Here we have to keep in mind that this code will always run when a child of the table is clicked but will only update the table when the target matches the predicate.
Without using event delegation you could do the following which will have similar results but behaves quite differently:
let tableElem = document.getElementById('table');
// To keep this simple we assume there is only one button
let button = tableElem.getElementsByClassName('plusRow')[0];
button.addEventListener('click', event => {
const name = event.currentTarget.getAttribute("table-data");
tableData.addData(name, 0, 1);
displayTable();
})
This version will only ever run when the first child of the table with a class of "plusRow" is clicked. Please note that this is just an example because if there is no element with such class an exception will be raised when we try to bind the event listener.
So I've come up with a dummy possible solution example using querySelector and querySelectorAll. Let me know if anyone sees an issue with the suggested solution.
function delegate(parentSelector, eventType, childSelector, callback) {
//lookup the parent element
var parent = document.querySelector(parentSelector);
//put the event listener for the event on the parent
parent.addEventListener(eventType, function(event) {
//get the element that caused the event
var element = event.target;
//find all the children in the parent that match the child selector,
//at this point in time
var children = parent.querySelectorAll(childSelector);
//if the element matches a child of the parent that matched the
//childSelector, we want to do our callback
for (var i = 0; i < children.length; i++) {
if (children[i] === element) {
callback();
break;
}
}
});
}
delegate('#table', 'click', '.addRow', function() {
document.querySelector('#table').innerHTML += `
<tr>
<td>Something</td>
<td><button class="addRow">Add Row</button></td>
</tr>
`;
});
<table id="table">
<tr>
<td>Something</td>
<td><button class="addRow">Add Row</button></td>
</tr>
</table>

Showing Hidden Row in Table

I am using some code based on the following JSFiddle. The intention is to show more information when the user clicks the "Show Extra" link.
The problem that I'm having is that when the link is clicked on all but the bottom row of the table the hidden element is shown briefly and then closes.
I am populating my table using template strings in javascript. Here is the code that I use to add rows to the table:
this.addRecordToTable = function(bet, index, id){
console.log(index);
console.log($.data(bet));
var butId = id.toString();
if (bet.bookies == null){
bet.bookies = "";
}
if (bet.bet == null){
bet.bet = "";
}
var newRow = `
<tr>
<td>${bet.date}</td>
<td>${bet.bookies}</td>
<td>${bet.profit}</td>
<td><button id=${butId}>Delete</button></td>
<td>Show Extra</td>
</tr>
<tr>
<td colspan=\"5\">
<div id=\"extra_${index}\" style=\"display: none;\">
<br>hidden row
<br>hidden row
<br>hidden row
</div>
</td>
</tr>
`
console.log(newRow);
console.log("#"+butId);
$(newRow).appendTo($("#betTable"));
$("#"+butId).click(
function()
{
if (window.confirm("Are you sure you want to delete this record?"))
{
var rec = new Records();
rec.removeRecordAt(index);
$("#betTable tbody").remove();
var c = new Controller();
c.init();
}
});
$("a[id^=show_]").click(function(event) {
$("#extra_" + $(this).attr('id').substr(5)).slideToggle("slow");
event.preventDefault();
});
}
EDIT:
I had to change $("a[id^=show_]").click to $("a[id=show_"+index).click..., as the event handler was being added to each element every time I added a new element. Thanks to #freedomn-m.
This code:
$("a[id^=show_]")
adds a new event handler to every existing link as well as the new one as it's not ID/context specific so all the show a's match the selector.
You need to add the context (newRow) or use the existing variable(s) as part of the loop that are already defined, eg:
$("a[id^=show_]", newRow)
$("a#show_" + index)
(or any other variation that works).
An alternative would be to use even delegation for the dynamically added elements, eg:
$(document).on("click", "a[id^=show_]", function...
in which case you'd only need to define/call the event once and it would be fired for new elements (ie put that outside the new row loop).

What happens to the event handler?

Example: A table with 1 row and 1 cell. Javascript gives this one cell and event handler which will append new rows.
<table border=1>
<tbody id="target">
<tr>
<td class="hi" >I append</td>
</tr>
</tbody>
</table>
var els = document.getElementsByClassName("hi");
for(i=0;i<els.length;i++){
els[i].onclick = function(){callMe(this)};
}
function callMe(t){
var el = document.getElementById("target");
el.innerHTML += '<tr><td class="hi" >appended...</td></tr>';
}
The callMe function gets called once, a new row is appended, the old row stays the same(I suppose).
The second time the first cell is clicked the function does not get called. Why?
What happened there?
What am I missing?
http://jsfiddle.net/2U3m3/1/
I am not using any libraries, just plain JavaScript. I want the first cell to be clickable always. It is meant to add rows forever not just one.
The second time the first cell is clicked the function does not get called. Why?
Because overwriting the innerHTML of an element re-recreates all child elements, no matter if you just “append” to the innerHTML using +=.
And that the table cell has gotten replaced by a new one means that the event handler bound to the old table cell is also gone.
The callMe function gets called once, a new row is appended, the old row stays the same(I suppose).
You “suppose” wrong here.
You need to use DOM methods for row/cell insertions if you plan to keep original event:
function callMe(t){
var el = document.getElementById("target");
var row = el.insertRow(el.rows.length);
var cell = row.insertCell(0)
cell.innerHTML = "Hi"
}
Demo: http://jsfiddle.net/ygalanter/2U3m3/2/
You can delegate the event to the class name directly. So any element with that class will have the click event including newly created ones. Adapted from the answer here.
if (document.body.addEventListener) {
document.body.addEventListener('click',clickHandler,false);
} else {
document.body.attachEvent('onclick',clickHandler); //for IE
}
function clickHandler(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target.className.match(/hi/)) //or whatever classname you want
{
callMe(target);
}
}

onclick event won't fire when there is more than one dynamically added button

So I have EDIT and REMOVE buttons that are dynamically added for each data node (a "poll") in a Firebase database. I have a function which assigns onclick listeners to these with jQuery, but oddly, the event only fires when there just happens to be a single node, and hence a single pair of EDIT/REMOVE buttons. When there are multiple nodes and multiple pairs of buttons, none will fire. Here's the javascript where the events are added to the buttons...
function displayCurrentPollsForEditing(pollsRef)
{
var tbl = createTable();
var th = ('<th>Polls</th>');
$(th).attr('colspan', '3');
$(th).appendTo($(tbl).children('thead'));
pollsRef.once('value', function(pollsSnapshot) {
pollsSnapshot.forEach(function(pollsChild) {
var type = pollsChild.name();
// If this is true if means we have a poll node
if ($.trim(type) !== "NumPolls")
{
// Create variables
var pollRef = pollsRef.child(type);
var pollName = pollsChild.val().Name;
var btnEditPoll = $('<button>EDIT</button>');
var btnRemovePoll = $('<button>REMOVE</button>');
var tr = $('<tr></tr>');
var voterColumn = $('<td></td>');
var editColumn = $('<td></td>');
var rmvColumn = $('<td></td>');
// Append text and set attributes and listeners
$(voterColumn).text(pollName);
$(voterColumn).attr('width', '300px');
$(btnEditPoll).attr({
'class': 'formee-table-button',
'font-size': '1.0em'
});
$(btnRemovePoll).attr({
'class': 'formee-table-remove-button',
'font-size': '1.0em'
});
$(btnEditPoll).appendTo($(editColumn));
$(btnRemovePoll).appendTo($(rmvColumn));
// Append to row and row to table body
$(tr).append(voterColumn).append(editColumn).append(rmvColumn);
$(tr).appendTo($(tbl).children('tbody'));
// Append table to div to be displayed
$('div#divEditPoll fieldset#selectPoll div#appendPolls').empty();
$(tbl).appendTo('div#divEditPoll fieldset#selectPoll div#appendPolls');
$(btnEditPoll).click(function() {
displayPollEditOptions(pollRef);
return false;
});
$(btnRemovePoll).click(function() {
deletePoll($(this), pollsRef);
return false;
});
}
});
});
}
The markup would be something like the following...
<div id="divEditPoll">
<form class="formee" action="">
<fieldset id="selectPoll">
<legend>SELECT A POLL</legend>
<div class="formee-msg-success">
</div>
<div class="grid-12-12" id="appendPolls">
</div>
</fieldset>
</div>
EDIT - So I've switched some lines around and now I don't set the click() events until the buttons are appended to the document, so the button elements are definitely in the DOM when the click events are attached. So could this issue result from not setting id's for these buttons? That seems strange to me, since I'm using variable references rather than ids to attach the events.
There are two things I would check for.
First, make sure you don't have two elements with the same id. If you do, jquery may only bind to the first, or not bind at all.
Second, make sure the element is added to the dom before jquery attempts to bind the click event. If the code is running asynchronously, which can easily happen if you're using ajax, then you may be trying to bind the event before creating the element. Jquery would fail to find the element then give up silently.
you should use .on() for dynamically added button

Categories