This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
Objective: Have multiple "Full Product Specifications" buttons that need to toggle the visibility of their respective Product Specification Tables. Initially, set all Product Specification tables to NOT display, then use the buttons to control. Cant use jQuery because ... reasons/stupid old website I don't have full control over...
I'm trying to use an anonymous JavaScript Function, but I'm unsure how to pass in my table? Or if I even can? My JS is not that great...
With jQuery I could probably just use .click() and .closest(). Unsure how to translate into pure JavaScript, so this is what I have instead.
The error...
Uncaught TypeError: Cannot set property 'display' of undefined at HTMLButtonElement.y.(anonymous function).onclick
And the code...
var x = document.getElementsByClassName("pdp-full-specs-table");
console.log("There are " + x.length + " tables");
for(i = 0; i < x.length; i++){
x[i].style.display = "none";
}
var y = document.getElementsByClassName("pdp-full-specs-toggle");
console.log("There are " + y.length + " toggles");
for(i = 0; i < y.length; i++){
var pdpTable = x[i];
y[i].onclick = function(pdpTable){
// Make this a toggle later
pdpTable.style.display = "table";
}
}
And the HTML in case that helps anyone
<button type="button" class="btn btn-link pdp-full-specs-toggle">Full Specifications ›</button><br>
<table class="pdp-full-specs-table">
<tr>
<td>Product Size</td>
<td>some size</td>
</tr>
</table>
A simple, efficient solution is just to store the index of each element on the element itself so that when the handler is invoked, you can reference it via the this reference to the element.
for(var i = 0; i < y.length; i++){
y[i].__table__ = i;
y[i].onclick = buttonHandler;
}
function buttonHandler() {
x[this.__table__].style.display = "table";
}
Some may use closures and such to accomplish this, but there's no need to be so complicated.
If each button comes just before each table, then you could do this.nextElementSibling to get to the table, but that won't work in IE8 and lower.
Related
This is a simple question I can't seem to figure out and every google search returns a million ways to do this via jquery, but I'd prefer to use vanilla javascript because I am new to it and want to learn it well before using any libraries. What I am trying to do is have a button collapse part of a table when clicked and then show those hidden parts again when clicked again. Basically just toggling the display of a class of elements.
I have a button that calls the test() function
when clicked nothing on my table changes. Here is my javascript code. I am using collapse[0] because if I understand it correctly collapse is a nodeList and I always close and open all of these together so I only need to check the first element.
function test() {
var collapse = document.getElementsByClassName("catOne");
var i = 0;//Counter for loops
if(collapse[0].style.display === "table-row"){
for(i = 0; i < collapse.length; i += 1){
collapse[i].style.display = "none";
}
}
if(collapse[0].style.display === "none"){
for(i = 0; i < collapse.length; i += 1){
collapse[i].style.display = "table-row";
}
}
}
I've tested the function with this code:
function test() {
var collapse = document.getElementsByClassName("catOne");
var i = 0;//Counter for loops
for (i = 0; i < collapse.length; i += 1) {
collapse[i].style.display = "none";
}
which works fine on collapsing the elements so evidentally the issue is with my if statement, but my IDE, Netbeans, doesn't throw any errors and as far as I can tell it should be working.
Thanks for the help.
Link to html and javascript: https://jsfiddle.net/ozjbekjy/
I suspect there are a few problems working against you.
First, you need to make sure the test() function is defined earlier in the page than it's being used. With jQuery, that means using the $(function(){}) wrapper to apply event handlers on DOM ready. You can approximate the same thing yourself with something like this answer.
Otherwise, simply place the <script> tag somewhere before the table (probably in the <head>), and the onclick will work.
You also are using i += 1 where you could be using i++ - they accomplish the same behavior.
Secondly, instead of manipulating the style attribute, use the classList.toggle() function to simply add and remove a class that has the rule display: none, like so:
CSS
.hide-me {
display: none;
}
JavaScript
function test() {
var collapse = document.getElementsByClassName("catOne");
for (var i = 0; i < collapse.length; i++) {
collapse[i].classList.toggle("hide-me");
}
}
Your JSFiddle, with the suggested updates: https://jsfiddle.net/ozjbekjy/4/
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
adding 'click' event listeners in loop [duplicate]
(5 answers)
Closed 7 years ago.
I have 5 buttons and I can not change DOM and can not use id and name attribute and cant use innerHTML and now I need to give output like when I click button 1 it should give a alert like "You click button # 1" and same will continue for all 5 buttons. I want to print the value of i .Now I got stuck as I have two solutions :
HTML Part:
//creating 5 buttons
<button>one</button>
<button>two</button>
<button>three</button>
<button>four</button>
<button>five</button>
1st Solution:
/* here I am always having you clicked element #5*/
var nodes = document.getElementsByTagName('button');//getting references
var counter;
for (var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', function() {
alert('You clicked element #' + i);
});
} //which is not working
2nd Solution:
/* here I am getting correct output*/
var nodes = document.getElementsByTagName('button');
var counter;
for (var i = 0; i < nodes.length; i++) {
assignEvent(nodes[i], i);
}
function assignEvent(node, i){
node.addEventListener('click', function(){
alert('You clicked element#' + (i+1));
});
}//this one is working
Now my question is why Solution 2 is working but solution 1 doesn't.. Please help. Why solution 2 is carrying the value of i correctly, while not solution 1.
If you don't want to create an additional function, just wrap the event listener assignment within a self-invoking anonymous function to which you pass 'i':
var nodes = document.getElementsByTagName('button');
var counter;
for (var i = 0; i < nodes.length; i++) {
(function(j) {
nodes[i].addEventListener('click', function() {
alert('You clicked element #' + (j+1));
});
})(i);
}
jsfiddle here: http://jsfiddle.net/vu31aa7y/
In your first solution when you add the anonymous function as parameter of addEventListener, the alert message is looking for the last value of i in this case i=5, that happens because you don't have the variable as local in the function, so your onlye possible value if the global variable.
If you want to do that try this:
var nodes = document.getElementsByTagName('button');//getting references
function alertMessage(i){
alert('You clicked element#' + (i+1));
}
for (i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', alertMessage.bind(null,i) , false);
}
Also I recommend you this lecture
You can write this:
[].forEach.call(document.getElementsByTagName('button'),
function(elt, index) {
elt.addEventListener('click', function() {
alert('You clicked element #' + (index + 1));
}, false);
});
http://jsfiddle.net/KKH9a/16/
Tried using console using table1.rows[0].cells[1].innerHTML => "Numbers"
Tried even this code table1.rows[0].cells[1].innerHTML!=null => true
But if I try this code below:
HTML:
<table id="table1">
<tr>
<td>Value</td>
<td></td>
</tr>
<tr>
<td>Value</td>
<td>Value</td>
</tr>
<table>
Javascript:
for (var i = 0; i < table1.rows.length; i++) {
for (var j = 0; j < table1.rows[i].cells[j].innerHTML; j++) {
if (table1.rows[i].cells[j].innerHTML != null) {
var count = 0;
count = count + 1;
alert(count);
}
}
}
table1 isn't defined. You need to use document.getElementById to get a reference to your table element.
On line 2 you're specifying j < table1.rows[i].cells[j].innerHTML. This doesn't make any sense and should be changed to j < table1.rows[i].cells.length.
You need to move your count variable completely outside your loop, otherwise it will always be equal to 1.
Change your code to this:
var table1 = document.getElementById('table1');
var count=0;
for(var i=0;i<table1.rows.length;i++)
{
for(var j=0;j<table1.rows[i].cells.length;j++)
{
if(table1.rows[i].cells[j].innerHTML!=null)
{
count++;
alert(count);
}
}
}
Working JSFiddle demo.
Work on understanding how Javascript interacts with the HTML DOM.
At present your code refers to "table1", but this has nothing to do with the HTML element with the id "table1".
Introductory Javascript tutorials will explain how to get DOM elements into variables. To make things easier, you could use JQuery or something similar.
Once you're past that, you can start looking at the errors in your for loop logic (which other answers have already addressed).
First, you shouldn't use innerHTML to check if there is something in a node. Just count the number of childs instead :
if (table1.rows[i].cells[j].childNodes.length > 0) {
Secondly, if you declare count inside the loops, it will be resetted at each iteration.
Thirldy, I don't understand what you're trying to do with j < table1.rows[i].cells[j].innerHTML. And innerHTML is a String, not a number. You should use parseInt on it.
Calculate count of cells using JQuery after document is ready
$(document).ready(function() {
var count = 0;
$('#table1 td').each(function() {
if($(this).html() != "") {
count++;
}
});
alert(count);
});
Updated Demo: http://jsfiddle.net/KKH9a/27/
I have a button that is defined as follows :
<button type="button" id="ext-gen26" class=" x-btn-text">button text here</button>
And I'm trying to grab it based on the text value. Hhowever, none of its attributes contain the text value. It's generated in a pretty custom way by the look of it.
Does anyone know of a way to find this value programmatically, besides just going through the HTML text? Other than attributes?
Forgot one other thing, the id for this button changes regularly and using jQuery to grab it results in breaking the page for some reason. If you need any background on why I need this, let me know.
This is the JavaScript I am trying to grab it with:
var all = document.getElementsByTagName('*');
for (var i=0, max=all.length; i < max; i++)
{
var elem = all[i];
if(elem.getAttribute("id") == 'ext-gen26'){
if(elem.attributes != null){
for (var x = 0; x < elem.attributes.length; x++) {
var attrib = elem.attributes[x];
alert(attrib.name + " = " + attrib.value);
}
}
}
};
It only comes back with the three attributes that are defined in the code.
innerHTML, text, and textContent - all come back as null.
You can do that through the textContent/innerText properties (browser-dependant). Here's an example that will work no matter which property the browser uses:
var elem = document.getElementById('ext-gen26');
var txt = elem.textContent || elem.innerText;
alert(txt);
http://jsfiddle.net/ThiefMaster/EcMRT/
You could also do it using jQuery:
alert($('#ext-gen26').text());
If you're trying to locate the button entirely by its text content, I'd grab a list of all buttons and loop through them to find this one:
function findButtonbyTextContent(text) {
var buttons = document.querySelectorAll('button');
for (var i=0, l=buttons.length; i<l; i++) {
if (buttons[i].firstChild.nodeValue == text)
return buttons[i];
}
}
Of course, if the content of this button changes even a little your code will need to be updated.
One liner for finding a button based on it's text.
const findButtonByText = text =>
[...document.querySelectorAll('button')]
.find(btn => btn.textContent.includes(text))
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.