I have the folowing code:
var transitionsSettingsClass = document.getElementsByClassName("transitionsSettings");
var transitionsSettingsClassLenght = transitionsSettingsClass.length;
for (i=0; i < transitionsSettingsClassLenght; i++);
{
transitionsSettingsClass[i].setAttribute("data-transition",transitionsSettings);
};
I know that transitionsSettingsClassLenght = 6 because I have checked it with alert. But when I put an alert inside cycle then it shows only 1-time (it should show 6-times). An also attribute data-transition is not set. But when I replace "i" inside transitionsSettingsClass[i] with transitionsSettingsClass[0] my first element changes and it is working. This script is supposed to change attribute data-transition in 6 elements.
Remove the ; at the end of
for (i=0; i < transitionsSettingsClassLenght; i++);
The for here only commands the code before the ;, that is nothing.
I'd recommend you to use the most frequent javascript style, as explicited by Google, as it helps avoid this kind of errors.
Have you tried with jquery each method?
$('.transitionsSettings').each(function(index) {
$(this).setAttribute("data-transition",transitionsSettings);
});
Just as a sidenote:
In all modern browsers you can set data- attributes by calling
node.dataset.transition = transitionsSettings;
The code below is interpreted as follows:
for (i=0; i < transitionsSettingsClassLenght; i++);
{
transitionsSettingsClass[i].setAttribute("data-transition",transitionsSettings);
};
The first line: for (i=0; i < transitionsSettingsClassLenght; i++); is executed 6 times as Javascript thinks its a single statement. Then it encounters
{
transitionsSettingsClass[i].setAttribute("data-transition",transitionsSettings);
}; which is executed once as a block. Removing the ; from the end of the for loop will solve the problem.
Related
I am admittedly a super newbie to programming in general. I am trying to design a quick piece of javascript to inject on a website for a class that will both uncheck and simulate a click on a series of checkboxes. This is nothing malicious, the web form we use to download data for use in this class presents way more variables than necessary, and it would be a lot more convenient if we could 'uncheck' all and only check the ones we want. However, simply unchecking the boxes via javascript injection doesn't yield the desired result. A mouse click must be simulated on each box. I have been trying to use the .click() function to no avail. Any help is greatly appreciated. My code below fails with an error of:
"TypeError: Cannot read property 'click' of null"
CODE:
var getInputs = document.getElementsByTagName("input");
for (var i = 0, max = getInputs.length; i < max; i++){
if (getInputs[i].type === 'checkbox')
getInputs[i].checked = false;
document.getElementById('shr_SUBJECT=VC' + i).click();
}
--------EDIT#1--------------
FYI, this is the website that I am trying to use this on:
http://factfinder2.census.gov/faces/nav/jsf/pages/searchresults.xhtml
if you search for and open up any of these tables they are huge. It would be awesome if I could easily pare down the variables by 'unchecking' and 'clicking' them all at once via javascript.
The code at the bottom ALMOST works.
The problem I am running into now is that it throws an error after the first or second run through the for loop:
"TypeError: document.getElementById(...) is null"
I understand that this is because the value it's trying to find doesn't exist? Sometimes on these tables the checkboxes are greyed out/don't exist or are otherwise 'unclickable'. My theory as to why I am getting this error is because in the table/form the 'available' ID's will start around:
shr_SUBJECT=VC03 or sh_SUBJECT=VC04
and it may then skip to:
shr_SUBJECT=VC06 then skip to shr_SUBJECT=VC09 and so on...
So if the for loop hits an ID that isn't available such as 05 or 07, it returns a null error :(
I did some reading and learned that javascript is able to 'catch' errors that are 'thrown' at it? My question now is that I'm wondering if there is an easy way to simply iterate to the next ID in line if this error is thrown.
Again, any and all help is appreciated, you guys are awesome.
OLD DRAFT OF SCRIPT
var getInputs = document.getElementsByTagName("input");
for (var i = 3, max = getInputs.length; i < max; i++){
if (getInputs[i].type === 'checkbox' && i < 10){
var count = i;
var endid = count.toString();
var begid = "shr_SUBJECT=VC0";
var fullid = begid.concat(endid);
document.getElementById(fullid).click();
}
else if(getInputs[i].type === 'checkbox' && i >= 10){
var count = i ;
var endid = count.toString();
var begid = "shr_SUBJECT=VC";
var fullid = begid.concat(endid);
document.getElementById(fullid).click();
}
}
--------EDIT#2----------
An example of a table that I am trying to manipulate can be found at this URL:
http://factfinder2.census.gov/faces/tableservices/jsf/pages/productview.xhtml?pid=ACS_12_5YR_DP02&prodType=table#
If you click on the 'Modify Table' button, you are able to select/deselect specific variables via the checkboxes. If you right-click on a couple of 'active' checkboxes and inspect the elements, and it looks something like this:
<input id="shr_SUBJECT=VC03" checked="" alt="hide SUBJECT=VC03" name="" value="" onclick="javascript:hiderow('SUBJECT=VC03');" type="checkbox">
<input id="shr_SUBJECT=VC25" checked="" alt="hide SUBJECT=VC25" name="" value="" onclick="javascript:hiderow('SUBJECT=VC25');" type="checkbox">
Thank you so much #Jonathan Steinbeck for the tip about the ternary operator, it really cleaned up my code.
The script works properly, but the problem I am running into now is that it doesn't iterate enough times after the try, catch statement. If there is a gap in the id #'s; say it jumps from shr_SUBJECT=VC19 to shr_SUBJECT=VC=24 the script will stop running. Is there a way to make it keep retrying the try/catch until it gets a valid ID # or one that exists/is an active checkbox?
CURRENT DRAFT OF SCRIPT :
var getInputs = document.getElementsByTagName("input");
for (var i = 3, max = getInputs.length; i < max; i += 1) {
try {
if (getInputs[i].type === 'checkbox'){
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
}
}
catch (err) {
i+=1;
if (getInputs[i].type === 'checkbox'){
if (getInputs[i].type === 'checkbox'){
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
}
}
}
}
When you call document.getElementById() with a non-existing ID, null is returned. Therefore this error means that you're trying to call the .click() method on null, which can't work.
So you should check what the correct ID naming scheme for the elements you want is. Maybe the elements' count starts with 1 instead of 0?
Also, the .click() doesn't work for all elements like you would expect as far as I know. So depending on the kind of element you are trying to retrieve you might have to create and dispatch your own event as suggested by RobG's comment.
EDIT in response to your recent edit:
You can wrap code that throws errors in a try-catch like this:
for (var i = 3, max = getInputs.length; i < max; i += 1) {
try {
document.getElementById("the_ID").click();
}
catch (error) {
console.error(error);
// continue stops the current execution of the loop body and continues
// with the next iteration step
continue;
}
// any code here will only be executed if there's not been an error thrown
// in the try block because of the continue in the catch block
}
Also, what are you doing with the 'i' variable? It doesn't make sense to assign it to so many variables. This does the same:
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
The ... ? ... : ... is an operator (called the 'ternary operator') that works like this: evaluate the expression before the "?" - if it results in a truthy value, the expression between "?" and ":" is evaluated and becomes the result of using the operator; if the condition results to false, the part after the ":" is evaluated as the value of the operator instead. So while "if" is a statement in JavaScript (and statements usually don't result in a value), the ternary operator can be used as an expression because it results in a value.
By concatenating a string with something else, you are forcing the 'something else' to be converted to string. So an expression like this will usually result in a string:
"" + someNonStringVar
Also, it doesn't make sense to define variables in a loop body in JavaScript. JavaScript variables have function scope, not block scope. What this means is that any variables defined in the loop body exist inside the whole function as well. Therefore it is recommended to write all of the "var"s at the top of your function to make it clear what their scope is. This behaviour of JavaScript is called 'hoisting', by the way.
I've furthermore taken a look at the URL you've given in your recent edit but I fail to find the kind of naming scheme for IDs you describe. In which table did you find those?
Edit in response to your second edit:
You shouldn't mess with the 'i' variable inside the body of a for loop. It makes your code much harder to reason about and is probably not what you want to do anyway. You don't need to handle the next step of the iteration in the catch block. The 'i' variable is incremented even if there's an error during fetching the element from the DOM. That's why you use catch in the first place.
The code below, produces the same annoying error. It will return the button element in the first pass of the loop but it only returns null thereafter. Any ideas?
<script>
function Check_Submission()
{var Entry = [];
for(var i = 0; i < 14; i++)
{
for(var j = 0; j < 10; j++)
{
Entry[i] = document.getElementById('Add');
document.write(Entry + '<br>');
}
}
}
</script>
<button id = 'Add' onclick = "Check_Submission()" >Click me.</button>
You can not use document.write after the page load. When you do that it wipes away the page content.
First loop it finds the element
You write to the page, it removes the button
other iterations can not find it since it was removed.
You need to use DOM methods to add new content or use the console for debugging.
When you do document.write() to an already loaded document, it clears the current document and starts writing a new empty document.
So, as soon as you call the first document.write() in your loop, it clears the current document and then document.getElementById('Add') will no longer find the former content.
Probably what you should do is to use DOM insertion methods such as .appendChild() or .insertBefore() to add new content to an existing loaded page.
It seems to me like the first time you run your for loop, you use document.write. That will clear everything, so the document.getElementById('Add') will return nothing. what you really want to do is something like 'appendChild' or modifying the innerHTML of the element.
document.write will clear everything each time it is executed.
Try writing,
document.getElementById('divid').innerHTML+=Entry+'<br>';
<div id='divid'></div>
I want to get all the <a> tags from an Html page with this JavaScript method:
function() {
var links = document.getElementsByTagName('a');
var i=0;
for (var link in links){i++;}
return i;
}
And i noticed it's won't return the correct number of a tags.
Any idea what can by the problem?
Any idea if there is any other way to get all the href in an Html ?
Edit
I tried this method on this html : http://mp3skull.com/mp3/nirvana.html .
And i get this result:"1". but there are more results in the page.
You don't need a loop here. You can read length property.
function getACount() {
return document.getElementsByTagName('a').length;
}
You don't have to loop over all of them just to count them. HTMLCollections (the type of Object that is returned by getElementsByTagName has a .length property:
$countAnchors = function () {
return document.getElementsByTagName('a').length;
}
Using getElementsByTagName("a") will return all anchor tags, not only the anchor tags that are links. An anchor tags needs a value for the href property to be a link.
You might be better off with the links property, that returns the links in the page:
var linkCount = document.links.length;
Note that this also includes area tags that has a href attribute, but I assume that you don't have any of those.
UPDATE Also gets href
You could do this
var linkCount = document.body.querySelectorAll('a').length,
hrefs= document.body.querySelectorAll('a[href]');
EDIT See the comment below, thanks to ttepasse
I would cast them to an array which you then slice up, etc.
var array = [];
var links = document.getElementsByTagName("a");
for(var i=0; i<links.length; i++) {
array.push(links[i].href);
}
var hrefs = array.length;
The JavaScript code in the question works as such or, rather, could be used to create a working solution (it’s now just an anonymous function declaration). It could be replaced by simpler code that just uses document.getElementsByTagName('a').length as others have remarked.
The problem however is how you use it: where it is placed, and when it is executed. If you run the code at a point where only one a element has been parsed, the result is 1. It needs to be executed when all a elements have been parsed. A simple way to ensure this is to put the code at the end of the document body. I tested by taking a local copy of the page mentioned and added the following right before the other script elements at the end of document body:
<script>
var f = function() {
var links = document.getElementsByTagName('a');
var i=0;
for (var link in links){i++;}
return i;
};
alert('a elements: ' + f());
</script>
The results are not consistent, even on repeated load of the page on the same browser, but this is probably caused by some dynamics on the page, making the number of a elements actually vary.
What you forget here was the length property. I think that code would be:
var count = 0;
for (var i = 0; i < links.length; i++) {
count++;
}
return count;
Or it would be:
for each (var link in links) {
i++;
}
length is used to determine or count the total number of the element which are the result.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for (For Loop)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for_each...in (Foreach Loop)
For this code:
var i = 0;
for (i < menuitem.length; i += 1;)
JSlint returns:
Expected a conditional expression and instead saw an assignment.
Expected an identifier and instead saw ')'.
And refuses to continues scanning.
This code works fine but what is wrong? How could I write this with an "if" statement? (if that is what jslint means).
Thanks for your help guys!
Yeah, JSLint is pretty vicious. As others have pointed out, you're not filling things in in the right places, but aside from that, JSLint requires that you put something in the initialization part of the for loop. There are a couple options you can do to make it play nice without messing with your logic, though. My favorite is to just reset i (even though it's already set):
var i = 0;
for (i = 0; i < menuitem.length; i += 1) {
/** do stuff **/
}
This make JSLint happy and also ensures that i gets reset if you decide to use it for another for loop in the same lexical scope. Another option is to just toss a null in there to fill the space (if you don't want to reset the value of i):
var i = 0;
for (null; i < menuitem.length; i += 1) {
/** do stuff **/
}
Both work fine and appease the ever-so-worrisome JSLint. However, no one will really care if you just leave the initialization part blank (aside from JSLint). You might try JSHint, as it's a bit more forgiving on this sort of thing.
Your for loop is kind of weird, the second part should be a condition for the loop, instead you have an assignment.
You must always have the parts in order (initialisation; condition; step).
var i = 0;
for (; i < menuitem.length; i += 1)
I just moved your semicolon from the end to the start. Alternatively, you can place the variable declaration and assignment inside the first part if you like.
for (var i = 0; i < menuitem.length; i += 1) {
// code
}
Or
var i = 0;
for (; i < menuitem.length; i += 1) {
// code
}
Found it! Here is the precise answer for validation:
var i;
for (i = 0; i < menuitem.length; i += 1) {
// code
}
var should be outside says jslint :s
From your code snippet, I'm going to assume that i is simply a variable used to control the number of cycles of your loop. The correct code would be
for (var i = 0; i < menuitem.length; i += 1) {
// code
}
That is the standardized declaration and syntax - at least for the languages I can think of right now. And that is really the point of this type of loop - for loops were designed this way so the author can simply write one line of code versus more if he/she wanted to do a while loop.
Well im new to javascript but why does this not work, all i want to do is to get a list of all selects on the page.
var elements = document.getElementsByTagName("select");
alert("there are " + elements.length + " select's");
for (i = 0; i < elements.length; i++)
{
alert(elements[i].getAttribute('Id'));
}
Edit: the error is that it does not find any selects at all, elements.length is allways zero!
You'r saying that elements.length is always returning 0 for you, this could be because:
You are running the JS code in the beginning of your page, thus the DOM is not fully available yet
Try using .id instead of of getAttribute('Id').
I guess the part of getting id attribute doesn't work for you. Probably it's because you typed there "Id" instead of "id".
The usual cause for getElementsByTagName returning zero results in a document with matching elements is that it is being run before the elements appear in the document (usually in the section and not inside a function that is called onload or onDomReady).
Move the element to just before the (END of body!) tag, or use an event handler that fires after the HTML has all been processed.
Well, as far as I can see is that perhaps the selects on your page don't have Id's (the alerts in the loop show null)