filling a form with dates...newbie needs a bit of help

W

WindAndWaves

Hi Gurus

Below you can find a function and the accompagnying html. I am keen to make
it work, but it seems to be riddled with errors. I basically can not get it
to work.

The idea is that the user completes the startdate field and that from there
on, the arrival dates and departure dates for the properties are calculated,
using the number of nights and the number of days (gap) between each
property. While the number of nights and the gap are entered as 1 and 0
respectively, the user should be able (once the function is working) to
change those values and the arrival and departure date should be
recalculated.

Any hints greatly appreciated (this is one of my first javascripts).

TIA

- Nicolaas


//this function fills a form (f), WHERE i is the section number (e.g. 0, 1,
2 or 3)
//each section of the form has the following fields:
//arrival: <INPUT CLASS="sg" ID="ai" NAME="ai">
//nights: <INPUT CLASS="xs" VALUE="1" ID="ni" NAME="ni">
//departure: <INPUT CLASS="sg" ID="di" NAME="di">
//gap between this and next stay: <INPUT CLASS="xs" VALUE="1" ID="gi"
NAME="gi">
//hidden actual arrival date: <INPUT TYPE="hidden" ID="hi" NAME="hi">


//fill form with data, f = Form, s = the number of sections (see above, e.g.
3)
function main(f, n) {
sd = new Date;
sd = f.startdate;
// need to put a check here to make sure we have a valid start date
return go(f, sd, n);
// for (i = 0; i < f.length; i++) {
// }
}

// set the elements in the form
function go(f, sd, n) {
for (i = 0; i < n; i++) { //start loop
if (i==0) { //first loop
writeD(false,f, 'h0', sd); //write hidden field (h0) with the date
} else { //other loops
writeD(false,f, 'h' + i, adf(getD(f, 'h' + (i-1)), getN(f, 'n' (i-1)) +
getN(f, 'g' (i-1)))); //set hidden field (previous hidden field + the number
of nights + the number of nights between (gap (g))
}
writeD(true, f, 'a' + i, getD(f, 'h' + i)); //write arrival date
writeD(true, f, 'd' + i, adf(getD(f, 'h' + i), getN(f, 'n' + i))); //write
departure date
return true;
}
}


//returns the number of seconds (number)
function pd(d) {
x = new Date(d);
return Date.parse(x); //parse provides the number of milli seconds since
1970
}

//add values to a date; sd = start date, ad = number of days to add
function adf(sd, ad){
var d = 0;
d = pd(sd) + (ad*86400000); //change number of days into number of
milliseconds
return new Date(d);
}

//write element with a date
function writeD(ft, f, el,d){
var bRef = null;
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}
if (ft == true) {
d = fmt(d);
}
bRef.value = d;
}

// get date from an element
function getD (f,el){
var bRef = null;
var nv = new Date(); //nv = new value
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}
nv = bRef.value;
return Date(nv); //change it into a date
}

// get number from an element
function getN (f,el){
var bRef = null;
var nv = null; //nv = new value
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}
nv = bRef.value;
return nv;
}



// format DD-MMM-YYYY
function fmt(d) {
d = Date(d);
return (d.getDate() < 10 ? "0" : "") + d.getDate() + "-" +
(["JAN","FEB","MAR","APR",
"MAY","JUN","JUL","AUG",
"SEP","OCT","NOV","DEC"])[d.getMonth()] + "-" +
d.getFullYear();
}

The relevant HMTL is:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>test me</TITLE>
</HEAD>
<BODY>
<FORM METHOD="POST" NAME="basket" ID="basket">
<INPUT TYPE="button" VALUE="calculate" ONCLICK="return main(this.form,
3);" ID="calculate" NAME="calculate">
<INPUT TYPE="reset" VALUE="reset" ID="Reset1" NAME="Reset1">

property1
arrival<INPUT CLASS="sg" ID="a0" NAME="a0">
nights<INPUT CLASS="xs" VALUE="1" ID="n0" NAME="n0">
departure<INPUT CLASS="sg" ID="d0" NAME="d0">
gap<INPUT CLASS="xs" VALUE="0" ID="g0" NAME="g0">
<BR><INPUT TYPE="hidden" ID="h0" NAME="h0">

property 2
arrival<INPUT CLASS="sg" ID="a1" NAME="a1">
nights<INPUT CLASS="xs" VALUE="1" ID="n1" NAME="n1">
departure<INPUT CLASS="sg" ID="d1" NAME="d1">
gap<INPUT CLASS="xs" VALUE="0" ID="g1" NAME="g1">
<BR><INPUT TYPE="hidden" ID="h1" NAME="h1">

property 3
arrival<INPUT CLASS="sg" ID="a2" NAME="a2">
nights<INPUT CLASS="xs" VALUE="1" ID="n2" NAME="n2">
departure<INPUT CLASS="sg" ID="d2" NAME="d2">
gap<INPUT CLASS="xs" VALUE="0" ID="g2" NAME="g2">
<BR><INPUT TYPE="hidden" ID="h2" NAME="h2">

property 4
arrival<INPUT CLASS="sg" ID="a3" NAME="a3">
nights<INPUT CLASS="xs" VALUE="1" ID="n3" NAME="n3">
departure<INPUT CLASS="sg" ID="d3" NAME="d3">
gap<INPUT CLASS="xs" VALUE="0" ID="g3" NAME="g3">
<BR><INPUT TYPE="hidden" ID="h3" NAME="h3">
</BODY>
</HTML>
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Sun, 12
Dec 2004 14:43:46, seen in WindAndWaves
Hi Gurus

