Get ID of <td> to change inner HTML multiple times - javascript

So I problem is that I want to generate a random ID for each in each row and then change the inner HTML of the specified whenever a certain button is clicked.
I have tried adding the onload attribute for each row that is created to try to get the id with a function and then pass the id when the function is called but it didn't work
function add(){
let taskInfo = `
<tr>
<td>${generateId(4)}</td>
<td>${productID}</td>
<td>-</td>
<td class="taskid"id="${generateId(4)}">Idle</td>
<td>
<span class="action-start" id="${generateId(4)}"onclick="start(getId())">Start</span>
<span class="action-stop" >Stop</span>
</td>
</tr>
`
let newTask = tbody.insertRow(tbody.rows.length);
newTask.innerHTML = taskInfo;
console.log("New task added!")
}
This is the function that adds the rows to the table ^
So what I am expecting to get is that when the users click start the status changes to a certain status, individually in each row

Related

Get cell Value of Table html

I have this code (opt1) to get the text of the cell, which is clicked, but this alerts all of the objects in the table as its in a loop. But when I place it outside the loop I just get a random text from the table and not the one which is clicked (opt2).
I need the textContent of the cell, which is clicked, once, and not any other.
FYI: the cell contains multiple <td> inside <tr>.
The current method gets me the name text either of all cells (opt1) or the last cell (opt2)
HTML:
<table id="table">
<tr class="cell" onclick="RowHandlers()">
<td class="name">Name</td>
<td class="date">Date</td>
<td class="subject">Subject</td>
</tr>
</table>
opt1
function RowHandlers() {
var table = document.getElementById("table");
var name;
for (var i=1;i<table.rows.length;i++) {
name = table.rows[i].cells[0].innerText;
alert(name);
}
}
opt2
function RowHandlers() {
var table = document.getElementById("table");
var name;
for (var i=1;i<table.rows.length;i++) {
name = table.rows[i].cells[0].innerText;
}
alert(name);
}
Your problem seems to be identifying the clicked row after a click has happened.
We can solve this in multiple ways:
In JS, use the event object's target property:
(Preferred) Add handler via addEventListener().
Use a single handler by making use of event propagation.
Add handlers to each row.
(Discouraged) Add handler via onevent property. Only one handler can be added this way.
(Deprecated) Use the global object window.event.
(Discouraged) In HTML, use inline event onclick on each row:
Pass this to the handler function (e.g. <tr onclick="RowHandler(this)">). this in inline events will refer to the clicked element.
Add IDs to each row (e.g. <tr id="row1">). For each row, pass its ID to the function (e.g. onclick="RowHandler('row1')"). Search for the element by the passed ID.
Using addEventListener()
To add a listener, pass the event type and the listener:
const input = document.querySelector("input");
const button = document.querySelector("button");
button.addEventListener("click", clickHandler);
function clickHandler(event) {
console.log(input.value);
input.value = "";
}
<input><button>Click me!</button>
Event propagation
Because events bubble up the DOM, <table>'s listener will also fire when its rows are clicked. We can use event.target to get the event's origin element and find the clicked row:
const table = document.querySelector("table");
table.addEventListener("click", tableClickHandler);
function tableClickHandler(event) {
const row = event.target.closest("tr.cell"); // event.target may be a <td>
const isInRow = Boolean(row);
const isFirstRow = row === table.rows[0];
if (!isInRow || isFirstRow) return;
const name = row.cells[0].textContent;
const date = row.cells[1].textContent;
const subject = row.cells[2].textContent;
console.log("Clicked:", { name, date, subject });
}
table,td{border:1px solid}
<table>
<tr>
<th>Name</th>
<th>Date</th>
<th>Subject</th>
</tr>
<tr class="cell">
<td class="name">Some name</td>
<td class="date">01-01-1999</td>
<td class="subject">Some subject</td>
</tr>
<tr class="cell">
<td class="name">Another name</td>
<td class="date">02-02-2020</td>
<td class="subject">Another subject</td>
</tr>
</table>
Regarding your solutions
You are missing some way of identifying the clicked element; see my suggestions above.
In opt2, you are looping through all rows, but constantly overriding the variable name before using it. Therefore it is the same as only reading the name of the last row.
You may want to use .textContent over .innerText, because it doesn't cause a reflow. If visibility of the content matters, choose .innerText, otherwise .textContent.
A table usually consists of sections (e.g. <thead>, <tbody>, <tfoot>, or an implicit section). Each section consists of rows; each row consists of cells. Therefore, your class name "cell" for a row may be confused with actual table cells (<td>/<th>).
Please check this.
const [row] = document.getElementsByClassName('cell');
row.addEventListener('click', function(event) {
console.log(event.target.innerText);
})
<table id="table">
<tr class="cell">
<td class="name">Name</td>
<td class="date">Date</td>
<td class="subject">Subject</td>
</tr>
</table>

