Suppose I have a form with 20 rows as shown in the figure below:
I'm naming the elements in the each row as:
1st row (Ambiance) -> v1[requirement], v1[observation], v1[status], v1[remarks]
2nd row (TV Room) -> v2[requirement], v2[observation], v2[status], v2[remarks]
3rd row (Cleanliness) -> v3[requirement], v3[observation], v3[status], v3[remarks]
.... and so on till 20th row
Using jquery or javascript can I find the number of rows present based on the names of the element? i.e., in this form name starts from v1 and ends at v20. So there are 20 rows.
UPDATE
The reason why I want the number of rows is because I plan to process the forms using:
for($i=1; $i<=$rowcount; $i++)
{
$v.$i = $_POST['v'.$i];
// then insert the first row into table and so on
}
If there is always a header row, then the number of rows will be the number of tr elements in the table -1, Eg.
var rowCount = $("#myTable tr").length -1;
This saves you having to use some convoluted method of attribute selector or string parsing.
This approach should work for you:
var rowCount = $("#data-table tr").filter(function() {
return $(this).find('[name^="v"]').length;
}).length;
This code will count only tose rows which have input with the name starting with v. I guess this is what you need.
Quick demo: http://jsfiddle.net/dfsq/2P5cN/
UPD
As per Mark Reed's comment we can make it even more simple:
var rowCount = $('#data-table tr').has('[name^=v]').length;
If you can't modify the markup at all, then you'll pretty much have to loop over everything and do your own counting. Something like this:
var tds = document.getElementsByTagName('td'); // or just $('td') for jQuery
var count_tds = tds.length;
var max = 0;
for (var i=0; i<count_tds; ++i) {
var td = tds[i]
var m = td.id.match(/^v(\d+)\[/)
if (m) {
if (m[1] > max) max=m[1]
}
}
Now max is the number of rows, assuming there are no extraneous elements with id's that match the pattern.
http://jsfiddle.net/usDD7/1/
EDIT Clearly I wasn't thinking with jQuery. See dfsq's answer for a much better solution (and my comment on that answer for a tiny improvement).
Related
I have a table that I'm trying to insert a paypal button in the last cell of the table which is blank. I'm not sure how many rows will be in the table and I have the id's hard coded now which works. The id's begin with el and a number for each row then _qryMyReservedSlots_Payment
['#el1_qryMyReservedSlots_Payment', '#el2_qryMyReservedSlots_Payment', '#el3_qryMyReservedSlots_Payment'].forEach(function(selector) {
paypal.Button.render({
...paypal code...
});
});
to be more efficient, how can I loop through the id's so I don't have to hard code them?
Scott
I'm not sure how many rows will be in the table and I have the id's
hard coded now which works
Use querySelectorAll and attribute contains selector - *
var allRows = document.querySelectorAll( "tr[id*='qryMyReservedSlots_Payment']");
Array.from( allRows ).forEach( function(rowElement){
//logic with rowElement
})
Use a for loop:
for (var el = 1; el < 4; el++) {
var selector = `#el${el}_qryMyReservedSlots_Payment`
...
}
or more old-fashioned:
for (var el = 1; el < 4; el++) {
var selector = '#el' + el + '_qryMyReservedSlots_Payment'
...
}
Do you need them to have unique ids ? You should give them a class and then do something like document.getElementsByClassName(className).forEach(...).
If you insist on having unique ids (which, again, is not needed and this is exactly one of the reasons why we have classes), your could would be something like this:
while (document.getElementById(`el${ counter++ }_qryMyReservedSlots_Payment`)) {
paypal.Button.render({
...paypal code...
});
}
Again, this is not good because each time you query the id, you are hitting the DOM. You should really get it all at once, manipulate in-memory, and then commit all your changes in as few DOM calls as possible.
I am having difficulty in understanding as to why my search of a table column is always showing the first row and the matched row after that? Even though the keyword doesn't match the cell in row 1 it will always show on top? I have gone through my code several times and tried different approach it still wont hide the first row?
Here is my working code
$('#filterbyname').on("keyup", function () {
var val = $(this).val();
var matches = $("table.bill tr:not(:first-of-type)");
matches.each(function (i,e) {
debugger;
$row = $(this);
$cells = $row.find("td:nth-child(2)");
$cells.each(function (i2, e2) {
var cell = $(this).text();
debugger;
$row.toggle(cell.indexOf(val) >= 0);
});
});
});
You can see from the above code if cell.indexOf(val) >= 0) then it will toggle according the matching rows.
Any suggestions please?
In fact in your matches variables you are using tr:not(:first-of-type) which selects all the rows expect the first one, because :not selector excludes all elements that matches :first-of-type here, which means that they are not the first child in their parent, so the first tr will be ignored.
Change this code:
var matches = $("table.bill tr:not(:first-of-type)");
To the following:
var matches = $("table.bill tr");
I am new to jQuery and hope someone can help me with this.
I have a large, dynamically created table that contains 3 columns, one for amounts that need to be subtracted, one for amounts that need to be added and one for the sum of each row.
So far I have the below which works as intended.
However, on the first row of the tbody it doesn't make sense to check for the sum from the previous row as there is no previous row.
Only in this case it should take the initial balance which appears in a th of the thead (class = "calcStart") instead of the sum of a previous row.
Can someone tell me how I can achieve this ?
Also, if there is something that can be written better / shorter in the code I have please let me know as well.
My JS:
var calcMinus, calcPlus;
var calcSum = 0;
$(document).on('keyup', '.calcMinus, .calcPlus', function(){
$(this).closest('table tbody').find('td.calcSum').each(function(){
calcMinus = Number( $(this).closest('tr').find('td.calcMinus').find('div').text() );
calcPlus = Number( $(this).closest('tr').find('td.calcPlus').find('div').text() );
if((calcMinus == '') && (calcPlus == '')){
$(this).text('0');
}else{
calcSum += Number( $(this).closest('tr').prev('tr').find('td.calcSum').text() );
calcSum -= calcMinus;
calcSum += calcPlus;
$(this).text(calcSum);
}
calcSum = 0;
});
});
Many thanks in advance,
Mike
use below code .. use :gt() selector
:gt(0)
Select all elements at an index greater than index within the matched
set.
$(this).closest('table tbody').find('td.calcSum:gt(0)').each(function(){
if you wan to skip first th then use below code
$(this).closest('table tbody').find('th:gt(0) td.calcSum').each(function(){
As Discussed with OP here another option to avoid first row
pass index in each function with index parametar
$(this).closest('table tbody').find('td.calcSum').each(function(index){
if (index === 0){}else{} });
I am trying to generate a table dynamically using ajax call. To simplify things i have just added my code to js fiddle here -> http://jsfiddle.net/5yLrE/81/
As you click on the button "HI" first two columns are created properly.. but some how as the td length reaches 2 . its not creating another row. The reason is that when i do find on the table elements its actually retrieving the children table elements. Can some one pls help.
I want a two column table.. Thank you.
sample code:
var tr = $("#maintable tbody tr:first");
if(!tr.length || tr.find("td:first").length >= max) {
$("#maintable").append("<tr>");
}
if(count==0) {
$("#maintable tr:last").append("<td>hi"+content+"</td>");
}
Basically the matching of descendants was allowing for great great grandchildren etc. Just needed to make the matching more specific.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/5yLrE/91/
max = 2
$("button").click(function () {
var content = $('#template').html();
var $table = $("#maintable");
var tr = $table.find(">tbody>tr:last");
if (!tr.length || tr.find(">td").length >= max) {
// Append a blank row
tr = $("<tr>");
$table.append(tr);
}
tr.append("<td>hi " + content + "</td>");
});
This one always targets the last row and adds a row if it does not exists at all (or there are too many divs already) which is what I gather you intended.
I also used the templating I suggested to separate messy HTML strings from the code.
You will want to check the length of the table cells before incrementing a new table row. After you have reached your max column length, reset the row and start over.
JSFiddle
max_columns = 2;
count=0;
$("button").click(function() {
var content='column';
if(count==max_columns||!$('#maintable tr').length){
$("#maintable").append("<tr>");
count=0;
}
if(count!=max_columns)
$("#maintable tr:last").append("<td>"+content+"</td>");
else
$("#maintable tr:first").append("<td>"+content+"</td>");
count++;
});
I would like a script that removes every table row for which the keyword STRING is found in a cell, but my script seems to remove every other row that contains the STRING keyword. Apparently, every time a row is deleted the numbering of the rows is updated? How would one account for this? Thanks in advance.
<script type="text/javascript">
var table = document.getElementById("DatePreferred").firstChild;
var rowCount = table.rows.length;
for(var i=0; i<rowCount; i++) {
var row = table.rows[i];
var text = row.cells[0].innerText;
if(text.indexOf("STRING")!=-1){
table.deleteRow(i);
}
}
</script>
Edit: So FishBasketGordo's answer got my script to work for IE and Safari but it wasn't working in FF. I looked into where the error was and apparently FF handles .innerText differently. You have to use .textContent instead. So if you add this below to the script above it will use the appropriate method:
if (row.cells[0].textContent){
var text = row.cells[0].textContent;}
else {var text = row.cells[0].innerText;}
When I need to do something like this, I like to work backward:
for(var i= rowCount - 1; i >= 0; i--) {
var row = table.rows[i];
var text = row.cells[0].innerText;
if(text.indexOf("STRING")!=-1){
table.deleteRow(i);
}
}
Just decrement i using i-- when you remove a row, so that your for loop re-examines the same index (which will now contain the next row).
EDIT: Having looked at your code again, you'll want to compare i to table.rows.length rather than your rowCount variable to account for the changing length of table.rows.