View Full Version : JS won't run because # of inputs vary

Local Hero
10-22-2005, 11:00 PM
My function takes user inputs about text/placement on t-shirts and puts it all together into a textarea. Then it clears the inputs. If the user wants to specify a second text/placement then it will add to the first. It's pretty straight foreword.

function textlayout(){
var textarea1 = document.getElementById('textarea1');
for(var i=0;i<document.forms.layout1.textalign1.length;i++) {
if(document.forms.layout1.textalign1[i].checked) {
var tbase = document.forms.layout1;
var text1 = tbase.texttext1.value;
var align1 = document.forms.layout1.textalign1[i].value;
var font1 = tbase.textfont1.value;
var color1 = tbase.textcolor1.value;
var size1 = tbase.textsize1.value;
var pos1 = tbase.textpos1.value;
var lay1 = "TEXT-("+text1+") ALIGN-("+align1+") FONT-("+font1+") COLOR-("+color1+") SIZE-("+size1+" inches) POSITION-("+pos1+")";
textarea1.value= textarea1.value + lay1;

This works fine. The problem is this. On my page a user can specify as many products as they need. You'll notice that the function calls inputs that end with a "1". It is the first product. Every input in the second product ends in "2" and so on... I could keep repeating this function over and over by changing the last number, but that would be tedious and take up too much room. Is there a way to modify my function to accept any number? If it helps, I can make a hidden field that will tell the function how many products there are, or which # is to be modified.

If anyone has any ideas on this, I would really appreciate it!

Local Hero
10-23-2005, 12:58 AM
I have an idea that gets me closer, but I still can't finish it. My idea is this: I can make each button that calls the function unique. Would it be possible to have something like this?

function textlayout(num){
var num = the number on the "onclick";
var tbase = document.forms.layout[num];
var text[num] = tbase.texttext[num].value;

<input="button" onclick="textlayout(3);">

I don't understand JS too well, but I thought I had seen a way to set a var based on what was selected. In this case I want it to recognize that if the third onclick is selected, then all the input names end in that number. Is anything like that possible?

10-24-2005, 03:39 AM
if you post, or provide a link to, your full page it would be a lot easier to help.

10-25-2005, 03:00 PM
After reading the first post, I was just going to suggest you try using an array instead of variables, but then you provided that answer yourself in post #2!

I have an idea that gets me closer, but I still can't finish it. My idea is this: I can make each button that calls the function unique. Would it be possible to have something like this?

function textlayout(num){
var num = the number on the "onclick";
var tbase = document.forms.layout[num];
var text[num] = tbase.texttext[num].value;

<input="button" onclick="textlayout(3);">

A few ideas to help you further... Firstly, make a set of global arrays: inside the <head>, make a javascript and put in "var text=new Array();" etc. for each T-shirt attribute you'd like to store. And also, depending upon how you'd like to have the script "remember" the next available key for each array, you may need to add a global counter variable (eg "var counter=0"), although a simpler, more "dangerous" method may also be used... see below.

Then in your function, you'd have:

function textlayout() // You won't need num argument; see below
// For any function, don't declare a variable if it is already being
// passed in to the function as an argument!
// var num = the number on the "onclick"; <-- can delete!

// Style 1: Using the global counter variable as set-up before
var tbase = document.forms.layout[counter];
// Using style 1 would then require you to increment the global variable
// to get the counter ready with the next available key...

// Style 2: Using the .length property of each array as the next key.
// Arrays start at 0 and are numbered to (.length-1).
// So if text.length = 5, that means there are 5 items in the text array:
// text[0], text[1], text[2], text[3], and text[4]...
// So typing 'text[text.length]=something',
// gets translated into 'text[5]=something', in the above array
text[text.length] = tbase.texttext[textext.length].value;
// By using the .length property, you don't need to increment any counter.
// This is because the very act of adding a new member to the array
// automatically increases the length of the array by one! Easy!
// alert(text[text.length]); // however, will cause an error.
// That's because if text[text.length] was translated to text[5] _before_
// the assingment, in this 'alert' line, text[text.length] will now translate to
// text[6], which is undefined! Dangeous!

// Also, as long as you are sure that all arrays will be built equally
// throughout your site, then the .length property should be the same
// for each. However a way to ensure better uniformity as well as to
// avoid using array.length twice and getting an error, is
// Style 3: To use a local variable = .length:
var localTempKey = text.length;
alert(text[localTempKey]); // Works fine now!
// Can also use this value for other T-shirt attributes:

A few last thoughts...
If you do go with using the arrays, you probably will only need one form. Just have a 'Process' button that onClick='textlayout()', which will call the function, add the values from the form into the arrays, and then clears the form (perhaps, 'tbase.reset();' as long as 'textarea1' is not a part of the rest of the form). This would allow you to have 'text[text.length]=tbase.texttext.value' in the function, instead...
If you understand arrays fairly well (or at least feel comfortable with what I explained above), you may want to also try using a multi-dimensional array where the first key is an associative string relating to one of the T-shirt attributes and the second key designates which line on the T-shirt the attribute relates to, such as:
After the above example, myTShirt.length would equal 2, which you would use for the second key when assigning a new line on the T-shirt! If set up properly, you could even have the associative keys equate to the fields in your form:

var inputTags=document.getElementsByTagName('input');
var nextKeyValue=myTShirt.length;
for(var counter=0; counter<inputTags.length; counter++)
// Assuming all <input> fields in form have value attributes for the T-shirt
// Any "type='hidden'" or other non-sense <inputs> would need to be removed
// Also, <input type='checkbox' or type='radio'> would need to be
// processed differently...

Finally, I'm not sure how picky js is with where variables are declared in blocks of text in relation to the variable's scope, but a strict interpretation of your line:
"for(var i=0;i<document.forms.layout1.textalign1.length;i++)"
and then using 'i' later in the code outside of the for-loop might cause a logical error.
In stricter programming languages, declaring 'i' in the for-loop's header (having 'for(var i=0...') states that 'i' is being defined as a variable inside the loop (having scope inside the for-loop's code-block); once the loop exits, any reference to 'i' no longer refers to the value it had inside the loop, and thus would either generate an error ('i' outside the loop is not defined) or would define 'i' with a defult value (eg i=0 outside the loop). Unless you know differently (eg have used this and not had any problems), I'd just declare 'i' outside the loop rather than inside, so your first code would change to:

var i;
for(i=0; ...)
{ /* Use i inside loop as normal */ ... }
// i retains value it had inside of the loop after it's exited outside
var align1 = document.forms.layout1.textalign1[i].value;