Jquery - On input, Get the value of a span inside a td using span class

I am trying to get the value of a spam changed by the user (using contenteditable),
through its class.
The spam is inside a <td> in a table.
I tried let newItemName = $(variantId).children(".item-description").text();
and also let newItemName = $(variantId).find('span.item-description').text();
which both return an empty string to newItemName variable.
Any ideas why I'm getting an empty string instead of the users input?
This is my JS:
let variantId;
$(document).on('click', ".tbl-itemClass", function () {
variantId = $(this).attr('id');
$(variantId).prop('contenteditable', true);
}).
on('input', function () {
//let newItemName = $(variantId).children(".item-description").text();
let newItemName = $(variantId).find('span.item-description').text();
});
This is my .csHtml (don't think it makes a difference, I'm using razor page, Asp.Net)
<tbody>
#foreach (var item in Model)
{
<tr currentitemid=" #item.Id">
<td class="tbl-itemClass desc" id="#("description"+ item.Id)" varianttype="#ViewBag.VariantType" >
<span class="spnSpc"> </span>
<span style="width:90%; padding:1px 5px 1px 2px;" **class="item-description"** contenteditable> #item.Description </span>
</td>
<td class="tbl-itemClass ">//more code here
</td>
</tr>
}
#item.Descriptions value is a color (i.e: 'red').
When the user changes that value (i.e: 'redX'), this code runs, but returns an empty string instead of 'redX'.
Thanks!
You select the element again with the variantId variable. But that is only a string and won't select the element, because the string doesn't contain the # when selecting elements with an id.
variantId = '#'+$(this).attr('id');
Now variantId will be #+your_id

Delete table row button removes all subsequent rows

