Using Variables In Javascript For Loop - javascript

I have a checkbox contained within a form on my page. When the user clicks a button I need to find out which items in the checkbox have been selected.
I can get this to work with the following code without ay problems.
for (i=0; i < Form3.CBox1.length; i++)
if (Form3.CBox1[i].checked)
{
Answer = Answer + Form3.CBox1[i].value + ",";
}
alert(Answer);
The problem I have is that I call the above function several times on my page and I want to pass in variables instead of hard coding the name of the form and checkbox. Everytime I do this Javascript will not return anything. The variables vCurrForm & vCurrCBox, in the following code, have been set earlier in another function and I have tested to ensure that they are set correctly but I still can't get this piece of code to work.
for (i=0; i < vCurrForm.vCurrCBox.length; i++)
if (vCurrForm.vCurrCBox[i].checked)
{
Answer = Answer + vCurrForm.vCurrCBox[i].value + ",";
}
alert(Answer);
Any help would be greatly appreciated. Thanks

When working with variables as the keys to an object, you need to use the array syntax (ie. []s), which on its own would give us this (still broken) code:
for (i=0; i < vCurrForm[vCurrCBox].length; i++)
{
if (vCurrForm[vCurrCBox][i].checked)
{
Answer = Answer + vCurrForm[vCurrCBox][i].value + ",";
}
}
alert(Answer);
The problem is that vCurrForm is still being treated as a regular old variable, even though it's the string name of that variable. Because of this, you need to reference it from its parent; window:
for (i=0; i < window[vCurrForm][vCurrCBox].length; i++)
{
if (window[vCurrForm][vCurrCBox][i].checked)
{
Answer = Answer + window[vCurrForm][vCurrCBox][i].value + ",";
}
}
alert(Answer);

Without seeing how you are declaring and setting these values it is very difficult to ascertain the problem. It could be related to the type of object the variables are being set to, or their scope. Here are some things to check:
Ensure the variable vCurrForm.vCurrCBox is an array.
Ensure that vCurrForm and vCurrCBox are declared in a scope that is accessible to the function being called.
In this case make sure you are setting vCurrForm to a Form Object and vCurrCBox to an array of checkbox controls.
Looking at the code provided almost makes me think that the variable being referenced is for a single item (Current Checkbox). Your probably not going to get the results you are looking for in that case.
Something else to consider if it is possible would be to use JQuery to more easily grab the checked boxes and concatenate their values. In JQuery your code could be done with something like:
var Answers = "";
$("input[type='checkbox']:checked").each(function() { Answers += $(this).val() + ", "; });

Or, a better solution is to pass reference to the array that contains elements, instead of matching it with strings. For example:
function getAnswers(items) {
for (var i = 0; i < items.length; i++)
{
if (items[i].checked) {
Answer = Answer + items[i].value + ",";
}
}
}

Thank you ever so much for all you help. I've seen the error of my ways.
The following worked for me
**for (i=0; i < document[vCurrForm][vCurrCBox].length; i++)
if (document[vCurrForm][vCurrCBox][i].checked)
{
Answer = Answer + document[vCurrForm][vCurrCBox][i].value + ",";
}**

Related

How to change variable values in an array of variables in JS