Below you can find a function and the accompagnying html. I am keen to make
it work, but it seems to be riddled with errors. I basically can not get it
to work.

You're not in America - the word is "cannot", which has a different
meaning to "can not".
The idea is that the user completes the startdate field and that from there
on, the arrival dates and departure dates for the properties are calculated,
using the number of nights and the number of days (gap) between each
property. While the number of nights and the gap are entered as 1 and 0
respectively, the user should be able (once the function is working) to
change those values and the arrival and departure date should be
recalculated.

Any hints greatly appreciated (this is one of my first javascripts).

Well, ISTR that hints to read the newsgroup FAQ have already been given.

Test each routine independently, with good & bad data, until you are
sure that it is sound. Introduce routines, testing continually.

Writing a whole lot of code and then trying to locate the errors is a
favourite beginners' technique. AIUI, the very best real programmers
sometimes try it too, but not for long.


//returns the number of seconds (number)
function pd(d) {
x = new Date(d);
return Date.parse(x); //parse provides the number of milli seconds since
1970
}

(a) Better to put no comment than to put incorrect comment.
(b) x is a date object; it holds milliseconds. Date.parse requires a
string parameter. So you force x to give a string representation in
order to turn it back into milliseconds.
(b) "since 1970" means since 1970-12-31 24:00 local time. The count is
actually from 1970-01-01.0 GMT.

//add values to a date; sd = start date, ad = number of days to add
function adf(sd, ad){
var d = 0;
d = pd(sd) + (ad*86400000); //change number of days into number of
milliseconds
return new Date(d);
}

Never write 86400000; it is too easy to miscount zeroes. 864e5 is
shorter and safer. OTOH, you should only rarely use that number, as it
is not the length of all days. Remember that it is now Summer, and you
are 13h ahead of UK time. That's not the way to add days.

//write element with a date
function writeD(ft, f, el,d){
var bRef = null;
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}

Since that always assigns to bRef, it could be written

bRef =
(document.getElementById) ? document.getElementById(el) : document.all[el];
if (ft == true) {
d = fmt(d);
}

Comparison with true is, at least generally, pointless. The statement
is more legible when written as

if (FT) d = fmt(d)
bRef.value = d;
}

// get date from an element
function getD (f,el){
var bRef = null;
var nv = new Date(); //nv = new value

Pointless assignations; you do not use those Objects. And if it is ever
necessary to create a Date Object that will not be used, then
new Date(0) is much more efficient, for reasons that should be
obvious.
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}
nv = bRef.value;
return Date(nv); //change it into a date
}


// get number from an element
function getN (f,el){
var bRef = null;
var nv = null; //nv = new value

Both pointless assignations.
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}
nv = bRef.value;
return nv;
}

The if then else part is repeated code, and should be factorised
into a standard, well-tested routine.
// format DD-MMM-YYYY
function fmt(d) {
d = Date(d);
return (d.getDate() < 10 ? "0" : "") + d.getDate() + "-" +

No need to evaluate getDate(), which is not quick, twice.
(["JAN","FEB","MAR","APR",
"MAY","JUN","JUL","AUG",
"SEP","OCT","NOV","DEC"])[d.getMonth()] + "-" +

BTW: probably more efficient for a constant literal array to be global.
d.getFullYear();
}




Indenting by a single space is inadequate for at least one user, and
probably more.

The whole point of indenting is LOST if you let your system break code
lines before/when sending them; if you may ask about your code in News, you
MUST keep its line-lengths below 70-72 characters. That also goes for HTML,
which can be laid out to show structure.

Comment within code should be indented as if it were code.
 
W

WindAndWaves

..... snip .....

Thank you for your indepth reply.

You're not in America - the word is "cannot", which has a different
meaning to "can not".

sorry - englighten me - English is my second language. I never use cannot
(since I am not in America), but I understood that can't should be written
as can not.

.... snip ....
Test each routine independently, with good & bad data, until you are
sure that it is sound. Introduce routines, testing continually.

This may sound stupid, but is there a way to do this? In VB (errr) I use
the debug.print command a lot, which I can use to write the values of
variables to a window so that I can see what is going on. As the error
message are rather cryptic at time (I use firefox to test) - it is often
really hard to find out what is going on.

....snip....
(a) Better to put no comment than to put incorrect comment.

true, I was not trying to pedantic at the stage when I wrote it, I just
wanted it to work.
(b) x is a date object; it holds milliseconds. Date.parse requires a
string parameter. So you force x to give a string representation in
order to turn it back into milliseconds.

how could i fix this? d is a date so can I turn d into a string?
(b) "since 1970" means since 1970-12-31 24:00 local time. The count is
actually from 1970-01-01.0 GMT.

Sure, the detail I will work out later. It does not really matter whether
it is local time or GMT, because all of them are hypothetical dates e.g.
people arrive on 1 Jan 05 then stay for two days (i.e. until 3 Jan,) etc.. -
no time is involved with it.

....
Never write 86400000; it is too easy to miscount zeroes. 864e5 is
shorter and safer. OTOH, you should only rarely use that number, as it
is not the length of all days. Remember that it is now Summer, and you
are 13h ahead of UK time. That's not the way to add days.