I have a table I've built in an app that when I click delete removes all rows following the row that was deleted on submit. That means that the table looks good to the user with just that one row removed, but when it hits the viewmodel on post action, those subsequent rows aren't included.
I've added some pretty complex code that goes all over the place to edit the index values of the rows but that ended up confusing the problem even more with some values replacing others and some other values just being set to 0. I know there has to be a more simple way.
I set this example back to the more simplified version where the delete appears to work well but then doesn't include any subsequent values in the viewModel when it hits the controller.
Here is the HTML Table
<input type="button" value="Add" class="button is-primary" id="btnAdd" />
<table id="tblPart" style="table-layout:fixed; width:100%;">
<thead>
<tr>
<th>
Part Number
</th>
<th>
Quantity
</th>
<th></th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.NumberModel.Count(); i++)
{
<tr >
<td >
#Html.TextBoxFor(modelItem => Model.NumberModel[i].PartNum, new { id = $"part{i}", required = "required", #class = "partTest" })
</td>
<td>
#Html.TextBoxFor(modelItem => Model.NumberModel[i].Quantity, new { type = "number", min = "0", id = $"quantity{i}", required = "required" })
</td>
<td>
<input type='button'
onclick='Remove(this)'
value='Remove' />
</td>
</tr>
}
</tbody>
</table>
Here is the JS
<script>
function Remove(button) {
//Determine the reference of the Row using the Button.
var row = $(button).closest("TR");
var name = $("TD", row).eq(0).html();
//console.log(row + name);
var index = 0;
var table = $("#tblPart")[0];
//Delete the Table row using it's Index.
table.deleteRow(row[0].rowIndex);
}
</script>
Thank you for your assistance.
When you delete the row, all subsequent rows index is wrong, you need to re-index the remaining rows on delete. If you for instance delete row with index 3 and then you have rows 0-2 and rows 4-6, 4-6 will be left out since there is no index 3, to fix this, you need to reindex the id and name attributes on the form fields after delete, also, you should consider using const and let in your function as var should be used for global variables, lastly, I added jquery tag to your post as you are mixing javascript and jquery in your code:
function Remove(button) {
//Determine the reference of the Row using the Button.
const row = $(button).closest("TR");
const name = $("TD", row).eq(0).html(); //this seems unnecessary
let index = 0; //this seems unnecessary
const table = $("#tblPart")[0];
//Delete the Table row using it's Index.
table.deleteRow(row[0].rowIndex);
//re-index
$('#tblPart tbody tr').each(function(i, el) {
//get the form fields
const $partnuminput = $(el).find('input[name*="PartNum"]');
const $quantityinput = $(el).find('input[name*="Quantity"]');
//use the iterator parameter of .each to set the index correctly
$partnuminput.attr("name", $partnuminput.attr("name).replace(/\d+/g, i);
$partnuminput.attr("id", $partnuminput.attr("id").replace(/\d+/g, i);
$quantityinput.attr("name", $partnuminput.attr("name).replace(/\d+/g, i);
$quantityinput.attr("id", $partnuminput.attr("id").replace(/\d+/g, i);
});
}

JS onclick event in table Collapsibles/Accordion

I am trying to find out how to create onClick event in a table, that works according to the row clicked, displaying hidden siblings.
This table comes from a DB (ajax call)
$("#table-data").append(
`<tr id="${response.data[i]["id"]}">
<td id="nameTag${response.data[i]["id"]}"> ${response.data[i]["firstName"] + " " + response.data[i]["lastName"]}</td>
<td> ${response.data[i]["id"]} </td>
<td> ${response.data[i]["jobTitle"]} </td>
<td> ${response.data[i]["email"]} </td>
<td> ${response.data[i]["department"]} </td>
<td> ${response.data[i]["location"]} </td>
</tr>`
Here is where I want to get the row on click, but the id should be nameTag[i], where i is the row id.
const nameTag = $("#nameTag1"); //example: if click on row 1 should be this ID.
const nameTag = $(`#nameTag${response.data[i]["id"]}`); //I tried this way using it inside the ajax call. but it makes open and close row 12 to the infinite...
$(document).on("click", nameTag, function () {
$('#nameTag1').siblings().toggle("slow");
});
I tried this for loop but also doesn't work
const table = document.getElementById('table');
for (var i = 0, row; row = table.rows[i]; i++) {
//do something....
}
If I use fixed ID values for test, like onClick just for nameTag1, opening his siblings, when i click in any row open row 1...
I don't know, but probably I am going to the wrong way, maybe I should use just CSS...

Jquery get id of an element on click of a common class

I am programmatically populating options to increase and decrease the value of an element and store the same in the DB table. To get a better idea, consider the following example:
<tr>
<td id="name_1">Element 1</td>
<td>increase icon</td>
<td>decrease icon</td>
</tr>
<tr>
<td id="name_2">Element 2</td>
<td>increase icon</td>
<td>decrease icon</td>
</tr>
<tr>
<td id="name_n">Element n</td>
<td>increase icon</td>
<td>decrease icon</td>
</tr>
Whenever I click any among the n increase / decrease icon, I need to access the value of #name_n. For which, I wrote the following function:
$(".increase").click(function(){
var id = $(this).attr('id'); //get the id of the element that was clicked.
console.log(id);
var arr = id.split("_"); //split to get the number
var no = arr[1]; //get the number
var name = $("#name_"+no).text(); //get the required value in name_n
console.log(name);
});
//replica for decrease class as well.
Problem :
Every time I click any increase icon, in my console, I'm getting id as inc_1 only! So, the value of name is Element 1 always. Same happens with click function for .decrease.
I have tried with the following ways to get the id:
var id = this.id;
var id = $(this).get(0).id;
var id = $(this)[0].id;
But nothing changed. The same problem persists. What's wrong and how do I resolve this?
Your code looks correct at first glance. Maybe there is some issue with rendering, perhaps the elements really get the same ID.
However, I would recommend a different approach for this task, without using ID's. You can achieve your goal by referencing the TD element relatively to the clicked increase/decrease button. I mean something like this.
$(".increase").click(function(){
var $td = $(this).closest("tr").children(":eq(0)"); //get the TR's first TD
var name = $td.text(); //get the required value in name_n td
console.log(name);
});
You could add a more generic class on the elements you wish tou target after the click(currently #name_n) and use the .closest and .siblings methods.
html
<tr>
<td id="name_n" class="target">Element n</td>
<td>increase icon</td>
<td>decrease icon</td>
</tr>
js
$(".increase").click(function(){
var name = $(this).closest('td').siblings('.target').text();
console.log(name);
});
Here is a working demo https://jsfiddle.net/0hru2jtx/

Categories