Not sure if this is possible to even do so I'll give it a quick shot and see if anyone has any solutions, ahem.
Is there any way I could store these variables into an array, and change them through the array as such;
function themepreviewchange() {pretaskbartxt=curcolsch[0];pretaskbartxtprs=curcolsch[1];preactivetitle=curcolsch[2];preinactivetitle=curcolsch[3];pretbgradinactive1=curcolsch[4];
pretbgradinactive2=curcolsch[5];pretbgradactive1=curcolsch[6];pretbgradactive2=curcolsch[7];cpwhite=curcolsch[8];cplightg=curcolsch[9];cpsilver=curcolsch[10];cpmidgray=curcolsch[11];
cpgray=curcolsch[12];cpblack=curcolsch[13];cpblue=curcolsch[14];cpprussian=curcolsch[15];cpwincyan=curcolsch[16];cpyellow=curcolsch[17];cpfont=curcolsch[18];cphover=curcolsch[19];
cpatext=curcolsch[20];preinvert=curcolsch[21];shuffleflop=curcolsch[22];discheckinv=curcolsch[23];enacheckinv=curcolsch[24];invcheckinv=curcolsch[25];prespritesheet=github+curcolsch[26];
cwpp=curcolsch[27]}
var settings = pretaskbartxt,pretaskbartxtprs,preactivetitle,preinactivetitle,pretbgradinactive1,pretbgradinactive2,pretbgradactive1,pretbgradactive2,cpwhite,cplightg,cpsilver,cpmidgray,
cpgray,cpblack,cpblue,cpprussian,cpwincyan,cpyellow,cpfont,cphover,cpatext,preinvert,shuffleflop,discheckinv,enacheckinv,invcheckinv,prespritesheet,cwpp,currentcolour
And just do a for loop?
for(var i=0; i<curcolsch.length; i++){settings[i]=curcolsch[i]}
The current result just ends up changing the value of that number in the array, and just changes it to the same thing as the current position in the curcolsch array. So my question is; how would I go about using a quicker route than just spamming the same set of variables with one step up in the array like I addressed above?
Just to be clear I'm not completely insane with the variable count problem, the whole reason i'm asking is so I can get rid of them.
Hoping this isn't your homework assignment....
let settings = {
pretaskbartxt: curcolsch[0],
pretaskbartxtprs: curcolsch[1],
...
cwpp: curcolsch[27],
};
for (const aThing in settings) {
console.log(`value of ${aThing} is ${settings[aThing]}`);
}
Should give you the basic idea....
I was hoping for a quick straight forward answer without the need to rewrite half my code, so I've just ended up removing all my variables in a replacement for a single array so I can switch easier and it's more compact + better than any other solution.
var preactive = [undefined,undefined,'--preactivetitle','--preinactivetitle',undefined,undefined,
undefined,undefined,'--prewhite','--prelightg','--presilver','--premidgray','--preblack',
'--preblue','--preprussian',undefined,'--preyellow','--prefont','--prehover',undefined,
'--preinvert']
function themepreviewchange() { precolsch = undefined; precolsch = schemes[themecurrent]
for(var i = 0; i<preactive.length; i++){docelem.style.setProperty(preactive[i], precolsch[i])}
gradient = "linear-gradient(90deg, " + precolsch[4] + "," + precolsch[5] + ")";

set attributes of elements stored in variables

Is there anyway to use jQuery to dynamically set the attributes of HTML elements that are stored in variables?
For example, at one point in my application, a user creates a varying number of select input fields. For eventual processing by PHP, the elements need to be named in the format name='input'+siteNumber+'['+x+']', where x is the number of elements created in a for loop.
Here's a rough sketch of what I'm thinking needs to be done - THIS IS NOT FUNCTIONAL CODE, IT IS ONLY AN ILLUSTRATION.
$(".number_select").change(function(){
numberFound = $(this).val();
siteNumber = $(this).parent().attr('data-site_number');
//HERE'S THE INPUT TO BE NAMED
selectInput = "<select></select>";
this['inputArray' + siteNumber] = [];
for(x = 1; x <= numberFound; x++){
//THIS IS WHAT I'D LIKE TO ACCOMPLISH - SETTING THE ATTRIBUTE - THOUGH THIS UNDERSTANDABLY DOES NOT WORK IN THIS PARTICULAR FORMAT
this['inputArray' + siteNumber].push(selectInput.attr("name", "species"+siteNumber+"["+x+"]"));
};
$(this).parent().append(this['inputArray' + siteNumber]);
};
Thank you.
Thanks everyone - I actually ended up deciding to handle this a little differently, but it works perfectly - rather than storing the elements in variables, I used a function instead...
function inputs(siteNumber, x){
return ("<select name='selectInput"+siteNumber+"["+x+"]'>"+list+"</select>");
};
$(".number_select").change(function(){
numberFound = $(this).val();
siteNumber = $(this).parent().attr('data-site_number');
this['inputArray' + siteNumber] = [];
for(x = 1; x <= numberFound; x++){
this['inputArray' + siteNumber].push(inputs(siteNumber, x));
};
$(this).parent().append(this['inputArray' + siteNumber]);
};
Don't know why I didn't think of this in the first place, it seems obvious to me now. Oh well, live and learn.
To vaguely answer your question, you can dynamically generate an element and use jQuery's attr for adjusting the name attribute pretty easily like so.
var select = $('<select>').attr('name', 'add-name-here');
$('<option>').attr('value', 'some-value').text('Option').appendTo(select);
$('#wrapper').html(select);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper"></div>
Which outputs
<select name="add-name-here">
<option value="some-value">Option</option>
</select>
In your case, instead of adding it to #wrapper you would build up the select box as you need and append it to whichever select box has the change? Not sure your specific use case. Hope it helps.

Unchecking and simulating a click on checkboxes in Javascript

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.

Jslint error: Expected a conditional expression and instead saw an assignment

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.

HTML Passing Link information through to javascript method

I am setting up some basic pagination of a table, and I have the following JS function:
function AddPagination() {
var paginationDiv = document.getElementById("pagination");
for (i = 0; i < 3; ++i) {
var page = document.createElement("a");
page.innerHTML = i + 1;
page.setAttribute("title", i + 1);
page.setAttribute("href", "javascript:RenderResultTable(this.innerHTML)");
paginationDiv.appendChild(page);
}
}
What I want to do is pass page number clicked on to the RenderResultTable method. I have this number stored as the innerHTML and title for the link element, how can I get this passed through using the above code?
Thanks.
Personally, I wouldn't use JavaScript for pagination but if that's the way you want to go, you need to use some string concatenation. I'm not sure what RenderResultTable() does but you can set that line up like this:
page.setAttribute("href", "javascript:RenderResultTable('" + page.innerHTML + "')");
I believe that should do the trick.
EDIT: Shouldn't you be using i++ in your loop instead of ++i? I think what you have right now will give 2 as the first page number. Please correct me if I am wrong.
EDIT: page.innerHTML will need to be escaped by this functions and then unescaped the in the RenderResultTable() function. escape() and unescape(). This is to prevent JavaScript injections and/or accidental bugs.

Categories