New to javascript and having an issue with arrays

Recently, I’ve started working with javascript since my group has decided we are going to web enable a bunch of our apps. To cut my teeth, I’ve been working on a simple application that will allow our users to submit their vacation requests via the web so that they can be e-mailed to our payroll admin. However, in order to create a dynamic field that will generate the appropriate amount of days, i wrote a javascript (based loosely on tips from Scott Good in his July 2003 Lotus Advisor article) to do this. unfortunately, it doesn’t work.

i believe my issues are due to the fact that i am not quote certain how to handle arrays in javascript. basically, i’ve tried to break up the code into two pieces–one piece that when given the month value determines how many days that month has and sets the field accordingly. the second bit of code actually generates the number list accordingly. It is called by the first bit of code once the first bit determines how long the month actually is.

here’s the code as contained in my JSHeader:

var doc = document.forms[0]; //set doc variable equal to current form

var today = new Date(); //get today’s date

function genList (num){

//this function generates a list based on the number passed to it

alert ("genList routine has begun");

var numlist = new Array(); //number list array container

for (i = 0; i<num; i++){ //loop through the numbers

	numlist[i] = i++; //set current array position equal to position + 1

}

return numlist;

alert ("genList has concluded");

}

function setDayChoices (month) {

//this function will create a list of date choices based on month and year selection

alert ("The month value is " + month); 

alert ("setDayChoicesFunction has begun");

var daylist = new Array (); //set daylist container for month choices

var year = doc.StDateYr.options.selectedIndex; //find out the current year selected

var leap = doc.StDateYr.options[year].value; //find the year value

switch (month){

	case "1"||"3"||"5"||"7"||"8"||"10"||"12": //if a 31 day month

		daylist = genList(31); //call genList function, set it equal to daylist array

		break;

	case "4"||"6"||"9"||"11": //if 30 day month

		daylist = genList(30); //call genList function

		break;

	case "2" && ((leap%4!=0) || ((leap%100==0) && (leap%400!=0))): //if a non leap year feb

		daylist = genList(28); //call genList function

		break;

	case "2" && ((leap%4)==0) : //if a leap year feb

		daylist = genList(29); //call genList function

		break;

	default: //default to 31 days

		daylist = genList(31);

		break;	

}

switch (this.Name){ //dependent on start date or end date, set the appropriate field with day listing

	case "StDateMo":

		for (i = 0;i<daylist.length;i++){

			doc.StDateDay.options[i] = daylist[i];

		}

		break;

	case "EndDateMo":

		for (i = 0;i<daylist.length;i++){

			doc.EndDateDay.options[i] = daylist[i];

		}

		break;

}		

alert ("setDayChoices has ended");

}

I call setDayChoices in one of two places–first, in the onLoad event of the form and secondly in the onChange event of the field that contains the month (“StDateMo”) I know for a fact that it at least calls setDayChoices in both events, because i received the alert–however, the genList function has never executed.

can someone show me where I am going wrong here? I’m almost certain it is due to some fundamental misunderstanding i have of the language, but i am too ignorant to see it myself.

thanks.

brandt

Subject: Update, with more info: New to javascript and having an issue with arrays.

I added an alert to my switch statement, but before the genList function is called in any of my case statements. This tells me that the case statements aren’t evaluating correctly. is there another method for allowing multiple options to resolve to the same case expression?

brandt

Subject: RE: Update, with more info: New to javascript and having an issue with arrays.

Actually, Brandt, I’d probably set a Date object to the first of the next month, then slide it back a day to get the last-of-the-month value.