Ok, will change the 864 thing, how do you add days?
//write element with a date
function writeD(ft, f, el,d){
var bRef = null;
if (document.getElementById) {
bRef = document.getElementById(el);
} else {
bRef = document.all[el];
}

Since that always assigns to bRef, it could be written

bRef =
(document.getElementById) ? document.getElementById(el) :
document.all[el];

will change
Comparison with true is, at least generally, pointless. The statement
is more legible when written as

if (FT) d = fmt(d)

Thank you, real beginner mistake I guess

....snip .....
No need to evaluate getDate(), which is not quick, twice.

so should I do something like
var day = d.getDate

(["JAN","FEB","MAR","APR",
"MAY","JUN","JUL","AUG",
"SEP","OCT","NOV","DEC"])[d.getMonth()] + "-" +

BTW: probably more efficient for a constant literal array to be global.

another good point - I guess you like really efficient code, so do I, but I
am just learning.
Indenting by a single space is inadequate for at least one user, and
probably more.

The whole point of indenting is LOST if you let your system break code
lines before/when sending them; if you may ask about your code in News, you
MUST keep its line-lengths below 70-72 characters. That also goes for HTML,
which can be laid out to show structure.

Comment within code should be indented as if it were code.

Ok, will try to format better. THank you very much for all your comments.
links.
 
R

RobG

WindAndWaves wrote:
[...]
sorry - englighten me - English is my second language. I never use cannot
(since I am not in America), but I understood that can't should be written
as can not.

As far as I am concerned, "can't", "cannot" and "can not" convey
exactly the same meaning - pedantry aside. :)
This may sound stupid, but is there a way to do this? In VB (errr) I use
[...]

I think what is being suggested is that you start with a simple bit of
code, maybe just a couple of lines, and test from there. I often start
with an single alert to validate that I am passing to the function the
values I think I am. Add statements a couple at a time, testing as you
go. That way, when you strike a problem, you know where it is.

Liberal use of alert() to test what is going on as you proceed really
helps too.

The above assumes that you already have valid HTML...

[...]
how could i fix this? d is a date so can I turn d into a string?

Like this:

//add days; sd = start date, ad = number of days to add
function adf(sd, ad){
return new Date(sd.getTime() + ad*864e5);
}

Gets rid of pd() altogether.

[...]
Ok, will change the 864 thing, how do you add days?

As above. I agree with your comment on dates.

[...]
so should I do something like
var day = d.getDate

Seems to me that d is already a date, so why not:

function fmt(d) {
var dateNum = d.getDate();
return (dateNum < 10 ? "0" : "") + dateNum + "-" + ...

I'll have a bit more of a play with your code later, hope that helps
a bit for now.
 
R

RobG

RobG wrote:
[...]
I'll have a bit more of a play with your code later, hope that helps
a bit for now.

Actually, it requires more work than I thought... Gimme a few hours, I
think the logic behind what you are trying to do needs a bit of work.

You need to be looping through all of your inputs. Users should be
given a date picker to pick the dates to prevent input errors and to
make sure they can't pick a date before the departure from the previous
property (easier than validating input sometimes).

The "gap" should be calculated, or if the user modifies it, only
subsequent dates should be modified. But do you preserve the "gap" or
the final date? I'll guess you want to preserve the gap, and assume
that the initial value of the gap is the minimum that can be set - it
should be zero if they are going from one to another.

If done right, the above should allow you to add more properties in the
chain.

One last point - can users skip a property? If so, you need a checkbox
to say so or use nights = zero (which may not be intuitive for users).
 
W

WindAndWaves

RobG said:
RobG wrote:
[...]
I'll have a bit more of a play with your code later, hope that helps
a bit for now.

Actually, it requires more work than I thought... Gimme a few hours, I
think the logic behind what you are trying to do needs a bit of work.

Hey Dude - thank you - awesome.
You need to be looping through all of your inputs. Users should be
given a date picker to pick the dates to prevent input errors and to
make sure they can't pick a date before the departure from the previous
property (easier than validating input sometimes).


I have a nice datepicker that I downloaded from the net. Otherwise, I also
have a really simple datepicker that allows people only to select valid
dates. The idea is that people only specify their departure date and how
many nights they stay at each property. The default number of nights per
property is one and as most people will stay one night, it is easy, all they
have to do is to give their departure date and all the other dates will be
worked out for them.
The "gap" should be calculated, or if the user modifies it, only
subsequent dates should be modified. But do you preserve the "gap" or
the final date? I'll guess you want to preserve the gap, and assume
that the initial value of the gap is the minimum that can be set - it
should be zero if they are going from one to another.

correct, users never touch the dates, they only touch the nights and, if
they have to they add a gap (e.g. they stay with relatives or go hiking for
a few days)
If done right, the above should allow you to add more properties in the
chain.

Well, yes, I have a PHP guru working on that. But I said, stupidly (hmmmm)
that I would take care of the javascript to manage the dates. It makes more
sense to do the dates with javascript, as with PHP you need to talk to the
server every time you make a change (i.e. long delays), so, I thought that
people can play around with the dates using (quick) javascript and then, if
they want to change (move, delete, add) a property, PHP comes along to help
out (using a session, so I have been told).
One last point - can users skip a property? If so, you need a checkbox
to say so or use nights = zero (which may not be intuitive for users).

Properties are selected from a list into a "shopping basket". This basket
page contains then I was asking about Javascript.

I guess I have given away all my trade secrets now, hmmmm, long live open
source.

Thank you once more for your help


- Nicolaas
PS once thing that I have not worked out yet is from where to call the
script. My guess would be to add it to the the OnChange event for every
input box.
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Mon, 13
Dec 2004 05:37:23, seen in RobG
WindAndWaves wrote:
[...]
sorry - englighten me - English is my second language. I never use cannot
(since I am not in America), but I understood that can't should be written
as can not.

As far as I am concerned, "can't", "cannot" and "can not" convey
exactly the same meaning - pedantry aside. :)

