Driver, C, 4and called the table fuel.dbf. I filled it in with some fake data for driver “1” and driver “2”:
Date, D
Gallons,N, 4, 0
<input id="V.R1.DRIVER" size="4" maxlength="4" class="AlphaSportsInput" name="V.R1.DRIVER" value="1" type="text">I highlighted the important point, which is that every input field in every row has a unique ID. We can use the ID to reference each input field in Javascript, using the Javascript method, document.getElementById(). That is, if I write
<input id="V.R1.DATE" size="10" maxlength="10" class="AlphaSportsInput" name="V.R1.DATE" value="09/05/2005" type="text">
<a onclick="load_date_picker('V.R1.DATE',document.getElementById('V.R1.DATE').value, fuel_DATE_DateSet)">
<img src="css/CalendarIcons/Calendar2.png" border="0"></a>
<input id="V.R1.GALS" style="text-align: right;" size="4" maxlength="4"
class="AlphaSportsInput" name="V.R1.GALS" value="18" type="text">
obj=document.getElementById(“V.R1.DRIVER”)then
objrefers to the “Driver” field in the first row, and
obj.valueretrieves the contents of that field. This is not the place for a complete Javascript tutorial, and I'm far from the person best qualified to do it in any event! However I am going to show you how much can be done with just a smattering of Javascript. The only important features of Javascript that we are going to use, other than flow control structures (if, while, function calls, etc.) are the document.getElementById() method and object.innerHTML assignment, which lets us assign HTML coding to an object – in this example, to a table data cell. I'm also going to use a little CSS to position the results nicely, to get the results shown below:
<html>
<head>
<script type="text/javascript" language="javascript">
function fuelUsed(){
var drivers="";
i=1;
var gals=0;
var rows=0;
// the while loop goes through the entire table
while (document.getElementById("V.R"+i+".GALS")) {
obj=document.getElementById("V.R"+i+".GALS");
// check to see if a number is in the field, as opposed to a blank field
if (parseFloat(obj.value)){
rows+=1;
gals+=parseFloat(obj.value);
driver=document.getElementById("V.R"+i+".DRIVER").value;
if (drivers.indexOf(driver+",")==-1)
drivers+=driver+",";
}
i+=1;
} //end while
if (rows>0) {
obj1=document.getElementById("V.R1.DATE");
if (obj1){
startDate=new Date(obj1.value);
endDate=new Date(document.getElementById("V.R"+rows+".DATE").value);
// subtracting days yields milliseconds, convert to days
diffDays=Math.abs((endDate-startDate)/(1000*60*60*24));
// now fill in the results
galObj=document.getElementById("gallons");
galObj.innerHTML=gals;
daysObj=document.getElementById("days");
daysObj.innerHTML=diffDays;
projectedObj=document.getElementById("projected");
projectedObj.innerHTML=Math.round(100*gals*365/diffDays)/100+" gallons";
drivArray=drivers.split(',');
document.getElementById("breakdownLabel").innerHTML="Breakdown by driver:"
for (i=0;i<drivArray.length-1;i++) {
driverObject=new Object();
driverObject.aDriver=drivArray[i];
driverObject.gals=0;
for (j=1;j<=rows;j++) {
driverObject.gals+=
document.getElementById("V.R"+j+".DRIVER").value ==
driverObject.aDriver?parseFloat(document.getElementById("V.R"+j+".GALS").value):0;
}
document.getElementById("breakdown").innerHTML+=
"<br />Driver "+driverObject.aDriver+": "+driverObject.gals+" gals.";
}
reslts=document.getElementById("right");
reslts.style.display=' block';
}
} else {
reslts=document.getElementById("right");
reslts.style.display=' none';
}
}
function init(){
i=1;
while (document.getElementById("V.R"+i+".GALS")) {
obj1=document.getElementById("V.R"+i+".DATE");
obj1.onchange=fuelUsed;
obj2=document.getElementById("V.R"+i+".GALS");
obj2.onchange=fuelUsed;
i+=1;
}
fuelUsed();
}
window.onload=init;
</script>
<style type="text/css">
#left {
float: left;
}
#results {
position:relative;
top:2em;
left:1em;
border:1ex solid blue;
}
</style>
<%a5
Delete Tmpl
DIM Tmpl as P
tmpl = a5w_load_component("fuel")
'Following code allows you to override settings in the saved component, and specify the component alias (componentName
property).
'Tip: Keep the componentName property short because this
name is used in page URLs, and it will help keep the URLs short.
'Each component on a page must have a unique alias
(componentName property).
with tmpl
componentName = "fuel"
end with '=======================================compute
the HTML for the Component=======================================
delete x_out
dim x_out as p
tmpl.request = request
tmpl.session = session
tmpl.response = response
tmpl.serversetting = serversetting
tmpl.PageVariables = local_variables()
x_out = a5w_run_Component(tmpl)
'=============================================================================================================
if x_out.RedirectURL <> "" then
response.redirect(x_out.redirectURL)
end
end if
?x_out.Output.Head.JavaScript
?x_out.Output.Head.CSS_Link
%>
<!--Alpha Five Temporary Code Start - Will be automatically removed when page is published -->
<!--CSS for tmpl -->
<link rel="stylesheet" type="text/css"
href="file:///C:\Program Files\A5V6/css/AlphaSportsSmall/style.css">
<!--Alpha Five Temporary Code End -->
<title>fuel</title>
</head>
<%a5 ?x_out.Output.Body.Body_Tag %>
<!--Alpha Five Temporary Code Start - Will be automatically removed when page is published -->
<!--Body Tag for tmpl -->
<body class="AlphaSportsSmallPageBODY"><!--Alpha Five Temporary Code End --><!-- Any text that you want to output above the component
goes here-->
<br>
<div id="left">
<table>
<tr>
<td><%A5 ?x_out.Output.Body.Grid_Echo %></td>
</tr>
<tr>
<td><%A5 ?x_out.Output.Body.UpdateErrors %></td>
</tr>
<tr>
<td><%A5 ?x_out.Output.Body.Search_HTML %></td>
</tr>
<tr>
<td><%A5 ?x_out.Output.Body.Grid_HTML %></td>
</tr>
<tr>
<td><%A5 ?x_out.Output.Body.DetailView_HTML %></td>
</tr>
</table>
</div>
<div id="right">
<table id="results">
<tr>
<td>Gallons used: </td><td id="gallons"></td>
</tr>
<tr><td>Over days: </td><td id="days"></td>
</tr>
<tr><td>Projected one year usage:</td><td id="projected"></td>
</tr>
<tr><td id="breakdownLabel"></td><td id="breakdown"></td></tr>
</table>
</div>
</body>
</html>
<table id="results">The table is given an ID of "results", so that Javascript and CSS can easily refer to it later. It has three rows and each row has two cells: the first cell in each row contains a label, e.g., "Gallons used:", and the second cell will hold the calculated results. The cells that will hold calculated results also have IDs so that I can easily use Javascript to put HTML into them.
<tr>
<td>Gallons used: </td><td id="gallons"></td>
</tr>
<tr><td>Over days: </td><td id="days"></td>
</tr>
<tr><td>Projected one year usage:</td><td id="projected"></td>
</tr>
<tr><td id="breakdownLabel"></td><td id="breakdown"></td></tr>
</table>
<style type="text/css">It's hard to get simpler than this. What is says is that the "left" div will "float" on the left side of the browser window, and the next div will appear, well, to its right! The table named "results" will be positioned 2 ems (the size of an "M" in the current text font) from the top of its "container", 1 em to the left of its container, and with a solid blue border of width 1 ex (the size of an "x" in the current font). What is the "container" for the table "results"? It is the div we called "right" which appears to the right of the div called "left". Please note that the names of "left", "right", and "results" that I used are completely arbitrary -- the output formatting depends on the CSS styling, not on the identifiers used!
#left {
float: left;
}
#results {
position:relative;
top:2em;
left:1em;
border:1ex solid blue;
}
</style>
<script type="text/javascript" language="javascript">
function fuelUsed(){
..with some code
}
function init(){
..with some code
}
window.onload=init;
</script>
window.onload=init;instructs a Javascript-enabled browser to execute the "init" function after the page content has finished loading, but before it is displayed. So let's look at what is in the "init" function? Expanded, it reads
function init(){
i=1;
while (document.getElementById("V.R"+i+".GALS")) {
obj1=document.getElementById("V.R"+i+".DATE");
obj1.onchange=fuelUsed;
obj2=document.getElementById("V.R"+i+".GALS");
obj2.onchange=fuelUsed;
i+=1;
}
fuelUsed();
}
The function initializes a local variable, "i", and sets it to "1". The
next line is a little odd if you haven't used Javascript before, but
believe me, it's one of the most powerful features of Javascript.
In the first iteration through the while
loop the line will readwhile (document.getElementById("V.R1.GALS")){
..do the loop
}
This while is testing for the existence
of an object with an ID of "V.R1.GALS". I don't have
to know in advance how many rows of the fuel table Alpha Five is passing to
the user's browser -- I can use this while
loop to run through the table. For each row in the table, I then
add an onchange event to the
cells that contain dates or fuel usage; if the user changes those
values, it will invoke the fuelUsed
function and recalculate the projections even before the new values are
saved. function fuelUsed(){
//initialize a few variables
var drivers="";
i=1;
var gals=0;
var rows=0;
// the while loop goes through the entire table
while (document.getElementById("V.R"+i+".GALS")) {
obj=document.getElementById("V.R"+i+".GALS");
/* check to see if a number is in the field, as opposed to a blank field
parseFloat() is a built-in Javascript function that tries to make a number out of
what it's been given. Therefore if parseFloat(obj.value) succeeds, it tests as true,
otherwise it returns something called NaN (Not a Number), or false.
I also use Javascript shorthand for addition, e.g.
rows=rows+1;
can be written in shorthand as
rows+=1;
*/
if (parseFloat(obj.value)){
rows+=1; // rows contains the number of non-empty rows
gals+=parseFloat(obj.value);
driver=document.getElementById("V.R"+i+".DRIVER").value;
/* I make up a string consisting of all the drivers separated by commas. If the
driver is not found in the string (tested with the indexOf built-in Javascript function),
then I add the driver to the string.
*/
if (drivers.indexOf(driver+",")==-1)
drivers+=driver+",";
}
i+=1;
} //end while
if (rows>0) {
obj1=document.getElementById("V.R1.DATE");
if (obj1){
startDate=new Date(obj1.value);
endDate=new Date(document.getElementById("V.R"+rows+".DATE").value);
/* Javascript has a built-in Date object, so we can get a date by feeding it
a string in a number of formats. Addition and subtraction of dates, though,
is done in milliseconds. When we subtract Javascript dates from one another, therefore,
we must divide by 1000*60*60*24 to get the actual number of days!
*/
diffDays=Math.abs((endDate-startDate)/(1000*60*60*24));
// now fill in the results
galObj=document.getElementById("gallons");
galObj.innerHTML=gals;
daysObj=document.getElementById("days");
daysObj.innerHTML=diffDays;
projectedObj=document.getElementById("projected");
/* Here we go. "innerHTML" is actually not standards-compliant scripting, but since all
browsers support it, I am using it here. It is a heck of a lot simpler to code with
"innerHTML" than it is to code with standards-compliant Javascript, which requires us to
add "nodes" to the "parent nodes" of objects. Ugh!
And "Math.round()" is a built-in Javascript function using the "Math object". Not
surprisingly, it rounds numbers to the nearest integer.
*/
projectedObj.innerHTML=Math.round(100*gals*365/diffDays)/100+" gallons";
/* I take the "drivers" list, which can look something like "2,1,", and put it in an
array called "drivArray" using the Javascript string-splitting function.
*/
drivArray=drivers.split(',');
// Here we use the 'innerHTML' again.
document.getElementById("breakdownLabel").innerHTML="Breakdown by driver:"
for (i=0;i<drivArray.length-1;i++) {
driverObject=new Object(); //create a new Object, like a pointer in Xbasic
driverObject.aDriver=drivArray[i];
driverObject.gals=0;
// I'll explain the next part separately below!
for (j=1;j<=rows;j++) {
driverObject.gals+=
document.getElementById("V.R"+j+".DRIVER").value ==
driverObject.aDriver?parseFloat(document.getElementById("V.R"+j+".GALS").value):0;
}
document.getElementById("breakdown").innerHTML+=
"<br />Driver "+driverObject.aDriver+": "+driverObject.gals+" gals.";
}
// if there are non-empty rows, then we display the "right" div
reslts=document.getElementById("right");
reslts.style.display=' block';
}
} else {
/* if there are no non-empty rows, e.g., only the Search part is active, then
don't display the "right" div
*/
reslts=document.getElementById("right");
reslts.style.display=' none';
}
}
for (j=1;j<=rows;j++) {
..some processing
}
This syntax is equivalent to the Xbasic syntax ofdriverObject.gals+=
document.getElementById("V.R"+j+".DRIVER").value ==
driverObject.aDriver?parseFloat(document.getElementById("V.R"+j+".GALS").value):0;
}
9/10/2005
Don't forget, we need your feedback to make this site better!