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).
Related
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>
I'm Looping through rows, generating links with each their identical value, in this case.
Shown here:
#foreach (var article in Model.Articles)
{
<tr class="etc">
#if (Model.Order.Status == Model.Orders.Status.Blocked)
{
<td id="buttonDeleteOrderLine" description="#article.Description" name="#Model.Order.FullName" value="#article.LineId" >Delete Line</td>
}
Value="value" is unique in this case!
My JS:
$('#buttonDeleteOrderLine').on('click', function () {
var DOL = $(this);
var orderDescription = DOL.attr("description");
var customerName = DOL.attr("name");
var lineID = DOL.attr("value");
I'm getting links for each row, and they're also clickable. However, only the first one actually works (shows a modal, not included in JS Code)
So I need a way, to search the class 'buttonDeleteOrderLine' (because the ID changes), and yet get the info from the clicked link.
You can only have one element per ID, where you can have any number of elements per Class.
It was quite simple actually,
Set
id="buttonDeleteOrderLine" to class="buttonDeleteOrderLine"
and I've changed:
$('#buttonDeleteOrderLine').on('click', function () {
to:
$('.buttonDeleteOrderLine').on('click', function () {
It now works and gets the correct information of each link, including the sub-information.
I have 3 tables in my boostrap tab. Each tab as a table. The rows of this table is dynamically generated with csharp asp.net code. Right I Want a scenario were if a user click on the row of the first table, the clicked role of the first table get remove from the first table and is added to the rows of the second table.
My challenge as been getting to remove the row after the onClick process.
<tbody>
<tr id="kayode#yahoo.com">
<td> kayode <a class="chat" connectionid="135976e6-799b-4cda-a764-a00f7110d515"
data-parentid="kayode#yahoo.com"
href="/Visitor/StartChat?threadid=3&email=kayode%40yahoo.com"
operatorid="1" target="_blank" threadid="3">chat</a></td>
<td>271.0.0.1</td>
<td>Active</td>
<td></td>
<td>9/13/2014</td>
<td>04:15:18</td>
<td>02:52:55</td>
<td>271.0.0.1</td>
</tr>
</tbody>
My javascript code which I am trying to use to remove the row after the Click event.
function updateWaitingState(sender) {
var parentid = $(sender).attr("data-parentid");
//alert(parentid);
//we are going to remove the role from this field
var element = document.getElementById(parentid);
element.parentNode.removeChild(element); //This line is a problem says
//document.querySelector("tablebody4 first").appendChild(element);
console.log(element);
}
This is untested, but I imagine jQuery will greatly reduce your headache here:
function updateWaitingState(sender) {
var parentId = $(sender).attr("data-parentid");
$('#' + parentId).appendTo('.tablebody4:first');
}
You may need to adjust the selector in the appendTo function, as it was a guess on my part.
function updateWaitingState(sender) {
var parentid = $(sender).attr("data-parentid");
var element = document.getElementById(parentid);
$(element).appendTo('.tablebody2:first');
}
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);
}
}
I want to know the best way to accomplish the following.
I have a table:
<table>
<tr><td>1</td><td>Some1</td></tr>
<tr><td>2</td><td>Some2</td></tr>
<tr><td>3</td><td>Some3</td></tr>
</table>
When I click on a TD (1,2,or 3), then a div is visible with id "#removediv" that has some basic text like "Remove". I click on the div, and the row that I had originally clicked on to get the div to show, is removed.
I imagine I would have to pass some information about the row or index to the "#removediv" object so that #removediv event handler would know which row to remove. Not sure how to best go about doing this.
var remove = null;
var caller = null;
$(function() {
remove = $('#removediv');
$('td').click(function() {
caller = $(this).parent('tr');
remove.show();
});
remove.click(function() {
caller.remove();
$(this).hide();
});
});