<table id="tableID">
<tr>
<th>Attr</th>
<th>Val</th>
</tr>
<td>
<input type="checkbox" name="firstChk" />
</td>
<td>
<input type="text" name="firstAttr" />
</td>
<td>
<input type="text" name="firstVal" />
</td>
</table>
<input type="button" value="Add A Row" onclick="javascript: addARow('tableID')" />
<input type="button" value="Delete" onclick="javascript: deleteARow('tableID')" />
This separate js file gets called:
function deleteARow(tID) {
try {
var tableObj = document.getElementById(tID);
var numRows = tableObj.rows.length;
// starts at 1 because never delete row that holds table headers
for(var index=1; index < numRows; index++) {
var rowObj = tableObj.rows[index];
// rowObj.cells[0] gives the td, then childNodes[0] gives checkbox element
var chkboxObj = rowObj.cells[0].childNodes[0];
if(null != chkboxObj && true == chkboxObj.checked) {
tableObj.deleteRow(index);
/* next 2 lines are necessary because DOM's tr indices shift back
* with a deletion
*/
numRows--;
index--;
}
} // end for
} // end try
catch(e) {
alert(e);
}
} // end function
This code can delete any row and any number of rows after clicking the "Delete" button EXCEPT for the first row that has a checkbox(the one whose xpath is //table/tr[1]). I've traced through the code by hand multple times and have been unable to debug it, so I've posted the code with my comments.
What's wrong with the code? I wish I could figure out how to use the js debugger in firebug :(
There were a few issues with your code.
First, the markup for your table was malformed. You have td's without parent tr's.
Second, the logic that you used to get the checkbox object was not returning the checkbox. So, when you hit your if statement, chkboxObj.checked returned undefined.
Here's the updated/working code:
HTML
<table id="tableID">
<tr>
<th>Attr</th>
<th>Val</th>
</tr>
<tr>
<td>
<input type="checkbox" name="firstChk" />
</td>
<td>
<input type="text" name="firstAttr" />
</td>
<td>
<input type="text" name="firstVal" />
</td>
</tr>
</table>
<input type="button" value="Add A Row" onclick="addARow('tableID')" />
<input type="button" value="Delete" onclick="deleteARow('tableID')" />
JavaScript
function deleteARow(tID) {
try {
var tableObj = document.getElementById(tID);
var numRows = tableObj.rows.length;
// starts at 1 because never delete row that holds table headers
for (var index = 1; index < numRows; index++) {
var rowObj = tableObj.rows[index];
// rowObj.cells[0] gives the td, then childNodes[0] gives checkbox element
// This was not returning the checkbox element. See updated code:
// Get first input in row - this will be the checkbox
var chkboxObj = rowObj.cells[0].getElementsByTagName("input")[0];
if (chkboxObj != null && chkboxObj.checked == true) {
tableObj.deleteRow(index);
/* next 2 lines are necessary because DOM's tr indices shift back
* with a deletion
*/
numRows--;
index--;
}
} // end for
} // end try
catch (e) {
alert(e);
}
} // end function
Also, here's a working fiddle.
Related
I made a listener to attatch an id "selectedRow" to the row a user has clicked on. The intent from there is be able to manipulate the data in that row; Previously i was using content editable however I'm trying to make it more obvious to the user that they are editing a row (this is for a project) so i've created an editing panel to do so. I've however ran in to some problems with a lot of data being returned as undefined when using .innerHTML when sending the TD to the input boxes.
I've tried using .HTML instead
$('tr').click(function() {
if(document.getElementById("SELECTEDROW")) {
var oldRow = document.getElementById("SELECTEDROW");
oldRow.classList.remove("selected");
$("#SELECTEDROW").removeAttr('id');
}
$(this).attr('id', 'SELECTEDROW');
selectedRow = document.getElementById("SELECTEDROW");
table = selectedRow.parentNode;
console.log("Row " + selectedRow.childNodes[1].innerHTML + " Selected");
selectedRow.classList.add("selected");
editRow();
});
function editRow() {
var currentTD = selectedRow.childNodes;
var inputs = document.getElementById("inputs").childNodes;
var i = 0;
for (i = 0; i < currentTD.length; i++) {
inputs[i].innerHTML = currentTD.html;
}
console.log('Now Editing:' + currentTD[1].innerHTML);
document.getElementById("editingPanel").style.display = "block";
document.getElementById("content").style.height = "49%";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Role</th>
<th>Address</th>
<th>Phone</th>
<th>Email</th>
<th>Password</th>
</tr>
<tr>
<td>1</td>
<td>Bill Robbins</td>
<td>Conductor</td>
<td>12, Caldrow Ave, Plymouth, Pl21XE</td>
<td>01921202384</td>
<td>XxbillyboyxX#bossman.com</td>
<td>CaTsRbAe1967</td>
</tr>
<tr>
<td>2</td>
<td>Kat Robbins</td>
<td>Admin</td>
<td>12, Caldrow Ave, Plymouth, Pl21XE</td>
<td>019232042454</td>
<td>katrobs#gmail.com</td>
<td>thR33mel0ns</td>
</tr>
</table>
</div>
<div id="editingPanel">
<div id="inputFields">
<form id="inputs">
<input id="input1" type="text" name=""/>
<input id="input2" type="text" name="">
<input id="input3" type="text" name="">
<input id="input4" type="text" name="">
<input id="input5" type="text" name="">
<input id="input6" type="text" name="">
<input id="input7" type="text" name="">
<input id="input8" type="text" name="">
</form>
</div>
<div id="editButtons">
<button onclick="addRow()">New Row</button>
<button onclick="editRow()">Save Row</button>
<button onclick="removeRow()">Delete Row</button>
</div>
</div>
The expected output would be for each td's text to be copied into the input boxes.
You need to get the children properly. You also need to assign the text to the value property of the input, not its innerHTML
function editRow() {
// You need to get elements by tag name, not childNodes
var currentTD = selectedRow.getElementsByTagName("td");
// You need to get elements by tag name, not childNodes
var inputs = document.getElementById("inputs").getElementsByTagName("input");
var i = 0;
for (i = 0; i < currentTD.length; i++) {
console.log(inputs[i]);
console.log(currentTD[i]);
// set the "Value" of an input box, not its "innerHTML"
// also you need to apply the [i] to the currentTD because it is a list
inputs[i].value = currentTD[i].innerHTML;
}
You can try this:
$("body").on("click","tr",function(){ //Just in case you are going to use dynamic content, because the click method doesn't work on dynamically created/added elements
for(let i=0;i<7;i++){
$("#input"+(i+1)).val($(this).children()[i].innerHTML); //You are using jQuery for a reason, to simplify code, so avoid using unnecessary JS where you can by using simplified jQuery
}
});
I have a button that the user clicks on to add a new row to the bottom of an input table. I would like this to also increment the id. So the next row would have desc2, hours2, rate2 and amount2 as the id. Is there a way to do this in the JavaScript function.
Also - just want to check my logic on this. After the user completes the filled out form, I will be writing all the data to a mysql database on two different tables. Is this the best way to go about this? I want the user to be able to add as many lines in the desc_table as they need. If this is the correct way to be going about this, what is the best way to determine how many lines they have added so I can insert into the db table using a while loop?
JS file:
function new_line() {
var t = document.getElementById("desc_table");
var rows = t.getElementsByTagName("tr");
var r = rows[rows.length - 1];
var x = rows[1].cloneNode(true);
x.style.display = "";
r.parentNode.insertBefore(x, r);
}
HTML:
<table id="desc_table">
<tr>
<td><font><br><h3>Description</h3></font></td>
<td><font><h3>Hours</h3></font></td>
<td><font><h3>Rate</h3></font></td>
<td><font><h3>Amount</h3></font></td>
<td></td>
</tr>
<tr>
<td ><textarea name="description" id="desc1" ></textarea></td>
<td> <input type="text" name="hours" id="hours1" ></td>
<td> <input type="text" name="rate" id="rate1"></td>
<td><input type="text" name="amount" id="amount1"></td>
<td>
<button type="button" name="add_btn" onclick="new_line(this)">+</button>
<button type="button" name="delete_btn" onclick="delete_row(this)">x</button>
</td>
</tr>
</table>
Thank you!
Check this code.After appending the row it counts the number of rows and and then assigns via if condition and incremental procedure the id's:
function new_line() {
var t = document.getElementById("desc_table");
var rows = t.getElementsByTagName("tr");
var r = rows[rows.length - 1];
var x = rows[1].cloneNode(true);
x.style.display = "";
r.parentNode.insertBefore(x, r);
for(var i=1;i<rows.length;i++){
if(rows[i].children["0"].children["0"].id.match((/desc/g))){
rows[i].children["0"].children["0"].id='desc'+i;
}
if(rows[i].children["1"].children["0"].id.match((/hours/g))){
rows[i].children["1"].children["0"].id='hours'+i;
}
if(rows[i].children["2"].children["0"].id.match((/rate/g))){
rows[i].children["2"].children["0"].id='rate'+i;
}
if(rows[i].children["3"].children["0"].id.match((/amount/g))){
rows[i].children["3"].children["0"].id='amount'+i;
}
}
}
<table id="desc_table">
<tr>
<td><font><br><h3>Description</h3></font></td>
<td><font><h3>Hours</h3></font></td>
<td><font><h3>Rate</h3></font></td>
<td><font><h3>Amount</h3></font></td>
<td></td>
</tr>
<tr>
<td ><textarea name="description" id="desc1" ></textarea></td>
<td> <input type="text" name="hours" id="hours1" ></td>
<td> <input type="text" name="rate" id="rate1"></td>
<td><input type="text" name="amount" id="amount1"></td>
<td>
<button type="button" name="add_btn" onclick="new_line(this)">+</button>
<button type="button" name="delete_btn" onclick="delete_row(this)">x</button>
</td>
</tr>
</table>
Please change variable names for more descriptive. :)
Example solution...
https://jsfiddle.net/Platonow/07ckv5u7/1/
function new_line() {
var table = document.getElementById("desc_table");
var rows = table.getElementsByTagName("tr");
var row = rows[rows.length - 1];
var newRow = rows[rows.length - 1].cloneNode(true);
var inputs = newRow.getElementsByTagName("input");
for(let i=0; i<inputs.length; i++) {
inputs[i].id = inputs[i].name + rows.length;
}
var textarea = newRow.getElementsByTagName("textarea")[0];
textarea.id = textarea.name + rows.length;
table.appendChild(newRow);
}
Note that I removed/edited below fragment.
x.style.display = "";
r.parentNode.insertBefore(x, r);
You could do this a lot easier with jquery or another dom manipulation language, but with vanilla JS here's an example of simply looping through the new row's inputs & textarea and incrementing a counter to append.
var count = 1;
function new_line() {
count++;
var t = document.getElementById("desc_table");
var rows = t.getElementsByTagName("tr");
var r = rows[rows.length - 1];
var x = rows[1].cloneNode(true);
x.style.display = "";
r.parentNode.insertBefore(x, r);
// update input ids
var newInputs = Array.from(x.getElementsByTagName('input'))
.concat(Array.from(x.getElementsByTagName('textarea')));
newInputs.forEach(function(input) {
var id = input.getAttribute('id').replace(/[0-9].*/, '');
input.setAttribute('id', id + count);
});
}
<table id="desc_table">
<tr>
<td><font><br><h3>Description</h3></font></td>
<td><font><h3>Hours</h3></font></td>
<td><font><h3>Rate</h3></font></td>
<td><font><h3>Amount</h3></font></td>
<td></td>
</tr>
<tr>
<td ><textarea name="description" id="desc1" ></textarea></td>
<td> <input type="text" name="hours" id="hours1" ></td>
<td> <input type="text" name="rate" id="rate1"></td>
<td><input type="text" name="amount" id="amount1"></td>
<td>
<button type="button" name="add_btn" onclick="new_line(this)">+</button>
<button type="button" name="delete_btn" onclick="delete_row(this)">x</button>
</td>
</tr>
</table>
I have the table with following structure . I am generating a dynamic table on the basis of input provided by user which will repeat this row .
I want to get the value of this text box and trying to use the code below
if (row.getAttribute('val') === 'answer') {
var Cell = table.rows[i].cells[0];
alert(Cell.innerHTML);
}
<tr val='answer'>
<td>
<input type='checkbox' />
<input style='width:483px' type='text' />
</td>
</tr>
I am putting alert to check if i am getting the correct value .I can see the two inputs in the alert message I want to get the value of text box using javascript not jquery
You can use querySelectorAll to select all rows and then use loop to get only rows with val='answer' and then use querySelector to get input with type="text"
var rows = document.querySelectorAll('tr');
for (var i = 0; i < rows.length; i++) {
if (rows[i].getAttribute('val') == 'answer') {
var input = rows[i].querySelector('input[type="text"]');
console.log(input.value);
}
}
<table>
<tr val='answer'>
<td>
<input type='checkbox' />
<input value="Some value" style='width:483px' type='text' />
</td>
</tr>
</table>
my table looks like this.
<body>
<table class="tblTest">
<tr>
<td>
<label>wer</label></td>
<td>
<label>ur4</label></td>
<td>
<label>ksdj</label></td>
</tr>
<tr>
<td>
<label>eiejr</label></td>
<td>
<label>ur4</label></td>
<td>
<label>yutu56</label></td>
</tr>
<tr>
<td>
<input type="text" /></td>
<td>
<input type="text" /></td>
<td>
<input type="text" />
</td>
</tr>
<tr>
<td>
<label>jweee</label>
</td>
<td>
<label>male</label>
</td>
<td>
<label>ur4</label>
</td>
</tr>
<tr>
<td>
<label>ssssss</label>
</td>
<td>
<label>male</label>
</td>
<td>
<label>ur4s</label></td>
</tr>
<tr>
<td>
<input type="text" /></td>
<td>
<input type="radio" name="gender" value="male" />Male
<br />
<input type="radio" name="gender" value="female" />Female
</td>
<td>
<select name="cars" style="width: 128px">
<option selected="selected" value="Select">Select</option>
<option value="saab">BMW</option>
<option value="fiat">Fiat</option>
<option value="audi">Audi</option>
</select>
</td>
</tr>
</table> <br />
<button type="button" onclick="function1()">Submit</button>
I want a Java script/jQuery which will check the two labels and if there is a mismatch then it will make the Text Box Red and if not then green. I can't use getElementById for the labels only I have to traverse through it and get the td index and do the task. I Don't know how to get prev and closest elements. Please help me with this.
The function which I'm trying is
function function1() {
var inputcontrols = document.getElementsByTagName('input');
for (var i = 0; i < inputcontrols.length; ++i)
{
var element = inputcontrols[i];
//element.style.background = "#90EE90"; by default making it green
var ind = $(this).closest('td').prev('td').text();
alert(ind);
}
Trying to get the td text in "ind", but its returning empty.
First get all the inputs, and use the each loop to iterate these. And by using the index to get the appropriate label texts.
The reason text() did not work for you, is because you are trying to get the text from the td element. This is empty, because it only contains a HTMLElement label. Look at the jQuery specs to see the difference between text() and html()
function function1() {
$('table').each(function(n, table) {
$(table).find('tr').each(function(n, tr) {
tr = $(tr);
var td = undefined;
var c = 0;
tr.find('input,select').each(function(i, input) {
if(!td || !td.is($(input).closest('td'))) {
td = $(input).closest('td');
c++;
}
var lbl1 = $(tr.prev().prev().find('td')[c]).find('label').text();
var lbl2 = $(tr.prev().find('td')[c]).find('label').text();
if(lbl1 === lbl2) {
$(input).css('backgroundColor', 'green');
} else {
$(input).css('backgroundColor', 'red');
}
});
});
});
}
The first problem I see is that you're using $(this) which is what how you chain the function scope in jQuery. For example:
$('a').each(function() {
// 'this' scopes to the current 'a' element inside the 'each' loop
$(this).css('color', '#FF0000');
});
Since you've already found your input controls and stored them in var element you need to pass that element into jQuery so it knows what you're looking for.
var element = inputcontrols[i];
$(element).closest('td').prev('td').text();
Next, if you're trying to compare the text field to the previous label you need to fix your traversal steps to be:
From the text field
Find its parent tr not td (go up to the row)
Find its the previous tr (go back a row)
Find its child label (drill down into the previous row)
Get the text from the label
assuming that you only have two table rows, you can try this-
function function1() {
var inputs = $('.tblTest input');
var tr1 = $('.tblTest tr:nth(0)');
var tr2 = $('.tblTest tr:nth(1)');
for (var i = 0; i < inputs.length; ++i)
{
var element = inputcontrols[i];
if(tr1.find('td:nth('+ i +') label').html().trim() == tr2.find('td:nth('+ i +') label').html().trim()) {
element.style.background = "green";
}
else {
element.style.background = "red";
}
}
}
Well I've ripped my hair off because I assumed I was finished this script but suddenly adding ONE more for loop broke every single indexOf, I tried to create checks so the console wouldn't freak out, but sadly no success. using a static value for "z" or LevelCheck allows for all the indexOfs to work properly but as soon as a for loop is involved, it seems none of the indexOfs wishes to work
<script type="text/javascript">
var tempval = new Array();
function Renew(){ //Reset tempval back to val
for(d=0;d<val.length;d++){
tempval[d] = val[d];
}
}
function UpdateLoop(){
Renew();
var Levels = document.getElementById("Lvl");
if(Levels){
for(z=0; z<=Levels.value; z++){
Update(z);
}
}
}
function Update(LevelCheck){
for (i=0; i<=key.length; i++){
if(key[i] != null){
if ( key[i].indexOf("rate") > -1 ) { //Search through
for (r=0; r<=key.length; r++){
if(key[i].indexOf(key[r]) > -1){ //Finds out which form it should replace
var raw=tempval[i];
for (y=0; y<=key.length; y++){
if(key[i] != "movespeed" && key[i] != "Movrate"){ //add a check to see if string is not there
var item = document.getElementById(key[y]);
if (item) { //Make it use formula value and then put that result into a value and loop back into function until level reached. If level changed to a lower number, reset to original value and repeat
//raw=raw.replace(key[y],document.getElementById(key[y]).value); //replace this with val[y]
raw=raw.replace(key[y],tempval[y]);
}
}
else
break;
}
if(raw != null){
if(raw.indexOf("Mov") > -1){
for(x=0; x<=key.length; x++){
if(key[x].indexOf("movespeed") > -1){
//raw=raw.replace("Mov",document.getElementById(key[x]).value);
raw=raw.replace("Mov",tempval[x]);
break;
}
}
}
if(raw.indexOf("Lvl") > -1){
raw=raw.replace("Lvl",document.getElementById('Lvl').value);
}
if(raw.indexOf("Exp") > -1){
raw=raw.replace("Exp","0");
}
}
if( document.getElementById('Lvl').value == LevelCheck){
alert("Input:"+tempval[i]);
if(key[i] == "Movrate"){
document.getElementById("movespeed").value = eval(raw);
}
else{
var check = document.getElementById(key[r]);
if (check){
document.getElementById(key[r]).value = eval(raw);
}
}
}
else{
tempval[r] = eval(raw);
}
break; //So it doesn't keep searching
}
}
}
}
}
}
</script>
Html portion(This is generated via php so I just used what the browser generated)
<table>
<tbody>
<tr>
<td>Creature Name:</td>
<td>
<input type="Text" name="CName" value="Thing" size="10%">
</td>
</tr>
<tr>
<td>Level:</td>
<td>
<input type="Text" id="Lvl" name="level" onchange="" value="1" size="10%">
</td>
</tr>
<tr>
<td>movespeed:</td>
<td>
<input type="Text" name="movespeed" id="movespeed" value="1" size="10%">
</td>
</tr>
<tr>
<td>str:</td>
<td>
<input type="Text" name="str" id="str" value="4" size="10%">
</td>
</tr>
<tr>
<td>dex:</td>
<td>
<input type="Text" name="dex" id="dex" value="3" size="10%">
</td>
</tr>
<tr>
<td>int:</td>
<td>
<input type="Text" name="int" id="int" value="1" size="10%">
</td>
</tr>
<tr>
<td>will:</td>
<td>
<input type="Text" name="will" id="will" value="2" size="10%">
</td>
</tr>
<script type="text/javascript">
var key=new Array();
var val=new Array();
key.push("movespeed");
val.push("1");
key.push("str");
val.push("4");
key.push("dex");
val.push("3");
key.push("int");
val.push("1");
key.push("will");
val.push("2");
key.push("Movrate");
val.push("Mov+1");
key.push("strrate");
val.push("1+str");
key.push("dexrate");
val.push("1+dex+(str/4)");
key.push("intrate");
val.push("1+int");
key.push("willrate");
val.push("1+will");
</script>
<tr>
<td>
<input type="button" name="button" value="Use Formula" onclick="UpdateLoop();">
</td>
<td>
<input type="submit" value="Save">
</td>
Console:
Uncaught TypeError: Object 2 has no method 'indexOf' Monsters.php:62
Update Monsters.php:62
UpdateLoop Monsters.php:39
onclick Monsters.php:28
you need to change your Update function to the following:
function UpdateLoop(){
var Levels = document.getElementById("Lvl");
if(Levels){
for(z=0; z<=Levels.value; z++){
Renew();
Update(z);
}
}
}
After processing Level 0, the tempval array had the values from Level 0, which wiped out the original values from the val array.
Making this change fixed the problem in my tests: http://jsfiddle.net/jimmym715/xTUND/
oh, and what MaxArt said in the comments above is right on the money... there are far better ways to accomplish what you're going for here
Turns out that flat numbers are NOT strings so in order to safely go through every value .toString() had to be present, thanks everyone for trying though.
so it would look like:
key[i].toString().indexOf(key[r])