Maybe so; but you're posting from AU.
Like this:

//add days; sd = start date, ad = number of days to add
function adf(sd, ad){
return new Date(sd.getTime() + ad*864e5);
}

That'll do in Que, NT, and WA; but not in NSW, ACT, Vic, & SA nor
Tasmania; and not in NZ, EU, most of NA, fUSSR, and others.

<URL:http://www.merlyn.demon.co.uk/uksumtim.htm#Else>
<URL:http://www.merlyn.demon.co.uk/js-date0.htm#DGU>
<URL:http://www.merlyn.demon.co.uk/js-date1.htm#incr>

BTW, the quoted code does not increase a Date Object, but generates a
new one - that may not be desirable.

Consider : var D = new Date() ; with (D) setDate(getDate()+1)
 
W

WindAndWaves

[...]
That'll do in Que, NT, and WA; but not in NSW, ACT, Vic, & SA nor
Tasmania; and not in NZ, EU, most of NA, fUSSR, and others.

<URL:http://www.merlyn.demon.co.uk/uksumtim.htm#Else>
<URL:http://www.merlyn.demon.co.uk/js-date0.htm#DGU>
<URL:http://www.merlyn.demon.co.uk/js-date1.htm#incr>

strictly speaking, no, but it practice we can ignore summer time, I hope, I
think, if you are only working with dates, adding or substracting a couple
of days.
BTW, the quoted code does not increase a Date Object, but generates a
new one - that may not be desirable.

Consider : var D = new Date() ; with (D) setDate(getDate()+1)

OK, thank you.
links.
 
R

RobG

WindAndWaves wrote:
[...]
I have a nice datepicker that I downloaded from the net. Otherwise, I also
have a really simple datepicker that allows people only to select valid
OK

[...]
correct, users never touch the dates, they only touch the nights and, if
they have to they add a gap (e.g. they stay with relatives or go hiking for
a few days)

Then the date "fields" should be text nodes rather than text inputs.
People like to play with input fields whether you want them to or not,
making them plain text nodes stops (most) users from even trying.

[...]
Properties are selected from a list into a "shopping basket". This basket
page contains then I was asking about Javascript.

I put in a visit checkbox so if they've selected a property then decide
not to visit, they just check the checkbox and it is removed from
calculations (though still visible on the page so they can change their
mind again...)
I guess I have given away all my trade secrets now, hmmmm, long live open
source.

Hardly! :) What I've provided below is just a prototype. I think you
should change the date fields to text nodes, ditch the "visited"
checkbox and modify the logic - perhaps just make them display none so
you can use them later if you want.

If you use text nodes instead of input fields, you'll have to use some
other way of referencing them other than as elements (say
getElementsById).

Tested & OK in the following Mac browsers:

Safari, IE, Camino, Firefox, Netscape

Failed in Opera on Mac.

I started on Firefox on Windows, I expect it's fine there.
Thank you once more for your help

No problem.

[...]
PS once thing that I have not worked out yet is from where to call the
script. My guess would be to add it to the the OnChange event for every
input box.