EDITED CODE (Thanks, Bill!


var firstOfNextMonth = new Date();

firstOfNextMonth.setDate(1);

var year = parseInt();

/*

** JavaScript months are zero-indexed, so we

** can use the current month value as “next”

** unless it’s 12

*/

if (month == 12) {

++year;

month = 0;

}

firstOfNextMonth.setYear(year);

firstOfNextMonth.setMonth(month);

//get total time elapsed from base date

var millis = firstOfNextMonth.getMilliseconds();

//subtract one day

var lastOfThisMonth = new Date();

var millisecondsPerDay = 1000 * 60 * 60 * 24;

lastOfThisMonth.setMilliseconds(millis - millisecondsPerDay);

varNumberOfDays = lastOfThisMonth.getDate()

That creates one more Date object than necessary, but the names work out better for clarity’s sake. From there, you can call your genList().

Subject: I think you might have a couple of errors here…

var firstOfNextMonth = new Date();firstOfNextMonth.setDate(1);

//var year = parseInt(); Should be

var month = firstOfNextMonth.getMonth() + 1;

/*

** JavaScript months are zero-indexed, so we

** can use the current month value as “next”

** unless it’s 12

*/

if (month == 12) {

++year;

month = 0;

}

firstOfNextMonth.setYear(year);

firstOfNextMonth.setMonth(month);

//get total time elapsed from base date

var millis = firstOfNextMonth.getMilliseconds();

//subtract one day

var lastOfThisMonth = new Date();

//lastOfThisMonth.setMilliseconds(millis - 18400000); sb 86400000 Ms

lastOfThisMonth.setMilliseconds(millis - (60 * 60 * 24 * 1000));

varNumberOfDays = lastOfThisMonth.getDate()

Subject: RE: I think you might have a couple of errors here…

Ask me where the 18400000 comes from, and I won’t be able to answer you. Gaseous cerebral emission caused by typing while chewing gum would be my best guess. Good catch, though – but even in your corrected version, 60, 60, 24, and 1000 are still “magic numbers” appearing where they do. The “right” way would have been:

.

.

.

var millisecondsPerDay = 1000 * 60 * 60 * 24;

var lastOfThisMonth = new Date();

lastOfThisMonth.setMilliseconds(millis - millisecondsPerDay);

.

.

.

It’s extra typing and extra variables, but the “right” way is always easier to troubleshoot and maintain. (I will read Code Complete again. And again. And again, until I actually start to practice good coding.)

No it should NOT be firstOfNextMonth.getMonth() + 1 – “month” is a value fed into the function as a param in Brandt’s original code (and this is a mere snippet, not an all-of-a-piece prêt-a-porter function). It comes from a

Subject: Got me. Did not go back and re-read his code. You confused me with the Year piece though.

Subject: sorry to be a complete dunce Stan…

but i’m not exactly certain how this code you’ve given me works.

in my original code that i posted, my intention was to grab whatever value had been chosen in a field called StDateMo (which does not have a zero element of “Select Month”–i had put an onLoad event in that would just assume that the month the user wanted to choose would be January–i’m sure that once I had more of a handle on Javascript, I was going to write something that would assume that the user was going to be assigned the current month instead) and then calculate the day choices accordingly. now I am a bit confused as to why my switch…case statements aren’t executing (because i don’t see any reason why they shouldn’t) and since i am a relative novice, i am a bit confused by your code sample, which comes in from an opposite direction from where I am coming from.

am i right in assuming that in this line:

firstOfNextMonth.setMonth(month)

that i am passing the month variable that i was passing in the getDayChoices function in my original code? also, this doesn’t really address the issue of my switch…case statements not executing.

anyway, sorry to be so daft, but i’m picking this up as i go, and history tells me that when i try to teach myself something i almost always bite off more than i can chew…

brandt

Subject: RE: sorry to be a complete dunce Stan…

Let’s start with the switch(). I have never run across multiple values in a case expresssion, and have never tried it in anger myself until you raised the point. The ECMA 262 language spec is not entirely clear on the matter (it’s not forbidden, but it isn’t explicitly allowed either), but I suspect that you’d need individual case statements for all non-default values.

As for my offering…

Yes, the “month” variable should be the same as the one you were passing in your original code.

My code comes from the making the assumption that the only really reliable method for working with dates is to actually use dates. The concept is the same as using:

@Day(@Adjust(@Adjust(firstOfThisMonth;0;1;0;0;0;0);0;0;-1;0;0;0))

By using the date-time methods to create a date at the first of the “current” month, then move it ahead a full month, then back a single day, we can be absolutely certain that the day resulting will be the last day of the “current” month, regardless of leap-year exceptions and so forth, without having to know the “meaning” of the current month value. The native code has all of the exceptions built in – why not use it?

Sorry if I misread your intention – the month value would be a perfect natural fit for a “blank” choice followed by the twelve month-names in order. That’s really not an issue, though, if you already have a means of obtaining the number (one-indexed) of the month. Your case expressions indicate that you do (but you’d probably have to parseInt() the values to make sure they’re integers rather than strings).

No need to apologize about having difficulty with a new-to-you language. I’m feeling a right idiot in VB.NET and C# right now – both of them are close to, but almost exactly unlike, languages that I am familiar with already. It’s kinda like trying to speak Portugese based on one’s knowledge of French and Italian.

Subject: RE: sorry to be a complete dunce Stan…

Stan,

well explained, and i think i will transplant your code into my existing function tomorrow.

now, if you’re just about to post an answer to my question about selectedIndex, i’ll be in hog heaven.

do you know where i can find that ECMA 262 language spec? is it on the Netscape site?

brandt

Subject: RE: sorry to be a complete dunce Stan…

It should be available from http://www.ecma-international.org/publications/standards/ECMA-262.htm

Subject: RE: sorry to be a complete dunce Stan…

Try http://www.mozilla.org/js/language/E262-2.pdf instead. It looks like a domain name scuffle between the European Computer Manufacturers Association and the European Carton Manufacturers Association (really!) has wiped the “real” ECMA from the face of the web for now.

Subject: even more info about my busted script (was sorry to be a complete dunce Stan…)

upon adding more alerts to the code I found out this is the offending line:

var year = doc.StDateYr.options.selectedIndex;

it just occured to me…when the user executes this script, they are going to be in the StDateMo field, not StDateYr…am i right in thinking that a field can only have a selectedIndex value if the user is IN the field? if so, how can i tell it that i want the value currently displayed in the UI for that field? or is that where your script comes in Stan?

brandt

Subject: No, once the user picks something, the field will retain its selectedIndex.

Subject: RE: even more info about my busted script (was sorry to be a complete dunce Stan…)

No, Brandt – focus should only affect what can be called by using “this”, unless your code or variables have gone out-of-scope. Since the function is global, and the variable “doc” is declared and instantiated within the function, it should not matter where the function call comes from. “document” is a top-level object that can be accessed directly from any other object without having to follow the “parent” trail.

*****D’OH!!! ******

Kill the “options”,

document.form[index].FieldName.selectedIndex

NOT

document.form[index].FieldName.options.selectedIndex

(Looking for mustard seeds – could not see the elephant!)

Subject: Well, you have a problem w/ your GenList function…

You are doing a double i++

function genList (num){

//this function generates a list based on the number passed to it

alert ("genList routine has begun");

var numlist = new Array(); //number list array container

for (i = 0; i<num; i++){ //loop through the numbers

	numlist[i] = i++; //set current array position equal to position + 1

}

return numlist;

alert ("genList has concluded");

}

Instead try…

for (i = 0; i<num; i++){ //loop through the numbers

	numlist[i] = i + 1; //set current array position equal to position + 1

}

Subject: RE: Well, you have a problem w/ your GenList function…

Just to put things straight, a bit of explanation.

“k = i + 1;” and “k = i++;” do things rather differently. If i = 3, then

k = i + 1;

assigns a value of 4 to k, while leaving i’s value at 3. On the other hand,

k = i++;

assigns a value of 3 to k (the current value of i), then increments i to a value of 4.

“i++” on a line by itself means “increment i”, but when used in concert with other code, it means “return the current value, then increment i”. That’s called “post incrementing”. A similar construct, “pre incrementing” would be formulated as “++i”. In this case, it says “increment the current value of i, then return the new value”.

Both pre and post incrementing directly affect the value of the variable.

Subject: RE: Well, you have a problem w/ your GenList function…

Bill,

thanks for pointing that out. It makes perfect sense.

Unfortunately, the genList function still isn’t working, but we’ll take baby steps i guess…

thanks again.

brandt