I've just recently learned how jquery can access dynamically generated content, by placing a "bubble" around its parent object (or first available parent that is not dynamic), and then telling it how to handle an event from within it etc.
I have a table (static) and rows are dynamically added.
<table class="aBorder_ClearBlack" width="100%" id="tblEveryone">
<tr class="TableHeading_Dark_Small">
<td>Current User Calls</td>
<td><span id="theRefresh" style="cursor:pointer">
<img ... onclick="javascript:clicky()"...></span>
</td>
</tr>
and the code that adds the rows:
function clicky() {
var table = document.getElementById("tblEveryone");
var tmpRowCount = table.rows.length;
//clear existing rows first (else it just appends)
for (var x = 2; x < tmpRowCount; x++) {
table.deleteRow(x);
tmpRowCount--;
x--;
}
jQuery.each(users, function (index, user) {
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
row.style.display = "none"; <--------
row.setAttribute('class', 'BeforeHover_Clean');
var cell1 = row.insertCell(0);
cell1.innerHTML = users[index].Name;
var cell2 = row.insertCell(1);
cell2.innerHTML = users[index].Calls;
});
$(".BeforeHover_Clean").show(); <-----
}
then the code i use to "bind" click events on each row
$(document).ready(function () {
$('#tblEveryone').delegate(".BeforeHover_Clean", "click", function () {
var whatClicked = this.innerHTML.toLowerCase().split("</td>")[0].split("<td>")[1];
document.getElementById("aIframe").src = "Calls.aspx?aUser=" + whatClicked;
});
});
The thing is (line marked with <---- above, second block), row.style.display, correctly starts off the items with none as visibility, but the last line, $(".BeforeHover_Clean").show(); obviously wont work as the content is dynamic. Is there a way to manipulate the delegate, or some other jquery feature, to set the items visible again when needed?
I am clueless at this level. Binding "click" events to the parent is as good as i got! lol. I feel like charles babbage now! ;)
The fact that it is dynamic shouldn't matter.
You hae a rather strange mix of jQuery and DOM JavaScript whjich probably isn't helping, and is also bloating your code substantially.
For example, your each loop can be condensed as follows:
jQuery.each(users, function (index, user) {
var $newRow = $("<tr class='BeforeHover_Clean'><td>" + users[index].Name+ "</td><td>" + users[index].Calls + "</td></tr>").hide();
$("#tblEveryone").find('tbody').append($newRow);
});
Try using the ID selector $("#myid"); instead of document.getElementById(); and also playing around with some of the jQuery DOM manipulation methods, append(), prepend(), insertAfter(), etc.
Not a specific answer to your question, but hopefully some helpful guidelines.
Related
I'm not the best at using jQuery, but I do require it to be able to make my website user-friendly.
I have several tables involved in my website, and for each the user should be able to add/delete rows. I created a jquery function, with help from stackoverflow, and it successfully added/deleted rows. Now the only problem with this is the names for those input fields is slightly messed up. I would like each input field to be an array: so like name[0] for the first row, name[1] for the second row, etc. I have a bunch of tables all with different inputs, so how would I make jQuery adjust the names accordingly?
My function, doesn't work completely, but I do not know how to go about changing it.
My Jquery function looks like:
$(document).ready(function() {
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
clone.find("select").val('');
clone.find('input').each(function(i) {
$(this).attr('name', $(this).attr('name') + i);
});
clone.find('select').each(function(i) {
$(this).attr('name', $(this).attr('name') + i);
});
tr.after(clone);
});
$("body").on('click', '.delete_row', function() {
var rowCount = $(this).closest('.row').prev('table').find('tr.ia_table').length;
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
if (rowCount > 1) {
tr.remove();
};
});
});
I also created a jsFiddle here: https://jsfiddle.net/tareenmj/err73gLL/.
Any help is greatly appreciated.
UPDATE - Partial Working Solution
After help from a lot of users, I was able to create a function which does this:
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
clone.find("select").val('');
clone.find('input').each(function() {
var msg=$(this).attr('name');
var x=parseInt(msg.split('[').pop().split(']').shift());
var test=msg.substr(0,msg.indexOf('['))+"[";
x++;
x=x.toString();
test=test+x+"]";
$(this).attr('name', test);
});
clone.find('select').each(function() {
var msg1=$(this).attr('name');
var x1=parseInt(msg1.split('[').pop().split(']').shift());
var test1=msg1.substr(0,msg1.indexOf('['))+"[";
x1++;
x1=x1.toString();
test1=test1+x1+"]";
$(this).attr('name', test1);
});
tr.after(clone);
});
A working jsFiddle is here: https://jsfiddle.net/tareenmj/amojyjjn/2/
The only problem is that if I do not select any of the options in the select inputs, it doesn't provide me with a value of null, whereas it should. Any tips on fixing this issue?
I think I understand your problem. See if this fiddle works for you...
This is what I did, inside each of the clone.find() functions, I added the following logic...
clone.find('input').each(function(i) {
// extract the number part of the name
number = parseInt($(this).attr('name').substr($(this).attr('name').indexOf("_") + 1));
// increment the number
number += 1;
// extract the name itself (without the row index)
name = $(this).attr('name').substr(0, $(this).attr('name').indexOf('_'));
// add the row index to the string
$(this).attr('name', name + "_" + number);
});
In essence, I separate the name into 2 parts based on the _, the string and the row index. I increment the row index every time the add_row is called.
So each row will have something like the following structure when a row is added...
// row 1
sectionTB1_1
presentationTB1_1
percentageTB1_1
courseTB1_1
sessionTB1_1
reqElecTB1_1
// row 2
sectionTB1_2
presentationTB1_2
percentageTB1_2
courseTB1_2
sessionTB1_2
reqElecTB1_2
// etc.
Let me know if this is what you were looking for.
Full Working Solution for Anyone Who needs it
So after doing loads and loads of research, I found a very simple way on how to do this. Instead of manually adjusting the name of the array, I realised that the clone method will do it automatically for you if you supply an array as the name. So something like name="name[]" will end up working. The brackets without any text has to be there. Explanation can't possible describe the code fully, so here is the JQuery code required for this behaviour to work:
$(document).ready(function() {
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
tr.after(clone);
});
$("body").on('click', '.delete_row', function() {
var rowCount =
$(this).closest('.row').prev('table').find('tr.ia_table').length;
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
if (rowCount > 1) {
tr.remove();
};
});
});
A fully working JSfiddle is provided here: https://jsfiddle.net/tareenmj/amojyjjn/5/
Just a tip, that you have to be remove the disabled select since this will not pass a value of null.
I am attempting to replace an image in a table on a click. I am not using JQuery; I am only Javascript to achieve this task. I think I have narrowed down the problem to the comment in the JavaScript code below. All other searches have ended me up with how to change image sources when they are part of the body etc. not part of a cell. I ran through other possible ways as well but for some reason I can't get it to work. Thanks so much!
HTML (Just cut out so you could see what each of the variables is referring to)
<td class="block"><img class="PieceImg" src="Directory/BlankSpace.png"></td>
JavaScript
var cells = document.getElementsByClassName("PieceImg");
for(var j = 0; j<cells.length;j++)
{
var cell = cells[j];
cell.addEventListener("click", function()
{
cell.src="Directory/RedPiece.png"; // This is the problem
alert('Test');
})
}
Assuming that you are running your JavaScript once the DOM is loaded, you should just have to replace cell.src with this.src.
var cells = document.getElementsByClassName("PieceImg");
for(var j = 0; j<cells.length;j++)
{
var cell = cells[j];
cell.addEventListener("click", function()
{
// Replace cell. with this.
this.src="Directory/RedPiece.png";
alert('Test');
})
}
The reason is simple: every time you loop, you create a variable called "cell" (var cell = cells[j];). This non-global variable is overwritten every time the loop is run. If you are running this code inside of a function, your cell variable will not even exist when it comes time to change the src. It will be undefined. Note that making this variable global would result in cell being the last element by class name PieceImg, so that wouldn't work any better.
However, if you use this instead, you will be referencing the "clicked" (remember addEventListener("click")) element when you click it, in this case your image. Thus you are able to change the src. Do a console.log of "this" inside your eventListener to see more things you can access. This gives a similar effect as adding the "click" handler inline:
<img src="fox.png" onclick="alert(this.src);" alt="Fox" />
Let me know if that makes sense to you.
Here's a fully function fiddle: https://jsfiddle.net/7se0vyf5/
Problem is the for loop and the reference of the variable. It does not keep the state when you assign the event handler.
var cells = document.getElementsByClassName("PieceImg");
for (var j = 0; j < cells.length; j++) {
var cell = cells[j];
(function(cell){
cell.addEventListener("click", function() {
console.log(cell);
cell.src = "Directory/RedPiece.png"; // This is the problem
alert('Test');
});
}(cell));
}
<table>
<tr>
<td class="block">
<img class="PieceImg" src="Directory/BlankSpace.png">
</td>
<td class="block">
<img class="PieceImg" src="Directory/BlankSpace.png">
</td>
<td class="block">
<img class="PieceImg" src="Directory/BlankSpace.png">
</td>
</tr>
</table>
I have a table that is created in ASP.NET C# code behind. The table has several levels of groupings, and when I create the rows for the outer most grouping, I add an custom attribute as follows:
foreach (Table2Row row in Table2Data)
{
// skipping a bunch of irrelevent stuff
...
tr_group.Attributes.Add("RowsToToggle", String.Format(".InnerRowGroupId_{0}", row.GroupHeaderId));
...
}
The attribute is the CSS class name of the inner level rows that I would like to toggle. When the user clicks on the outer level row, I would like to call JQuery Toggle function for all inner level rows that match the custom attribute.
To achieve that effect, I have attached an onclick event to the header rows with the following script in the aspx file:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
}
});
function ToggleOnRowClick(row) {
var r = $('#' + row.id);
var innerRows = r.attr('RowsToToggle');
$(innerRows ).toggle();
}
So, clicking anywhere on the header row should call the function ToggleOnRowClick, which should then toggle the set of rows below it via the custom attribute RowsToToggle.
When I set a (FireBug) break point in the ToggleOnRow function, the variable r appears to be pointing to the correct object. However, innerRows is not getting set but instead remains null. So am I setting the custom attribute incorrectly in ASP.NET or reading in incorrectly in JQuery?
You did not post the code to generate inner level rows, I am assuming you sat proper classes to them.
There are few issues with the jquery you posted. This line wouldn't work:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i]); }
You don't have any groupRows property defined for table object.
We don't care about table row anymore, we care about groupRows[i] and want to pass it to ToggleOnRowClick function.
This line in next function is also wrong:var r = $('#' + row.id);
Solution: Change your script to this:
var tableId = '<%= Table2MainTable.ClientID %>';
$(document).ready(function () {
var table = document.getElementById(tableId);
var groupRows = table.getElementsByClassName("Table2GroupHeaderRow");
for (i = 0; i < groupRows.length; i++) {
groupRows[i].onclick = function () { ToggleOnRowClick(this); }
}
});
function ToggleOnRowClick(row) {
//var r = $('#' + row.id);
var innerRows = $(row).attr('RowsToToggle');
$("." + innerRows).toggle();
}
I have tested the code with dummy data. So if you have any issue, PM me.
This line is your culprit:
table.groupRows[i].onclick = function () { ToggleOnRowClick(table.rows[i])
By the time the event handler runs, table.rows might still exist, but i will be set to groupRows.length+1, which is out of bounds for the array. The handler will get called with an argument of undefined.
Remember, Javascript is an interpreted language! The expression "table.rows[i]" will get interpeted when the handler runs. It will use the last value of i (which will still be set to the value that caused your for loop to end, groupRows.length+1).
Just use
table.groupRows[i].onclick = function () { ToggleOnRowClick(this) }
So, First you shouldn't use custom attributes... they are a sin!
Please use data attributes instead, so that is what I'm going to use in the code, should be an easy fix regardless.
If this doesn't work then I'd be very very interested in seeing a dumbed down HTML snippet of the actual output.
$(document).ready(function () {
$('#MYTABLE').on('click', '.Table2GroupHeader', function() {
var attr_if_you_insist_on_sinning = $(this).attr("RowsToToggle");
var data_if_you_like_not_sinning = $(this).data("RowsToToggle");
//if the row is like <tr data-RowsToToggle=".BLAH" or th etc
//asumming you set the attribute to .BLAH then:
var rows_to_toggle = $(data_if_you_like_not_sinning);
rows_to_toggle.toggle();
//assuming you set it to BLAH then:
var rows_to_toggle = $("."+ data_if_you_like_not_sinning);
rows_to_toggle.toggle();
});
});
$(document).ready(function () {
$('#<%= Table2MainTable.ClientID %> .Table2GroupHeader').each(function(){
$(this).click(function(){
$(this).toggle();
});
});
});
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have code in the following style :
<tr id="201461">
<td id="0A" style="cursor:pointer" onClick = "ProcessTextBoxClick()" value="Feb 23 2008">Feb 23 2008</td>
<td id="0B" style="cursor:pointer" onClick = "ProcessTextBoxClick()" value="Feb 25 2008">Feb 25 2008</td>
<td id="0C" style="cursor:pointer" onClick = "ProcessTextBoxClick()" value="Feb 28 2008">Feb 28 2008</td></tr><tr id="201460">
<td id="1A" style="cursor:pointer" onClick = "ProcessTextBoxClick()" value="47">47</td></tr>
I have some JQuery where I am getting the id of each row, and now I want to get each value in each td for each row. How do I do this?
var tbl = document.getElementById("tbl-1");
var numRows = tbl.rows.length;
for (var i = 1; i < numRows; i++) {
var ID = tbl.rows[i].id;
Your code does not look like jQuery. Are you sure you aren't using the term jQuery as a synonym to JavaScript? :) If that is the case, I suggest you read this question as well; it will make things a lot more clear for you.
Anyway, here goes JavaScript:
var tbl = document.getElementById("tbl-1");
var numRows = tbl.rows.length;
for (var i = 1; i < numRows; i++) {
var ID = tbl.rows[i].id;
var cells = tbl.rows[i].getElementsByTagName('td');
for (var ic=0,it=cells.length;ic<it;ic++) {
// alert the table cell contents
// you probably do not want to do this, but let's just make
// it SUPER-obvious that it works :)
alert(cells[ic].innerHTML);
}
}
Alternatively, if you really use jQuery:
var table = $('#tbl-1').
var rowIds = [];
var cells = [];
$('tr', table).each(function() {
rowIds.push($(this).attr('id'));
$('td', $(this)).each(function() {
cells.push($(this).html());
});
});
// you now have all row ids stores in the array 'rowIds'
// and have all the cell contents stored in 'cells'
in jQuery:
$("table#tbl-1 tr").each(function( i ) {
$("td", this).each(function( j ) {
console.log("".concat("row: ", i, ", col: ", j, ", value: ", $(this).text()));
});
});
You can check it in work here: http://jsfiddle.net/3kWNh/
I want to get each value in each td for each row
Do you want the value of the value attribute, the HTML, or the HTML stripped of markup? The various answers so far have mostly gone with "the HTML", at least one went with "the HTML stripped of markup", but none (so far) has gone with "the value of the value attribute". So:
Using jQuery:
var valuesByRowID = {};
$("#tbl-1 tr").each(function() {
valuesByRowID[this.id] = $(this).find("> td").map(function() {
// Option 1: Getting the value of the `value` attribute:
return this.getAttribute("value"); // or return $(this).attr("value");
// Option 2: Getting the HTML of the `td`:
return this.innerHTML;
// Option 3: Getting the HTML of the `td` with markup stripped:
return $(this).text();
}).get();
});
The end result is an object with properties for each row, with the property name being the row's id value, and the property value being an array of the td information.
So for instance, to get the array for row 201461, you can do this:
var data = valuesByRowID["201461"]; // Note that property names are strings
var index;
for (index = 0; index < data.length; ++index) {
alert(data[index]);
}
The above uses:
$() to find the rows in the table.
map (followed by get) to build the array of values.
A simple JavaScript object to hold the result. JavaScript objects are, at heart, maps (aka dictionaries, aka associative arrays, aka name/value pair collections).
Off-topic:
As I mentioned in a comment on the question, the HTML you've listed there is "invalid" in W3C terminology, td elements don't have a value attribute. You might consider using data-* attributes instead.
As Spudley pointed out in a comment on the question, those id values are likely to cause you trouble. Recommend not having id values that start with a digit. Although valid in HTML5, they're not valid in earlier versions of HTML and not valid in CSS. Since jQuery uses CSS selectors, if you're using CSS, I would strongly advise sticking to the CSS rules. (In your case, it's really easy: Just put an d on the front of them or seomthing.)
You can simply do
$("td","#tbl-1").each(function(){
//access the value as
$(this).html()
});
What you are using there is not jQuery, if you are using jQuery you can use .html(); to retrieve the value.
Here is your code with jQuery:
$('#tbl-1 td').each(function(){
var ID = $(this).attr('id');
var value = $(this).html();
});
If you want to loop over all <td>
$('#tbl-1 td').each(function() {
// do stuff for each td in here...
alert($(this).html());
})
NOTE: This is jQuery whereas your example is native JavaScript.
In this fiddle you see a table with a select-field where you should select a name.
Below there are 5 input-fields where one could type in some text and 3 input-fields which are set to readonly.
I wanted to ask whether there is a way to add table cells dynamically when clicking on the button. The result should like this fiddle. The id should be incremented by i+.
I tried cloning the code, but could't figure out how to do increment the id of the cloned input-field. The only input-fields I do not want to clone are the readonly input-fields.
Do you have an example code or a link you would recommend? A hint to start would be helpful as well.
I've been searching the net already, but wasn't able to find something.
Here is the code you ask (i added an id to the button to target it easy)
$('#add').click(function(){
$(this)
.closest('table')
.find('tr td:first-child:not(:has([readonly]))')
.each(function(){
var $this = $(this);
$this
.clone()
.each(function(){
var $inp = $(':input',this);
var id = $inp.attr('id');
var idwithoutnum = id.replace(/([0-9]+)$/,'');
var maxId = $(':input[id^='+idwithoutnum+']:last').attr('id');
var idnum = parseInt(/([0-9]+)$/.exec(maxId)) + 1;
var newid = id.replace(/([0-9]+)$/,idnum);
$inp.attr('id', newid);
alert(newid); // remove this line
})
.insertAfter($this
.closest('tr')
.find('td:last')
);
});
});
example at http://jsfiddle.net/fMZDd/7/
I would choose not to use tables for dom manipulation. Either way, here is how you could do it.
to add a table cell
var td = document.createElement("td")
var idVals = prevId.match(/^([a-z_]*)([0-9]+)$/)
td.innerHTML = "<input type='text' id='"+ idVals[1] + (parseInt(idVals[2]) + 1) +">";
tr.appendChild(td)
Hope this helps.