Argghhh! <-( My personal preference is to have a "calculate" button.
I *hate* things that just do stuff, particularly as I may make a key
error that I'd like to correct myself rather than get a message that I
have to dismiss, then fix the error I was going to fix anyway.

Just my view, it's your site! :)

PS. I put in two check digit functions, pick whichever you like best.
The first does not handle leading spaces, so if you use it, modify it.

Sorry to take so long to post back but my news server has been down &
I've been too busy to use google groups.

I looked at Dr J's suggestion on the date but decided not to include
it. I make a new depDate object anyway, I think adding to the one date
is OK (i.e. create one date object and keep adding nights and gaps to
fill the various fields) but that would require a change of logic that
I haven't got time to address.

I'm not sure there would be much of a performance gain with only a few
date fields, I tested on a 400 MHz G3 and it all ran fine.

The last "gap" input is hidden because it is redundant I think, but if
you delete it, IE gives an error when trying to access it. So rather
than mess with logic to account for a non-existent box I just did a
quick fix. You may want to test for the existence of n and g inputs
before reading from or writing to them to make it more robust.

Have now tested on Firefox and IE on XP and all is good.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>test me</TITLE>
<script type="text/javascript">

// Make month and day arrays global
var monthsA = ['Jan','Feb','Mar','Apr',
'May','Jun','Jul','Aug',
'Sep','Oct','Nov','Dec'];
var daysA = ['Sun','Mon','Tue','Wed',
'Thu','Fri','Sat'];

function formatDate(d) {
var s = daysA[d.getDay()]
+ ' ' + d.getDate()
+ ' ' + monthsA[d.getMonth()]
+ ' ' + d.getFullYear();
return s;
}

function calc(f){

// Setup variables - msg is for debug
var ele, x, n, numNights, gapDays,
depDate, nField, gField;
var digitErr = 'You must enter a whole number from zero to 99';


// Get a collection of the form elements
ele = f.elements;

// I've used a separate startdate input
// as the start date. Ditch if not required
// make more robust if keeping (there's zero validation)
// Check month adjustment, keep aligned with input
var aa = f.elements['startdate'].value;
var a = aa.split('-')[0];
var b = aa.split('-')[1]-1; // Adjust for jan=0...dec=11
var c = aa.split('-')[2];
var sd = new Date(c,b,a);

// Loop thru all the elements
for (var i=0; i<ele.length; i++) {

// if the element has a name
if (ele.name) {

// If the element is the to be visited checkbox
if (ele.name.split('-')[0] == 'v') {

// Get the element id extension
n = ele.name.split('-')[1];

// If intend to visit (checkbox is checked)
if (ele.checked) {

// Check user input fields as we go
// Put the start date in
f.elements['a-' + n].value = formatDate(sd);

// Get the nights staying
nField = f.elements['n-' + n];
if ( !(numNights = nField.value)
|| !checkDigit2(numNights)) {
alert(digitErr);
// Blank field
nField.value = '';
// Put focus on it if you like
nField.select() = '';
return false;
}

// Add the number of nights to get depature date
depDate = new Date (sd.getTime() + numNights*864e5);

// Write dep date to form
f.elements['d-' + n].value = formatDate(depDate);

// Get gap days
gField = f.elements['g-' + n];
if ( !(gapDays = gField.value)
|| !checkDigit(gapDays)) {
alert(digitErr);
gField.value = '';
gField.select() = '';
return false;
}

// startdate for next property is now depDate plus gap days
sd = new Date(+depDate.getTime() + gapDays*864e5);

// Otherwise blank the fields
} else {
f.elements['a-' + n].value = '';
f.elements['n-' + n].value = '';
f.elements['d-' + n].value = '';
f.elements['g-' + n].value = '';
}
}
}
}
}

function checkDigit(x) {
var dayRegX = /^\d{1,2}$/;
// var dayRegX = /^(0|[1-9])\d*$/
if (!dayRegX.test(x)) {
return false;
}
return true;
}

function checkDigit2(x) {
if (x == parseInt(x,10) && x == parseFloat(x)) {
return true;
} else {
return false;
}
}
</script>

<style type="text/css">
body, th, td {font-family: sans-serif; font-size: 90%;}
th {background-color: #dfdfdf; padding: 0 8 0 8;}
td {text-align: center;}
..sg {width: 10em;}
..xs {width: 2em;}
..hint {color: #333366; font-weight: normal; font-size: 90%;}
</style>

</HEAD>
<BODY>

<FORM METHOD="POST" NAME="basket" ID="basket">
<!-- This field is just to provide a start date -->
<label for="startdate">Start Date
<input type="text" value="05-12-2004" name="startdate"></label>

<table border="0" cellspacing="0">
<thead>
<tr>
<th>Property Name</th>
<th>Will you visit<br>this property?</th>
<th>Date of arrival<br><span class="hint">after
1pm</span></th>
<th>How many nights<br>you will stay?</th>
<th>Date of departure<br><span class="hint">before
10am</span></th>
<th>Nights gap to<br>next property</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">
<INPUT TYPE="reset" VALUE="reset" ID="Reset1" NAME="Reset1"><br>
</td>
<td colspan="3">
<INPUT TYPE="button" VALUE="calculate" ONCLICK="
return calc(this.form);
"
ID="calculate" NAME="calculate" tabindex="8">
</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>property1</td>
<td><input type="checkbox" id="v-1" name="v-1" checked></td>
<td><INPUT type="text" CLASS="sg" ID="a-1" NAME="a-1"></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-1" NAME="n-1"
tabindex="1"></td>
<td><INPUT type="text" CLASS="sg" ID="d-1" NAME="d-1"></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-1" NAME="g-1"
tabindex="2"></td>
</tr>
<tr>
<td>property 2</td>
<td><input type="checkbox" id="v-2" name="v-2" checked></td>
<td><INPUT type="text" CLASS="sg" ID="a-2" NAME="a-2"></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-2" NAME="n-2"
tabindex="3"></td>
<td><INPUT type="text" CLASS="sg" ID="d-2" NAME="d-2"></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-2" NAME="g-2"
tabindex="4"></td>
</tr>
<tr>
<td>property 3</td>
<td><input type="checkbox" id="v-3" name="v-3" checked></td>
<td><INPUT type="text" CLASS="sg" ID="a-3" NAME="a-3"></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-3" NAME="n-3"
tabindex="5"></td>
<td><INPUT type="text" CLASS="sg" ID="d-3" NAME="d-3"></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-3" NAME="g-3"
tabindex="6"></td>
</tr>
<tr>
<td>property 4</td>
<td><input type="checkbox" id="v-4" name="v-4" checked></td>
<td><INPUT type="text" CLASS="sg" ID="a-4" NAME="a-4"></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-4" NAME="n-4"
tabindex="7"></td>
<td><INPUT type="text" CLASS="sg" ID="d-4" NAME="d-4"></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-4" NAME="g-4"
style="display: none;"></td>
</tr>
</tbody>
</table>

</BODY>
</HTML>
 
R

RobG

RobG wrote:
[...]
The last "gap" input is hidden because it is redundant I think, but if
you delete it, IE gives an error when trying to access it. So rather
than mess with logic to account for a non-existent box I just did a
quick fix. You may want to test for the existence of n and g inputs
before reading from or writing to them to make it more robust.

Here's the fix so you can get rid of the redundant g input. It just
checks to see if the inputs exist before trying to use them.

Replace:

if ( !(gapDays = gField.value)
|| !checkDigit(gapDays)) {

with

if ( gField
&& !(gapDays = gField.value)
|| !checkDigit(gapDays)) {

and

f.elements['g-' + n].value = '';

with

if (f.elements['g-' + n])
f.elements['g-' + n].value = '';

It may be worthwhile doing the same to the n- fields too.
 
W

WindAndWaves

RobG said:
RobG wrote:
[...]
The last "gap" input is hidden because it is redundant I think, but if
you delete it, IE gives an error when trying to access it. So rather
than mess with logic to account for a non-existent box I just did a
quick fix. You may want to test for the existence of n and g inputs
before reading from or writing to them to make it more robust.

Here's the fix so you can get rid of the redundant g input. It just
checks to see if the inputs exist before trying to use them.

Replace:

if ( !(gapDays = gField.value)
|| !checkDigit(gapDays)) {

with

if ( gField
&& !(gapDays = gField.value)
|| !checkDigit(gapDays)) {

and

f.elements['g-' + n].value = '';

with

if (f.elements['g-' + n])
f.elements['g-' + n].value = '';

It may be worthwhile doing the same to the n- fields too.


Where can I send the chocolates?
 
R

RobG

WindAndWaves wrote:
[...]
Where can I send the chocolates?

Give 'em to your wife/girlfriend/partner/mum?

Just for a giggle, here's a version using spans for the arrival and
departure dates. Also fixed a niggling bug with focus() that I'd
missed before (I had ...focus() = ''; gee, must been up late ;-) ).

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<TITLE>test me</TITLE>
<script type="text/javascript">

// Make month and day arrays global
var monthsA = ['Jan','Feb','Mar','Apr',
'May','Jun','Jul','Aug',
'Sep','Oct','Nov','Dec'];
var daysA = ['Sun','Mon','Tue','Wed',
'Thu','Fri','Sat'];

function formatDate(d) {
var s = daysA[d.getDay()]
+ ' ' + d.getDate()
+ ' ' + monthsA[d.getMonth()]
+ ' ' + d.getFullYear();
return s;
}

function calc(f){

// Setup variables - msg is for debug
var ele, x, n, numNights, gapDays,
depDate, nField, gField;
var digitErr = 'You must enter a whole number from zero to 99';


// Get a collection of the form elements
ele = f.elements;

// I've used a separate startdate input
// as the start date. Ditch if not required
// make more robust if keeping
// Check month adjustment, keep aligned with input
var aa = f.elements['startdate'].value;
var a = aa.split('-')[0];
var b = aa.split('-')[1]-1; // Adjust for jan=0...dec=11
var c = aa.split('-')[2];
var sd = new Date(c,b,a);

// Loop thru all the elements
for (var i=0; i<ele.length; i++) {

// if the element has a name
if (ele.name) {

// If the element is the to be visited checkbox
if (ele.name.split('-')[0] == 'v') {

// Get the element id extension
n = ele.name.split('-')[1];

// If intend to visit (checkbox is checked)
if (ele.checked) {

// Check user input fields as we go
// Put the start date in
document.getElementById('a-' + n).innerHTML
= formatDate(sd);

// Get the nights staying
nField = f.elements['n-' + n];
if ( !(numNights = nField.value)
|| !checkDigit2(numNights)) {
alert(digitErr);
// Blank field
nField.value = '';
// Put focus on it if you like
nField.focus();
return false;
}

// Add the number of nights to get depature date
depDate = new Date (sd.getTime() + numNights*864e5);

// Write dep date to form
document.getElementById('d-' + n).innerHTML
= formatDate(depDate);

// Get gap days
gField = f.elements['g-' + n];
if ( gField
&& !(gapDays = gField.value)
|| !checkDigit(gapDays)) {
alert(digitErr);
gField.value = '';
gField.focus();
return false;
}

// startdate for next property is now depDate plus gap days
sd = new Date(+depDate.getTime() + gapDays*864e5);

// Otherwise blank the fields
} else {
// f.elements['a-' + n].value = '';
document.getElementById('a-' + n).innerHTML = '&nbsp;';
f.elements['n-' + n].value = '';
// f.elements['d-' + n].value = '';
document.getElementById('d-' + n).innerHTML = '&nbsp;';
if (f.elements['g-' + n])
f.elements['g-' + n].value = '';
}
}
}
}
}

function checkDigit(x) {
var dayRegX = /^\d{1,2}$/;
// var dayRegX = /^(0|[1-9])\d*$/
if (!dayRegX.test(x)) {
return false;
}
return true;
}

function checkDigit2(x) {
if (x == parseInt(x,10) && x == parseFloat(x)) {
return true;
} else {
return false;
}
}
</script>

<style type="text/css">
body, th, td {font-family: sans-serif; font-size: 90%;}
th {background-color: #dfdfdf; padding: 0 8 0 8;}
td {text-align: center;}
..sg {width: 10em;}
..xs {width: 2em;}
..hint {color: #333366; font-weight: normal; font-size: 90%;}
</style>

</HEAD>
<BODY>

<FORM METHOD="POST" NAME="basket" ID="basket">
<!-- This field is just to provide a start date -->
<label for="startdate">Start Date
<input type="text" value="05-12-2004" name="startdate"></label>

<table border="0" cellspacing="0">
<thead>
<tr>
<th>Property Name</th>
<th style="width: 10em;">Will you visit<br>this
property?</th>
<th style="width: 12em;">Date of arrival<br><span
class="hint">after 1pm</span></th>
<th>How many nights<br>you will stay?</th>
<th style="width: 12em;">Date of departure<br><span
class="hint">before 10am</span></th>
<th>Nights gap to<br>next property</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">
<INPUT TYPE="reset" VALUE="reset" ID="Reset1" NAME="Reset1"><br>
</td>
<td colspan="3">
<INPUT TYPE="button" VALUE="calculate" ONCLICK="
return calc(this.form);
"
ID="calculate" NAME="calculate" tabindex="8">
</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>property 1</td>
<td><input type="checkbox" id="v-1" name="v-1" checked></td>
<td><span class="sg" ID="a-1">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-1" NAME="n-1"
tabindex="1"></td>
<td><span class="sg" ID="d-1">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-1" NAME="g-1"
tabindex="2"></td>
</tr>
<tr>
<td>property 2</td>
<td><input type="checkbox" id="v-2" name="v-2" checked></td>
<td><span class="sg" ID="a-2">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-2" NAME="n-2"
tabindex="3"></td>
<td><span class="sg" ID="d-2">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-2" NAME="g-2"
tabindex="4"></td>
</tr>
<tr>
<td>property 3</td>
<td><input type="checkbox" id="v-3" name="v-3" checked></td>
<td><span class="sg" ID="a-3">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-3" NAME="n-3"
tabindex="5"></td>
<td><span class="sg" ID="d-3">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-3" NAME="g-3"
tabindex="6"></td>
</tr>
<tr>
<td>property 4</td>
<td><input type="checkbox" id="v-4" name="v-4" checked></td>
<td><span class="sg" ID="a-4">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="1" ID="n-4" NAME="n-4"
tabindex="7"></td>
<td><span class="sg" ID="d-4">&nbsp;</span></td>
<td><INPUT type="text" CLASS="xs" VALUE="0" ID="g-4" NAME="g-4"
style="display: none;">&nbsp;</td>
</tr>
</tbody>
</table>

</BODY>
</HTML>
 
M

Michael Winter

[snip]
// var dayRegX = /^(0|[1-9])\d*$/

ARRGH! I made a correction!

/^(0|[1-9]\d*)$/

Notice the position of the closing parenthesis. It makes a huge
difference. However, for what you want:

/^(0|[1-9]\d?)$/
if (!dayRegX.test(x)) {

You could just use the literal directly:

if(!/.../.test(x)) {
return false;
}
return true;
}

I assume that was done for clarity, but it should be

return /.../.test(x);

[snip]

Mike
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Tue, 14
Dec 2004 10:55:14, seen in WindAndWaves
[...]
That'll do in Que, NT, and WA; but not in NSW, ACT, Vic, & SA nor
Tasmania; and not in NZ, EU, most of NA, fUSSR, and others.

<URL:http://www.merlyn.demon.co.uk/uksumtim.htm#Else>
<URL:http://www.merlyn.demon.co.uk/js-date0.htm#DGU>
<URL:http://www.merlyn.demon.co.uk/js-date1.htm#incr>

strictly speaking, no, but it practice we can ignore summer time, I hope, I
think, if you are only working with dates, adding or substracting a couple
of days.

Think what you like; we don't mind you writing buggy code, as long as
you don't make it public. One can change the local date reliably by
adding a fixed number of seconds, but only if the time part is
constrained to exclude an hour each side of midnight.

Don't quote signatures. Read the newsgroup FAQ.
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Tue, 14
Dec 2004 03:34:36, seen in RobG
Just for a giggle, here's a version using spans for the arrival and
departure dates.



FYI, On the HTML, my copy of TIDY says
line 143 column 4 - Warning: missing </form>
line 143 column 4 - Warning: <form> lacks "action" attribute
line 148 column 1 - Warning: <table> lacks "summary" attribute


There is script not compatible with my browser, so I have not tested
fully. But I can't see that the input date is validated, and dd-mm-yyyy
is not a safe input format internationally, and the example 05-12-2004
will be interpreted differently in UK & USA. Use yyyy-mm-dd or
yyyy/mm/dd.


This, and its mate, -
// Add the number of nights to get depature date
depDate = new Date (sd.getTime() + numNights*864e5);
should still fail in Autumn (or Spring?), where Summer Time is used.

Test D = new Date(+new Date(2004, X, 1) + Y*864e5).getHours()
for X=0 & X=6, Y = 1 & Y = 180.


For :
function checkDigit2(x) {
if (x == parseInt(x,10) && x == parseFloat(x)) {
return true;
} else {
return false;
}
}

this is simpler :

function checkDigit2(x) {
return x == parseInt(x,10) && x == parseFloat(x)) }

Likewise for CheckDigit2 (which may not check >=0).


There's no need to split aa three times.


See below.
 
R

RobG

Dr John Stockton wrote:
[...]
There is script not compatible with my browser, so I have not tested
fully. But I can't see that the input date is validated, and dd-mm-yyyy
is not a safe input format internationally, and the example 05-12-2004
will be interpreted differently in UK & USA. Use yyyy-mm-dd or
yyyy/mm/dd.

The OP said the start date is catered for on a previous page where a
date picker is used. I just put the startdate field there for the sake
of providing a start date. It also allows testing various start dates
This, and its mate, -


should still fail in Autumn (or Spring?), where Summer Time is used.

I noted your previous advice to add integer days to the date rather
than 24 hrs to the time, but made excuses for not implementing it. I
subsequently did it anyway but didn't post the code, so a new calc()
function is posted below. It fixes a couple more minor bugs too.

[...]
this is simpler :

function checkDigit2(x) {
return x == parseInt(x,10) && x == parseFloat(x)) }

Likewise for CheckDigit2 (which may not check >=0).


There's no need to split aa three times.

Quite correct except for the extra ")".

function checkDigit2(x) {
return x == parseInt(x,10) && x == parseFloat(x)
}

I wanted to make it really obvious how sd was created, I expect that
bit of code will not survive past initial testing when the start date
will be provided by the previous page. But anyway, I've included your
suggestion.

New calc() below, thank you for the suggestions, see if you get errors
this time.

function calc(f){
var ele, x, n, numNights, gapDays,
depDate, nField, gField;
var digitErr = 'You must enter a whole number from zero to 99';
ele = f.elements;
// Process start date (for dev only)
var aa = f.elements['startdate'].value.split('-');
var sd = new Date(aa[2],aa[1]-1,aa[0]);

for (var i=0; i<ele.length; i++) {
if (ele.name) {
if (ele.name.split('-')[0] == 'v') {
n = ele.name.split('-')[1];
if (ele.checked) {
// Write the start date
document.getElementById('a-' + n).innerHTML
= formatDate(sd);
// Get the nights staying
nField = f.elements['n-' + n];
if ( !(numNights = nField.value)
|| !checkDigit2(numNights)) {
alert(digitErr);
nField.value = ''; // Blank field
nField.focus();
return false;
}
// Add the number of nights to get depature date
sd.setDate(sd.getDate() + +numNights);
document.getElementById('d-' + n).innerHTML
= formatDate(sd);
// Get gap days
gField = f.elements['g-' + n];
if ( gField
&& !(gapDays = gField.value)
|| !checkDigit(gapDays)) {
alert(digitErr);
gField.value = '';
gField.focus();
return false;
}
// Increment start date
sd.setDate(sd.getDate() + +gapDays);
} else {
document.getElementById('a-' + n).innerHTML = '&nbsp;';
f.elements['n-' + n].value = '';
document.getElementById('d-' + n).innerHTML = '&nbsp;';
if (f.elements['g-' + n])
f.elements['g-' + n].value = '';
}
}
}
}
}
 
W

WindAndWaves

[...]
Think what you like; we don't mind you writing buggy code, as long as
you don't make it public. One can change the local date reliably by
adding a fixed number of seconds, but only if the time part is
constrained to exclude an hour each side of midnight.

In the function, which Rob and you really helped me a lot - thank you again
for that. We have a date (from a datepicker), to which we add a couple of
days only (lets say 30 at the very very most). Because time does not come
into it, I dont think that date light saving matters, but correct me if I am
wrong, I may have misunderstood you.Are you saying that, for some people,
their local javascript engine may take daylight saving into account so when
we start adding a few days it may end up being before midnight rather than
on midnight? In that case, daylight saving obviously does matter. Could
you clarify that (I do want to get it right, but I prefer to keep it as
simple as pos.)

Thank you

- Nicolaas

Don't quote signatures. Read the newsgroup FAQ.
links.
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Tue, 14
Dec 2004 22:59:09, seen in RobG
New calc() below, thank you for the suggestions, see if you get errors
this time.

I do, of course (see sig); a fix is to put

if (document.all && !document.getElementById) {
document.getElementById = function(id) {
return document.all[id] } }

in front of
function calc(f){

// Process start date (for dev only)
var aa = f.elements['startdate'].value.split('-');

// or var aa = f.elements['startdate'].value.split(/\D+/); // said:
var sd = new Date(aa[2],aa[1]-1,aa[0]);



and then it runs (new calc in page-as-before). I'd align dates right,
not centre, especially with day-of-week first. I'd check the start date
to be not before today, and not too far ahead - and give a warning if
more than a year ahead. But if doing that, consider bookings from
across the Date Line; yesterday is usually not all that far East of the
Antipodes.

It's easier to check 1/2 digit fields with a RegExp -
OK = /^\d?\d$/.test(field)
and if OK it can safely be converted to Number with a unary +.

I'd change gapDays to gapNights !

I'd do the string-to-number conversion immediately after passing the
format test, but that is mere preference.

I've not checked all the logic, but it seems to do what seems expected.

I *might* enter '---' rather than '' for blank dates, and shift "Nights
gap" down half a line. "you will" -> "will you" ?!

By the way, another way of avoiding summer time error is to calculate in
UTC.

No need for the CSS, which overrules my font choice; HTML alone could
give an adequate layout.
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Wed, 15
Dec 2004 21:14:42, seen in WindAndWaves
In the function, which Rob and you really helped me a lot - thank you again
for that. We have a date (from a datepicker), to which we add a couple of
days only (lets say 30 at the very very most). Because time does not come
into it, I dont think that date light saving matters, but correct me if I am
wrong, I may have misunderstood you.Are you saying that, for some people,
their local javascript engine may take daylight saving into account so when
we start adding a few days it may end up being before midnight rather than
on midnight? In that case, daylight saving obviously does matter. Could
you clarify that (I do want to get it right, but I prefer to keep it as
simple as pos.)

Summer time can matter, even if you are only trying to add one day, if
you do it by adding 86400 seconds. Where there is summer time, one
Autumn day is 90000 seconds long (except for Lord Howe Island).

For subtracting days, note that one Spring day (e f L H I) can be 82800
seconds long.

Javascript ignores Leap Seconds.

In javascript, getTime(), valueOf(), and new Date(x) where x is a
number, use milliseconds GMT (UTC, if you prefer).

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
||||||||||||||||||||||||||||||||||||||||||||||||||


<FAQENTRY> An entry referring to dates should mention the importance of
discriminating between GMT, local Winter Time, & local Summer Time.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top