How to detect which row [ tr ] is clicked? - javascript

In javascript, how can we detect which row of the table is clicked? At present what i am doing is, i am binding the the method at run time like this.
onload = function() {
if (!document.getElementsByTagName || !document.createTextNode) return;
var rows = document.getElementById('my_table').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (i = 0; i < rows.length; i++) {
rows[i].onclick = function() {
alert(this.rowIndex + 1);
}
}
}
[ copied from [ http://webdesign.maratz.com/lab/row_index/ ] ]
But i don't like this approach. Is there any alternative? My problem is just to get the index of the row which is clicked.
No jQuery please :D.

You can use event delegation for that. Basically you add one clickhandler to your table. This handler reads out the tagname of the clicked element and moves up the DOM tree until the containing row is found. If a row is found, it acts on it and returns. Something like (not tested yet, but may give you ideas):
var table = document.getElementById('my_table');
table.onclick = function(e) {
e = e || event;
var eventEl = e.srcElement || e.target,
parent = eventEl.parentNode,
isRow = function(el) {
return el.tagName.match(/tr/i));
};
//move up the DOM until tr is reached
while (parent = parent.parentNode) {
if (isRow(parent)) {
//row found, do something with it and return, e.g.
alert(parent.rowIndex + 1);
return true;
}
}
return false;
};

The this keyword can be used to get the parentNode of the cell, which is a <tr> element. The <tr> element has a property for the row number, .rowIndex.
The Event:
onclick='fncEditCell(this)'
The Function:
window.fncEditCell = function(argThis) {
alert('Row number of Row Clicked: ' + argThis.parentNode.rowIndex);
};
Full Working Example Here:
jsFiddle
Dynamically Set OnClick Event
Use .setAttribute to inject a click event:
cell2.setAttribute("onmouseup", 'editLst(this)');
Example of Dynamically Creating a Table:
for(var prprtyName in rtrnTheData) {
var subArray = JSON.parse(rtrnTheData[prprtyName]);
window.row = tblList.insertRow(-1);
window.cell1 = row.insertCell(0);
window.cell2 = row.insertCell(1);
window.cell3 = row.insertCell(2);
window.cell4 = row.insertCell(3);
window.cell5 = row.insertCell(4);
window.cell6 = row.insertCell(5);
window.cell7 = row.insertCell(6);
window.cell8 = row.insertCell(7);
window.cell9 = row.insertCell(8);
cell1.setAttribute("onmouseup", 'dletListing(this.title)');
cell1.setAttribute("title", "'" + subArray.aa + "'");
cell2.setAttribute("onmouseup", 'editLst(this)');
cell2.setAttribute("title", "'" + subArray.aa + "'");
cell1.innerHTML = "Dlet";
cell2.innerHTML = "Edit";
cell3.innerHTML = subArray.ab;
cell4.innerHTML = "$" + subArray.ac;
cell5.innerHTML = subArray.ad;
cell6.innerHTML = subArray.ae;
cell7.innerHTML = subArray.af;
cell8.innerHTML = subArray.ag;
cell9.innerHTML = subArray.meet;
};

This uses sectionRowIndex to get the index in the containing tBody.
function getRowIndex(e){
e= window.event || e;
var sib, who= e.target || e.srcElement;
while(who && who.nodeName!= 'TR') who= who.parentNode;
if(who){
alert(who.sectionRowIndex+1)
if(e.stopPropagation) e.stopPropagation();
else e.cancelBubble= true;
// do something with who...
}
}
onload= function(){
document.getElementById('my_table').onclick= getRowIndex;
}

I tried Alan Wells written answer, but it was returning, undefined.
So, I modified a little, to get the row index as follows:
argThis.rowIndex
This will return the row index for the row clicked.
modify the <tr> tag:
<tr onclick="fncEditCell(this)" >
Then, add a script tag at the bottom of the HTML:
<script>
window.fncEditCell = function(argThis) {
alert('Row number of Row Clicked: ' + argThis.rowIndex);
};
</script>
As an example, you can see this image:

Related

How can I get the text of a JavaScript-generated input element?

I have a table that creates a row of input elements each time the "+" button is clicked underneath it. All elements are given the className "table-data". Once the "Done" button is clicked I want to loop through all these elements and get the text inside of them:
<table id="myTable"></table>
<button onclick="addRow();">+</button>
<button onclick="getData();">Done</button>
function addRow() {
var table = document.getElementById("myTable");
var row = table.insertRow(-1);
cell1 = row.insertCell(0);
cell1.innerHTML = '<input type="text"></input>';
cell1.className = 'table-data';
cell2 = row.insertCell(1);
cell2.innerHTML = '<input type="text"></input>';
cell2.className = 'table-data';
}
function getData() {
inputCells = document.getElementsByClassName("table-data");
for (var i = 0; i < inputCells.length(); i++) {
console.log(inputCells[i].innerHTML);
}
}
However, when I run this code it just logs: 'input type="text"'
I tried using this instead:
console.log(inputCells[i].value);
But this method just logs "undefined". How can I get the value of these input elements?
Note: I don't mind if jQuery is used to answer this question.
I've prepared a solution for you using jQuery as your question is tagged with it. My solution find all inputs in table and then iterates over them using jQuery#each method.
const $table = $('#myTable');
$('#addBtn').on('click', function() {
let tr = $('<tr>');
let td1 = $('<td>');
let td2 = $('<td>');
let input = $('<input>', {
type: 'text',
class: 'table-data'
});
td1.append(input.clone());
td2.append(input.clone());
tr.append(td1);
tr.append(td2);
$table.append(tr);
});
$('#doneBtn').on('click', function() {
$table.find('input').each(function() {
console.log($(this).val());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable"></table>
<button id='addBtn'>+</button>
<button id='doneBtn'>Done</button>
Details commented in demo
// Reference form
const form = document.forms[0];
/*
//A Pass a number (max 10)
//B Reference table
//C Number of cells in a row
//D if number of cells in a row is less than input number...
//E Run addCols() function
//F Number of cells in a row is equal to number of the input
//G Add row
//H On each iteration...
//I Add a cell
//J Create an input assign type and name
//K Add input to cell.
*/
function addRow(count) {//A
const table = document.querySelector("table");//B
let width = table.rows[0].cells.length;//C
if (width < count) {//D
addCols(table, width, count);//E
width = count;//F
}
const row = table.insertRow();//G
for (let r = 0; r < width; r++) {//H
const cell = row.insertCell();//I
const text = document.createElement('input');//J
text.name = 'data';
text.type = 'text';
cell.appendChild(text);//K
}
return false;
}
// Similar to addRow() but will only adds cells
function addCols(table, width, count) {
let rowCount = table.rows.length;
for (let r = 0; r < rowCount; r++) {
let row = table.rows[r];
for (let c = 0; c < (count - width); c++) {
let cell = row.insertCell();
let text = document.createElement('input');
text.type = 'text';
text.name = 'data';
cell.appendChild(text);
}
}
return false;
}
/*
//A Pass Event Object
//B Prevent the form from sending data to a browser
//C Collect all form controls and convert collection into array
//D Use flatMap() to filter in the inputs with text and extract it
*/
function getData(event) {//A
event.preventDefault();//B
const ui = [...this.elements];//C
let txt = ui.flatMap(field => field.matches('[name=data]') && field.value !== '' ? [field.value] : []);//D
console.log(txt);
return txt;
}
//Register the button to click event
form.elements.add.onclick = function(event) {
const qty = Number(event.target.previousElementSibling.value);
addRow(qty);
};
//Register the form to submit event
form.onsubmit = getData;
input {display:inline-block;font:inherit;width:10vw}
<form>
<input id='qty' type='number' min='0' max='10' value='2'>
<button id='add' type='button'>+</button>
<button type='submit'>Done</button>
<table><tr></tr></table>
</form>

Parent node undefined in button creation

I'm developing a test build for my project, which includes a lot of data manipulation. I have two buttons inline at the end of the rows, one for editing, and one for committing the changes made.
function editRow(btn) {
var row = btn.parentNode.parentNode;
row.contentEditable = "true";
row.focus();
}
function addRow(tableID, numberOfCells) {
var tbl = document.getElementById(tableID);
//create rows
var newRow = tbl.insertRow(-1);
var i;
for (i = 0; i < numberOfCells; i++) {
newRow.insertCell(0);
}
//assignbuttons
var lastcell = newRow.cells[numberOfCells - 1];
addEditButton(lastcell);
addCommitButton(lastcell);
}
function addEditButton(context) {
var button = document.createElement("input");
button.type = "button";
button.value = "Edit";
button.onclick = editRow(this);
context.appendChild(button);
}
The user will press the new row button, and then an empty row will appear along with the two buttons.
I am getting the error:
Uncaught TypeError: Cannot read property 'parentNode' of undefined
at editRow (js.js:97)
at addEditButton (js.js:123)
at addRow (js.js:115)
at HTMLButtonElement.onclick (index.html:36)
There are 2 problems I can see.
button.onclick = editRow(this); the this would result in undefined (in strict mode) in that scope. You can probably fix this by sending in the button element
button.onclick = editRow(button);
More reading on this in a function scope
Also you are not creating a row with a td element to place the button in. So btn.parentNode.parentNode is not the row element as you are expecting
Try this
function editRow(btn) {
var row = btn.parentNode.parentNode;
row.contentEditable = "true";
row.focus();
}
function addRow(tableID, numberOfCells) {
var tbl = document.getElementById(tableID);
//create rows
var newRow = tbl.insertRow(-1);
var i;
for (i = 0; i < numberOfCells; i++) {
newRow.insertCell(0);
}
//assignbuttons
var lastcell = newRow.cells[numberOfCells - 1];
addEditButton(lastcell);
//addCommitButton(lastcell);
}
function addEditButton(context) {
var row = document.createElement("row");
var td = document.createElement("td");
var button = document.createElement("input");
button.type = "button";
button.value = "Edit";
td.appendChild(button);
row.appendChild(td);
context.appendChild(row);
button.onclick = editRow(button);
}
addRow("myTable", 2)
<table id="myTable">
</table>
function addRow(tableID, numberOfCells) {
var tbl = document.getElementById(tableID);
var tableHTML = $("#" + tableID).html();
if(numberOfCells === 5) {
$("#" + tableID).html(tableHTML + "<tr id=\"bikeTableBike_new\"><td>-</td><td>-</td><td>-</td><td>-</td><td><button id=\"editBikeButton\" class=\"tableButtons\" onclick=\"editRow(this)\"><img src=\"images/edit.png\"/></button><button id=\"deleteBikeButton\" class=\"tableButtons\" onclick=\"commitRow(this)\"><img src=\"images/commit.png\"/></button></td></tr>");
}
if(numberOfCells === 4) {
$("#" + tableID).html(tableHTML + "<tr id=\"bikeTableBike_new\"><td>-</td><td>-</td><td>-</td><td><button id=\"editBikeButton\" class=\"tableButtons\" onclick=\"editRow(this)\"><img src=\"images/edit.png\"/></button><button id=\"deleteBikeButton\" class=\"tableButtons\" onclick=\"commitRow(this)\"><img src=\"images/commit.png\"/></button></td></tr>");
}
if(numberOfCells === 3) {
$("#" + tableID).html(tableHTML + "<tr id=\"bikeTableBike_new\"><td>-</td><td>-</td><td><button id=\"editBikeButton\" class=\"tableButtons\" onclick=\"editRow(this)\"><img src=\"images/edit.png\"/></button><button id=\"deleteBikeButton\" class=\"tableButtons\" onclick=\"commitRow(this)\"><img src=\"images/commit.png\"/></button></td></tr>");
}
}

Adding a new row to html table on click event

I have a list with names, each name has a sublist with subitems.
I need to pass those subitems to the table when I click on the name.
Here is an example, try to expand the first name.
But if I click on it again, it will keep adding that value to different cells of the table. How may I add this only once ? Or always at the same place?
Also, I have some attributes of the disciplines:
data-time = The time the discipline start;
data-id = The ID of that discipline (all brought from database);
My Code:
/*JQuery*/
$(document).ready(function(){
$(".prof-list h3").click(function(event){
var obj = event.target;
var disciplina_id = $(this).next().find('li').data('id');
var disciplina_hora = $(this).next().find('li').data('time');
if(disciplina_hora == "14:30:00"){
var myRow = document.getElementById("prof-table").rows[3];
myRow.insertCell(1).innerHTML = $(this).next().find('li').text();
}
else if(disciplina_hora == "08:30:00"){
var myRow = document.getElementById("prof-table").rows[1];
myRow.insertCell(1).innerHTML = $(this).next().find('li').text();
}
if(obj.nodeName == "H3")
$(this).next().slideToggle();//Aplica efeito slide
//$("#list_prof").html("clicked: " + event.target.nodeName ); //Teste
})
})
use .cells[] to update cell content
if(disciplina_hora == "14:30:00"){
var myRow = document.getElementById("prof-table").rows[3];
// insert if `myRow` only has 1 cell
if(myRow.cells.length <= 1)
myRow.insertCell(1);
// use `cells[1]` to update the 2nd cell content
myRow.cells[1].innerHTML = $(this).next().find('li').text();
}
Edit Update
if(myRow.cells.length <= 1){
$(this).next().find('li').each(function(idx, elm) {
myRow.insertCell(idx + 1);
myRow.cells[idx + 1].innerHTML = $(elm).text();
});
} else {
while(myRow.cells.length > 1)
myRow.deleteCell(1);
}

jQuery loop through table to display values

I'm at a loss here.
I created a quick script that will add a new row to a table and also has the capability to delete a row.
jsFiddle -->http://jsfiddle.net/wLpJr/10/
What I want to achieve is this:
Display each value of each row (in the div with id='thedata')
I originally started off with adding a number at the end of each id, starting at '1', and incrementing each time the user adds a row.
//This is random code
var rowcount = parseInt($('#rowcount').val());
var newcount = rowcount + (1*1);
var x = $('#radioinput' + newcount).val('a value');
$('#rowcount').val(newcount);
The problem is that lets say you add 5 rows. Now delete row 3. When you loop through the table of data you will get an error because row "3" does not exist. You have rows 1, 2, 4, 5, 6. Specifically - the input with id = 'radioinput3' will not be present.
I then decided to do this:
$('#maintable > tbody > tr').each(function() {
radiovalue[i] = $("input[type='hidden']", this).map(function() {
var vid = 'radio' + i;
var myval = this.value;
var radioinput = document.createElement("input");
radioinput.type = "hidden";
radioinput.value = myval; // set the CSS class
radioinput.id = vid;
$('#maintable').append(radioinput);
}).get()
text1value[i] = $('td > input', this).map(function() {
var vid = 'text1pos' + i;
var myval = this.value;
var text1input = document.createElement('input');
text1input.type='hidden';
text1input.value = myval;
text1input.id = vid;
$('#maintable').append(text1input);
}).get()
text2value[i] = $('td > input', this).map(function() {
var vid = 'text2pos' + i;
var myval = this.value;
var text2input = document.createElement('input');
text2input.type='hidden';
text2input.value = myval;
text2input.id = vid;
$('#maintable').append(text2input);
}).get();
});
The problem here is that I'm getting 'undefined' values.
You are looping through a counter, which you increment everytime you add a new row, but do not take into account that a row can be deleted at any time. Instead, just use the each function to loop over the elements remaining in the DOM.
Add thead and tbody tags to your table, it will make your life easier.
I'm not sure why you have those hidden div to hold the input[type=radio] values, you don;t need them, access the values directly.
$('#showdata').click(function() {
$("#maintable tbody tr").each(function(i, v) {
var myp = "<p>Radio value is = " + $(this).find('input[type=radio]:checked').val()
+ "\nText1 value is = " + $(this).find('input[id$=text1]').val()
+ "\nText2 value is = " + $(this).find('input[id$=text2]').val() + "</p>";
$('#thedata').append(myp);
});
});
jsFiddle Demo
You could add a CSS class to the input text fields to make it easier to get, but i just used the jQuery ends with selector.
Also, you delete selector if far too high up the DOM tree on (document), instead restrict it as near as you can, in this case the #maintable.

How to add an UpperCase function to each textbox in a dynamic table?

I am trying to create a dynamic table with textboxes but I want the textboxes to be converted to upper case every time I write.
Any ideas on how to do this??
Currently this is how I am doing the dynamic table:
var n = 1;
function addRow(tableID,nroColumna) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
for(i=0;i<nroColumna;i++){
var cell = row.insertCell(i);
var element = document.createElement("input");
element.type = "text";
element.name = n+"0"+i;
element.size = "12";
element.id = n+"0"+i;
//element.onkeyup = function(){alert()};
cell.appendChild(element);
}
n++;
}
I was trying to do a document.getElementById(element.id).value.toUpperCase() but I am getting an error with a null value for the element.id
Any help is greatly appreciated!
If you're ok with a non JavaScript solution, you could apply this CSS to your inputs:
text-transform: uppercase;
That would make the text uppercase from the beginning...
Darkajax's solution, works, you can target it to inputs within a table with a specific ID
with
#tableid input
{
text-transform: uppercase;
}
I tested your code with the onkeyup function activated:
var n = 1;
function addRow(tableID,nroColumna) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
for(i=0;i<nroColumna;i++){
var cell = row.insertCell(i);
var element = document.createElement("input");
element.type = "text";
element.name = n+"0"+i;
element.size = "12";
element.id = n+"0"+i;
element.onkeyup = function(){alert(element.id);};
cell.appendChild(element);
}
n++;
}
And that worked. However, it uses the last element.id computed for every call to the function... so, when I created one row of 3 cells, every time I typed into a cell, it would alert "102" regardless of which cell I typed in.
This is because the onkeyup function is dynamic. It is called on the keyup action - not set when the object is created. So it uses the element.id value that exists at the time of the action, not what it was when you passed it in the first time. I hope that makes sense.
I had this issue myself on a recent project. One solution is to create a separate function for the inner workings of the for loop as such:
var n = 1;
function createRow (n, i) {
var element = document.createElement("input");
element.type = "text";
element.name = n+"0"+i;
element.size = "12";
element.id = n+"0"+i;
element.onkeyup = function(){alert(element.id);};
return element;
}
function addRow(tableID,nroColumna) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
for(i=0;i<nroColumna;i++){
var cell = row.insertCell(i);
element = createRow(n, i);
cell.appendChild(element);
}
n++;
}
This code alerts the correct element.id value.
EDIT: you can change the onkeyup() line to read:
element.onkeyup = function(){document.getElementById(element.id).value = document.getElementById(element.id).value.toUpperCase();};
And it should work as you want it to.
with jQuery it will be like
$('.yourClass').val($(this).val().toUpperCase());
or
$('#yourId').css({'text-transform' : 'uppercase'})

Categories