469,282 Members | 1,704 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,282 developers. It's quick & easy.

calculating in table made by createElement and appendChild

kie
hello,

i have a table that creates and deletes rows dynamically using
createElement, appendChild, removeChild.
when i have added the required amount of rows and input my data, i
would like to calculate the totals in each row.

when i try however, i receive the error:

"Error: 'elements[...]' is null or not an object"

i have tried looping through all elements in the form and this gives
me the name & value of each element.
when i call the element by name however, i receive the above error.

it is easier to explain by cuting and pasting the source of my html
file below:

i'd greatly appreciate any pointers, here's the code.
<script language="JavaScript" type="text/JavaScript" >
<!--

var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
var globalChanged = false;
var globalNewRowChanged = false;
var globalClaimLnsRowNum = 1;

function ex_amount(s_cur){
switch (s_cur)
{
case '1':
return '1.2';
break;
case '2':
return '0.6';
break;
case '3':
return '1.5';
break;
case '4':
return '2';
break;
case '5':
return '1';
break;
default:
return 0;
}
}

function detail_row(s_goods_id,s_unit_price,s_currency_id,s _quantity,s_uplift,s_total_line,s_incl_uplift,s_in cl_uplift_euro)
{
var body=document.body;
var Table,theRow,aCell,aTextBox,tablebody2,rowSec2;
var theTable;
var rowSec1,currenttext;
var opt1,sel2;
var cellSec1,cellSec2,cellSec3,cellSec4,cellSec5;
var cellSec6,cellSec7,cellSec8,cellSec9,cellSec10;
theTable=document.getElementById('formation').getE lementsByTagName('tbody')[0];
tablebody2 = document.createElement('TBODY');
rowSec2=document.createElement('TR');
cellSec2=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='2d_cmb_goods__' + globalClaimLnsRowNum;
opt1=document.createElement('option');
opt1.value='9';
if (opt1.value==s_goods_id){opt1.setAttribute('select ed',
true);}
opt1.innerHTML='Airconditioners';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='5';
if (opt1.value==s_goods_id){opt1.setAttribute('select ed',
true);}
opt1.innerHTML='Audio Goods';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='13';
if (opt1.value==s_goods_id){opt1.setAttribute('select ed',
true);}
opt1.innerHTML='Video Recorder';
sel2.appendChild(opt1);
cellSec2.appendChild(sel2);
rowSec2.appendChild(cellSec2);

cellSec3=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_unit_price);
aTextBox.size = '10';
aTextBox.name = '2d_txt_unit_price__' + globalClaimLnsRowNum;
cellSec3.appendChild(aTextBox);
rowSec2.appendChild(cellSec3);

cellSec4=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='2d_cmb_currency__' + globalClaimLnsRowNum;
opt1=document.createElement('option');
opt1.value='1';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',
true);}
opt1.innerHTML='US$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='2';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',
true);}
opt1.innerHTML='」STG';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='3';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',
true);}
opt1.innerHTML='A$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='4';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',
true);}
opt1.innerHTML='NZ$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='5';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',
true);}
opt1.innerHTML='BHAT';
sel2.appendChild(opt1);
cellSec4.appendChild(sel2);
rowSec2.appendChild(cellSec4);

cellSec5=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_quantity);
aTextBox.size = '5';
aTextBox.name = '2d_txt_quantity__' + globalClaimLnsRowNum;
cellSec5.appendChild(aTextBox);
rowSec2.appendChild(cellSec5);

cellSec6=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_total_line);
aTextBox.size = '5';
aTextBox.name = '2d_txt_total_line__' + globalClaimLnsRowNum;
cellSec6.appendChild(aTextBox);
rowSec2.appendChild(cellSec6);

cellSec7=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='2d_cmb_uplift__' + globalClaimLnsRowNum;
opt1=document.createElement('option');
opt1.value='100';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='100%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='105';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='105%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='110';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='110%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='0';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='other';
sel2.appendChild(opt1);
cellSec7.appendChild(sel2);
rowSec2.appendChild(cellSec7);

cellSec8=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_incl_uplift);
aTextBox.size = '3';
aTextBox.name = '2d_txt_incl_uplift__' + globalClaimLnsRowNum;
cellSec8.appendChild(aTextBox);
rowSec2.appendChild(cellSec8);

cellSec9=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_incl_uplift_euro);
aTextBox.name = '2d_txt_incl_uplift_euro__' +
globalClaimLnsRowNum;
aTextBox.size = '5';
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);}
cellSec9.appendChild(aTextBox);
rowSec2.appendChild(cellSec9);

cellSec10=document.createElement('TD');
ButtonSupprimer=document.createElement('input');
ButtonSupprimer.type = 'button';
ButtonSupprimer.value = 'remove';
ButtonSupprimer.onclick=function(){formation.remov eChild(tablebody2)}
cellSec10.appendChild(ButtonSupprimer);
rowSec2.appendChild(cellSec10);

tablebody2.appendChild(rowSec2);
formation.appendChild(tablebody2);
globalClaimLnsRowNum = globalClaimLnsRowNum + 1;
}

function calculateTab(n_line_no){

var oForm = document.forms[0];

alert('line number = ' + n_line_no);

oForm.elements['2d_txt_total_line__' + n_line_no].value =
nz(oForm.elements['2d_txt_unit_price__' + n_line_no].value) *
nz(oForm.elements['2d_txt_quantity__' + n_line_no].value);
}

function nz(s_val){
var s_datatype = "undefined";
if(s_val==null || s_val=='' || isNaN(s_val) ||
typeof(s_val)==s_datatype){
//return isNaN(num)?0:num;
return 0;
}
else{
//alert(s_val);
return parseFloat(s_val);
}
}

function resetForm(){
var oForm = document.forms[0];
for (i=0; i<oForm.elements.length; i++){
oForm.elements[i].value = "";
}
}

function setLabel(s_message,s_label_name) {
document.all(s_label_name).innerText = s_message;
}
//-->
</script>

<html>
<head>
</head>
<body>
<form method="post" action="" id="form1" name="form1">
<table>
<tr>
<td width='4%'>
<tr>
<td colspan='6'> </td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="button" name="Button2" value="change label"
onclick=setlabel('here is some different text','label_detail');>
</td>
<td><input type="button" name="Button" value="calculate"
onclick=calculateTab('1');></td>
<td colspan='1' align='right'>&nbsp;</td>
<td>
<input name='cmd_detail_new' type='button' id='cmd_detail_new'
value='add row [click here]' onclick=detail_row();>
</td>
<td>&nbsp;</td>
<td colspan='3' align='right'>total </td>
<td>
<input name='2d_txt_detail_total' type='text'
id='2d_txt_detail_total' value='' size='10'
onChange=document.forms[0].elements['txt_haschanged'].value ='yes';>
</td>
<td width='16%'>=EUR</td>
<td width='30%'>
<input name='2d_txt_detail_total_euro' type='text'
id='2d_txt_detail_total_euro' value='' size='10'
onChange=document.forms[0].elements['txt_haschanged'].value
='yes';></td>
</td>
</tr>
<tr>
<td colspan='6'></td>
</tr>
</table>
</td>
</tr>
</table>
<table>
<tr>
<td height='20' valign='top'>
<table width='100%' border='1' cellpadding='0' cellspacing='0'
valign='top' id='formation'>
<tr>
<td width='15%'>&nbsp;<b>GOODS</b></td>
<td width='5%'>&nbsp;<b>UNIT PRICE</b></td>
<td width='10%'>&nbsp;<b>CURRENCY</b></td>
<td width='5%'>&nbsp;<b>QUANTITY</b></td>
<td width='5%'>&nbsp;<b>TOTAL LINE</b></td>
<td width='5%'>&nbsp;<b>UPLIFT (%)</b></td>
<td width='5%'>&nbsp;<b>INCL. UPLIFT</b></td>
<td width='5%'>&nbsp;<b>=EUR</b></td>
<td width='5%'>&nbsp;<b>&nbsp;</b></td>
</tr>
<tr>
<td colspan='10'>
<label id='label_detail'>NO RECORDS FOUND</label>
</td>
</tr>
<input type='text' id='2d_txt_detail_ids'
name='2d_txt_detail_ids' value=''>
<input type='text' id='txt_update_ids' name='txt_update_ids'
value=''>
</table> </td>
</tr>
</table>
</form>
</body>
</html>
thanks for any help, kie

p.s. the funtion setLabel that addresses: <label id='label_detail'>
fails for a reason unknown to me, any pointers on this too would be
greatly appreciated.
Jul 20 '05 #1
25 4795
kie wrote:
i have a table that creates and deletes rows dynamically using
createElement, appendChild, removeChild.
when i have added the required amount of rows and input my data, i
would like to calculate the totals in each row.

when i try however, i receive the error:

"Error: 'elements[...]' is null or not an object"

i have tried looping through all elements in the form and this gives
me the name & value of each element.
when i call the element by name however, i receive the above error.

it is easier to explain by cuting and pasting the source of my html
file below:

i'd greatly appreciate any pointers, here's the code.

<snip>

hi Kie,
had a look and wrote down things as I encountered them. IE bug looks
like the biggest problem:

HTML:
Generally include script elements in the head section or (less often) in
the body section.
(moved script to head section when testing)

Element names beginning with "2d" are invalid HTML:
<cite>
ID and NAME tokens must begin with a letter ([A-Za-z]) and may be
followed by any number of letters, digits ([0-9]), hyphens ("-"),
underscores ("_"), colons (":"), and periods (".").
</cite>
(low priority in that it works in some browsers. Changed "2d" to "Two_d"
when testing)
Handler text used in HTML attribute values should be quoted
<cite>
In certain cases, authors may specify the value of an attribute without
any quotation marks. The attribute value may only contain letters (a-z
and A-Z), digits (0-9), hyphens (ASCII decimal 45), periods (ASCII
decimal 46), underscores (ASCII decimal 95), and colons (ASCII decimal
58). We recommend using quotation marks even when it is possible to
eliminate them.
</cite>
This rules out most javascript code.
(low priority in that it works in some browsers. Didn't change during test)

DOM errors:
To access elements by id, use document.getElementById.
Access using named properties of the window object is not standard.
Hence changed

theTable=document.getElementById('formation').getE lementsByTagName('tbody')[0];
to
var formation = document.getElementById('formation');
theTable=formation.getElementsByTagName('tbody')[0];
in order to allow later event handlers to access the formation value
held in the closure.
[This may set up memory leaks under IE. Walking the DOM in an
unbeforeunload handler and setting event handlers to null is one
possible workaround, although changing use of formation to
getElementById('formation') may be a better idea.]

Also changed setLabel use of document.all to document.getElementById.
Note that innerText is not a standard method of altering the text
content of element nodes. This has been covered in other posts with
bodies containing "createTextNode". Even "innerHTML" is more cross
browser compliant.
function setLabel(s_message,s_label_name) {
document.getElementById(s_label_name).innerHTML = s_message;
}
tested.

(priority for WWW documents)
Browser Detection
IE conditional comments can reliably check for Internet Explorer
(from Lasse Reichstein Nielsen, 27/9/03)

<script type="text/javascript">
var isIE = false;
</script>
<!--[if IE]>
<script type="text/javascript">
isIE = true;
</script>
<!--[end if]-->

Internet Explorer Bug
This is the killer. Form field elements added to the DOM are not
reflected as named properties of the FORM object. Code fix after adding
elements and before accessing them by name:

function makeFieldUnionByName(oEls, name)
{
var result = null;
var resultArray = false;
for( var i = 0; i < oEls.length; ++i)
{
if( oEls[i].name!=name)
continue;
if( result && !resultArray)
{ result = [result];
resultArray = true;
}
if(resultArray)
result[result.length]=oEls[i];
else
result=oEls[i];
}
return result;
}
function fixFormBug( oForm) // Internet Explorer only
{
var oEls = oForm.elements;
var name;
for( var i = 0; i < oEls.length; ++i)
{
name = oEls[i].name;
if(name && !oForm[ name])
oForm[name] = makeFieldUnionByName(oEls,name);
}
}
/* ....
and then in calculateTab
...
*/
var oForm = document.forms[0];
if(isIE)
fixFormBug( oForm)
...

Case Sensitivity
call setLabel using the same combination of case.
onchange="setLabel(....)"

========
HTH
Dom

Jul 20 '05 #2
kie
wow! Dom, that really helped me a lot.

what you said made sense and i can now calculate all the rows after
updating each cell. this is what i set out to do.

to increase efficiency i tried to calculate each row individually,
using the line: "aTextBox.onchange=function(){calculateTab(globalC laimLnsRowNum);}"
to send the current row number to the calculateTab function.
globalClaimLnsRowNum is a global variable though, so the value in
calculateTab is always the maximum value of globalClaimLnsRowNum. is
there a way to calculate a single row?

copy and pasting the below code will present an example, it also shows
dom's solutions in practice:

<html>
<head>
<script language="JavaScript" type="text/JavaScript" >
<!--

var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
var globalChanged = false;
var globalNewRowChanged = false;
var globalClaimLnsRowNum = 1;
var isIE = false;
// make check - find IE = true.
isIE = true;

function ex_amount(s_cur){
switch (s_cur)
{
case '1':
return '1.2';
break;
case '2':
return '0.6';
break;
case '3':
return '1.5';
break;
case '4':
return '2';
break;
case '5':
return '1';
break;
default:
return 0;
}
}

function detail_row(s_goods_id,s_unit_price,s_currency_id,s _quantity,s_uplift,s_total_line,s_incl_uplift,s_in cl_uplift_euro)
{
var body=document.body;
var Table,theRow,aCell,aTextBox,tablebody2,rowSec2;
var theTable;
var rowSec1,currenttext;
var opt1,sel2;
var cellSec1,cellSec2,cellSec3,cellSec4,cellSec5;
var cellSec6,cellSec7,cellSec8,cellSec9,cellSec10;
var formation = document.getElementById('formation');
theTable=formation.getElementsByTagName('tbody')[0];

tablebody2 = document.createElement('TBODY');
rowSec2=document.createElement('TR');
cellSec2=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='two_d_cmb_goods__' + globalClaimLnsRowNum;
sel2.onchange=function(){calculateTab(globalClaimL nsRowNum);}
opt1=document.createElement('option');
opt1.value='9';
if (opt1.value==s_goods_id){opt1.setAttribute('select ed',true);}
opt1.innerHTML='Airconditioners';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='5';
if (opt1.value==s_goods_id){opt1.setAttribute('select ed',true);}
opt1.innerHTML='Audio Goods';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='13';
if (opt1.value==s_goods_id){opt1.setAttribute('select ed',true);}
opt1.innerHTML='Video Recorder';
sel2.appendChild(opt1);
cellSec2.appendChild(sel2);
rowSec2.appendChild(cellSec2);

cellSec3=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_unit_price);
aTextBox.size = '10';
aTextBox.name = 'two_d_txt_unit_price__' + globalClaimLnsRowNum;
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);}
cellSec3.appendChild(aTextBox);
rowSec2.appendChild(cellSec3);

cellSec4=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='two_d_cmb_currency__' + globalClaimLnsRowNum;
sel2.onchange=function(){calculateTab(globalClaimL nsRowNum);}
opt1=document.createElement('option');
opt1.value='1';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',true);}
opt1.innerHTML='US$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='2';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',true);}
opt1.innerHTML='」STG';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='3';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',true);}
opt1.innerHTML='A$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='4';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',true);}
opt1.innerHTML='NZ$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='5';
if (opt1.value==s_currency_id){opt1.setAttribute('sel ected',true);}
opt1.innerHTML='BHAT';
sel2.appendChild(opt1);
cellSec4.appendChild(sel2);
rowSec2.appendChild(cellSec4);

cellSec5=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_quantity);
aTextBox.size = '5';
aTextBox.name = 'two_d_txt_quantity__' + globalClaimLnsRowNum;
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);}
cellSec5.appendChild(aTextBox);
rowSec2.appendChild(cellSec5);

cellSec6=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_total_line);
aTextBox.size = '5';
aTextBox.name = 'two_d_txt_total_line__' + globalClaimLnsRowNum;
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);}
cellSec6.appendChild(aTextBox);
rowSec2.appendChild(cellSec6);

cellSec7=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='two_d_cmb_uplift__' + globalClaimLnsRowNum;
sel2.onchange=function(){calculateTab(globalClaimL nsRowNum);}
opt1=document.createElement('option');
opt1.value='100';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='100%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='105';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='105%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='110';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='110%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='0';
if (opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='other';
sel2.appendChild(opt1);
cellSec7.appendChild(sel2);
rowSec2.appendChild(cellSec7);

cellSec8=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_incl_uplift);
aTextBox.size = '3';
aTextBox.name = 'two_d_txt_incl_uplift__' +
globalClaimLnsRowNum;
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);}
cellSec8.appendChild(aTextBox);
rowSec2.appendChild(cellSec8);

cellSec9=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_incl_uplift_euro);
aTextBox.name = 'two_d_txt_incl_uplift_euro__' +
globalClaimLnsRowNum;
aTextBox.size = '5';
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);}
cellSec9.appendChild(aTextBox);
rowSec2.appendChild(cellSec9);

cellSec10=document.createElement('TD');
ButtonSupprimer=document.createElement('input');
ButtonSupprimer.type = 'button';
ButtonSupprimer.value = 'remove';
ButtonSupprimer.onclick=function(){formation.remov eChild(tablebody2)}
cellSec10.appendChild(ButtonSupprimer);
rowSec2.appendChild(cellSec10);

tablebody2.appendChild(rowSec2);
formation.appendChild(tablebody2);
globalClaimLnsRowNum = globalClaimLnsRowNum + 1;
}

function calculateTab(n_line_no){

alert(n_line_no);

var oForm = document.forms[0];
var a_ids = new Array;
var j=0;
var s_cur = 0;
var n_uplift = 0;
var n_uplift_euro = 0;

if(isIE)
fixFormBug( oForm)

// make array of ids were dealing with
for (i=0; i<oForm.elements.length; i++){
if(oForm.elements[i].name.indexOf("two_d_") == 0){
if(oForm.elements[i].name.indexOf("two_d_cmb_goods__") == 0){
n = oForm.elements[i].name.replace(/two_d_cmb_goods__/g,'');
a_ids[j] = n;
j = j+1;
}
}
}

// use array of ids to calculate all values in all rows
for (i=0; i<j; i++){
oForm.elements['two_d_txt_total_line__' + a_ids[i]].value =
(parseFloat(nz(oForm.elements['two_d_txt_unit_price__' +
a_ids[i]].value)) * parseFloat(nz(oForm.elements['two_d_txt_quantity__'
+ a_ids[i]].value)));
oForm.elements['two_d_txt_incl_uplift__' + a_ids[i]].value =
(parseFloat(nz(oForm.elements['two_d_txt_total_line__' +
a_ids[i]].value)) * (parseFloat(nz(oForm.elements['two_d_cmb_uplift__'
+ a_ids[i]].value))/100));
oForm.elements['two_d_txt_incl_uplift_euro__' + a_ids[i]].value =
(parseFloat(oForm.elements['two_d_txt_incl_uplift__' +
a_ids[i]].value) * (ex_amount(oForm.elements['two_d_cmb_currency__' +
a_ids[i]].value)));
n_uplift = n_uplift + nz(oForm.elements['two_d_txt_incl_uplift__' +
a_ids[i]].value);
n_uplift_euro = n_uplift_euro +
nz(oForm.elements['two_d_txt_incl_uplift_euro__' + a_ids[i]].value);
}

// if currencies are not all equal, cannot show sum of incl. uplift,
only sum of euro
for (i=0; i<j; i++){
if((s_cur != oForm.elements['two_d_cmb_currency__' +
a_ids[i]].value) & (s_cur != 0)){
n_uplift = 0
break;
}
s_cur = oForm.elements['two_d_cmb_currency__' + a_ids[i]].value;
}

// assign total values
oForm.elements['two_d_txt_detail_total'].value = nz(n_uplift);
oForm.elements['two_d_txt_detail_total_euro'].value =
nz(n_uplift_euro);

}

function nz(s_val){
var s_datatype = "undefined";
if(s_val==null || s_val=='' || isNaN(s_val) ||
typeof(s_val)==s_datatype){
//return isNaN(num)?0:num;
return 0;
}
else{
//alert(s_val);
return parseFloat(s_val);
}
}

function resetForm(){
var oForm = document.forms[0];
for (i=0; i<oForm.elements.length; i++){
oForm.elements[i].value = "";
}
}

function setLabel(s_message,s_label_name) {
document.getElementById(s_label_name).innerHTML = s_message;
}
function makeFieldUnionByName(oEls, name)
{
var result = null;
var resultArray = false;
for( var i = 0; i < oEls.length; ++i)
{
if( oEls[i].name!=name)
continue;
if( result && !resultArray)
{ result = [result];
resultArray = true;
}
if(resultArray)
result[result.length]=oEls[i];
else
result=oEls[i];
}
return result;
}
function fixFormBug( oForm) // Internet Explorer only
{
var oEls = oForm.elements;
var name;
for( var i = 0; i < oEls.length; ++i)
{
name = oEls[i].name;
if(name && !oForm[ name])
oForm[name] = makeFieldUnionByName(oEls,name);
}
}
//-->
</script>

</head>
<body>
<form method="post" action="" id="form1" name="form1">
<table>
<tr>
<td width='4%'>
<tr>
<td colspan='6'> </td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type='button' name='Button2' value='change label'
onclick=setLabel('','label_detail');>
</td>
<td><input type="button" name="Button" value="calculate"
onclick=calculateTab(1);></td>
<td colspan='1' align='right'>&nbsp;</td>
<td>
<input name='cmd_detail_new' type='button' id='cmd_detail_new'
value='add row [click here]'
onclick=detail_row();setLabel('','label_detail');>
</td>
<td>&nbsp;</td>
<td colspan='3' align='right'>total </td>
<td>
<input name='two_d_txt_detail_total' type='text'
id='two_d_txt_detail_total' value='' size='10'
onChange=document.forms[0].elements['txt_haschanged'].value ='yes';>
</td>
<td width='16%'>=EUR</td>
<td width='30%'>
<input name='two_d_txt_detail_total_euro'
type='text'id='two_d_txt_detail_total_euro' value='' size='10'
onChange=document.forms[0].elements['txt_haschanged'].value='yes';></td>
</td>
</tr>
<tr>
<td colspan='6'></td>
</tr>
</table>
</td>
</tr>
</table>
<table>
<tr>
<td height='20' valign='top'>
<table width='100%' border='1' cellpadding='0' cellspacing='0'
valign='top' id='formation'>
<tr>
<td width='15%'>&nbsp;<b>GOODS</b></td>
<td width='5%'>&nbsp;<b>UNIT PRICE</b></td>
<td width='10%'>&nbsp;<b>CURRENCY</b></td>
<td width='5%'>&nbsp;<b>QUANTITY</b></td>
<td width='5%'>&nbsp;<b>TOTAL LINE</b></td>
<td width='5%'>&nbsp;<b>UPLIFT (%)</b></td>
<td width='5%'>&nbsp;<b>INCL. UPLIFT</b></td>
<td width='5%'>&nbsp;<b>=EUR</b></td>
<td width='5%'>&nbsp;<b>&nbsp;</b></td>
</tr>
<tr>
<td colspan='10'>
<label id="label_detail">NO RECORDS FOUND</label>
</td>
</tr>
<input type='text'
id='two_d_txt_detail_ids'name='two_d_txt_detail_id s' value=''>
<input type='text' id='txt_update_ids' name='txt_update_ids'
value=''>
</table> </td>
</tr>
</table>
</form>
</body>
</html>

thanks for any help,

kie
Jul 20 '05 #3
kie wrote:
i can now calculate all the rows after
updating each cell. this is what i set out to do.

to increase efficiency i tried to calculate each row individually, This might be useful, but be careful: if an existing row is changed, how
to make certain page totals are updated correctly?
using the line: "aTextBox.onchange=function(){calculateTab(globalC laimLnsRowNum);}"
to send the current row number to the calculateTab function.
globalClaimLnsRowNum is a global variable though, so the value in
calculateTab is always the maximum value of globalClaimLnsRowNum. is
there a way to calculate a single row?
You could determine the row number of an element which has changed by
assigning the TR in which it resides an id based on row number, and
searching for the TR and its id in the parentNode chain of an element.

After looking at the code further I noticed a few more things. For your
own interest I suggest placing doctype and character set definitions:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

at the start of the document and validating it at:
http://validator.w3.org


<html>
<head>
<script language="JavaScript" type="text/JavaScript" > Note the language attribute is deprecated:
<script type="text/javascript"> <!-- SGML comments can be omitted nowadays (unless you use a validation tool
that requires them)
var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1; This check is unreliable - apparently browsers forge the appName value
on a regular basis. var globalChanged = false;
var globalNewRowChanged = false;
var globalClaimLnsRowNum = 1;
var isIE = false;
// make check - find IE = true.
isIE = true;
uh huh :)
Okay, the page is under development and the real test goes in later...

<snip>

All the event handlers in detail_row retain the activation object of
detail_row() in scope and probably leak memory under IE6. I made some
static functions to replace the nested function versions (not shown,
they could go into a single object as properties to save on name space)

function calculateAll()
{
calculateTab(globalClaimLnsRowNum);
}

function removeRow() // method of form element within row
{
for( var node = this.parentNode; node; node=node.parentNode)
if(node.tagName=="TR")
break;
node.parentNode.removeChild(node);
calculateAll();
}

and in the editor replaced all
function(){calculateTab(globalClaimLnsRowNum);}
with
calculateAll;

Now comes the gritty bit. In the HTML code posted, you do not provide a
TBODY element before accessing it in code (so the browser must supply
it), and insert rows as TBODY elements. In testing, I inserted the
missing TBODY tag and started inserting and deleting TR elements, so a
few lines need changing:
function detail_row(s_goods_id,s_unit_price,s_currency_id,s _quantity,s_uplift,s_total_line,s_incl_uplift,s_in cl_uplift_euro)
{ ....
removed: // theTable=formation.getElementsByTagName('tbody')[0]; inserted:
var tablebody2=formation.getElementsByTagName('tbody')[0];
removed: // tablebody2 = document.createElement('TBODY');
....
aTextBox.onchange=function(){calculateTab(globalCl aimLnsRowNum);} This is one of the lines changed to
aTextBox.onchange=calculateAll;

....

Changed ButtonSupprimer.onclick=function(){formation.remov eChild(tablebody2)} to
ButtonSupprimer.onclick=removeRow;

....
After rowSec2.appendChild(cellSec10); inserted:
rowSec2.id = "row_" + globalClaimLnsRowNum; and after tablebody2.appendChild(rowSec2); removed: // formation.appendChild(tablebody2);
.... function fixFormBug( oForm) // Internet Explorer only
[A cautionary note on this code fix. As written, it patches an IE form
object after elements have been added, but makes no repairs if field
elements have been removed. In this particular case that should be not
be a problem, but would test submission]

....
The BODY used in testing (with various fixups) was:

<body>
<form method="post" action="" id="form1" name="form1">

<table>
<tbody>
<tr>
<td>&nbsp;</td>
<td>
<input type='button' name='Button2' value='change label'
onclick="setLabel('','label_detail');">
</td>
<td>
<input type="button" name="Button" value="calculate"
onclick="calculateTab(1);">
</td>
<td>&nbsp;</td>
<td>
<input name='cmd_detail_new' type='button' id='cmd_detail_new'
value='add row [click here]'
onclick="detail_row();setLabel('','label_detail'); ">
</td>
<td>&nbsp;</td>
<td align='right'>total </td>
<td>
<input name='two_d_txt_detail_total' type='text'
id='two_d_txt_detail_total' value='' size='10'
onchange="form.elements['txt_haschanged'].value ='yes';">
</td>
<td width='16%'>=EUR</td>
<td width='30%'>
<input name='two_d_txt_detail_total_euro' type='text'
id='two_d_txt_detail_total_euro' value='' size='10'
onchange="form.elements['txt_haschanged'].value='yes';">
</td>
</tr>
</tbody>
</table>

<!-- table in table removed, head and body elements inserted -->

<table width='100%' border='1' cellpadding='0' cellspacing='0'
valign='top' id='formation'>
<thead>
<tr>
<td width='15%'>&nbsp;<b>GOODS</b></td>
<td width='5%'>&nbsp;<b>UNIT PRICE</b></td>
<td width='10%'>&nbsp;<b>CURRENCY</b></td>
<td width='5%'>&nbsp;<b>QUANTITY</b></td>
<td width='5%'>&nbsp;<b>TOTAL LINE</b></td>
<td width='5%'>&nbsp;<b>UPLIFT (%)</b></td>
<td width='5%'>&nbsp;<b>INCL. UPLIFT</b></td>
<td width='5%'>&nbsp;<b>=EUR</b></td>
<td width='5%'>&nbsp;<b>&nbsp;</b></td>
</tr>
<tr>
<td colspan='9'>
<label id="label_detail">NO RECORDS FOUND</label>
</td>
</tr>

<!-- insert missing TR, TD tags, put spaces between attributes -->

<tr>
<td colspan='9'>
<input type='text' id='two_d_txt_detail_ids'
name='two_d_txt_detail_ids' value=''>
<input type='text' id='txt_update_ids'
name='txt_update_ids' value=''>
</td>
</tr>
</thead>

<tbody><!-- empty at this stage -->
</tbody>
</table>
</form>
</body>

========

Finally, if you want to find the row number from an event handler set on
element within a row, walk up the DOM to find the TR element (similar to
deleting a row) and extract the row number from the id value assigned in
detail_row().

HTH and good luck,
Dom

Jul 20 '05 #4
kie
thanks for your advice Dom, you're making a lot of things clearer for
me
After looking at the code further I noticed a few more things. For your
own interest I suggest placing doctype and character set definitions:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

at the start of the document and validating it at:
http://validator.w3.org


I have done this, one thing I noticed was that I couldn't control the
size of my select boxes:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<META http-equiv="Content-Type" content="text/html;
charset=ISO-8859-1">
<html>
<head>
<title>Untitled Document</title>
</head>
<body>
<SELECT id='test' name='test' style='width:50'>
<OPTION name='select one' value='' selected>
<OPTION name='1h_cmb_policy' value='YY10001878'>YY10001878
<OPTION name='1h_cmb_policy' value='YY10001884'>YY10001884
</OPTION>
</SELECT>
</body>
</html>

if I remove the first 2 lines from the code above, the select box will
become 50 pixels in width.
If I include the first 2 lines. the select box size is the width of
the longest string contained in it.

I tried adding the line:
"sel2.style.width ='100';"

after
rowSec2.id = 'row_' + globalClaimLnsRowNum;
cellSec2=document.createElement('TD');
and I had no problems.
Are the style.width used in createElement and the style='width:50' in
HTML much different commands?

I've been studying the code you used to restrict a loop to one row; by
copying the code from removeRow() into CalculateAll() I have tried and
failed to extract the row number or "TR" id

function calculateAll()
{
for( var node = this.parentNode; node; node=node.parentNode){
//if(node.tagName=="TR"){
//alert('node name and current row id: ' + node.Name);
//alert('node name and current row id: ' +
document.forms[0].elements.node.name);
//alert('node name and current row id: ' +
document.forms[0].elements[node].name);
//alert('node name and current row id: ' + node);
alert('node name and current row id: ' +
document.getElementById(node));
// }
}
calculateTab(2,globalClaimLnsRowNum);
}

I would expect that if "node" is an object, then it should have a
name. And I expected that name to be "row_1", "row_2" etc, from the
line:

"rowSec2.id = 'row_' + globalClaimLnsRowNum;"

am I mistaking "node" for an "element"? I have changed the attributes
of "TR" elements in the past using lines such as:

"document.getElementById(tdId).style.backgroundCol or = '#000000';"

With the "TBODY" element missing, the browser creates it. does that
mean before i was unnecesasarily creating a new "TBODY" element each
time the user clicks "Add Row"?
Memory dissipation is also halted by calling a function instead of
inserting the code into the elements onchange handler?

I need to find out more about nodes, apart from that it works great,
and is easier to understand now it is better laid out (below),

thanks again,

kie

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<META http-equiv="Content-Type" content="text/html;
charset=ISO-8859-1">
<html>
<head>
<meta name="Author" content="kie">
<meta name="Copyright" content="2003">
<meta name="keywords" content="">
<meta name="description" content="">
<link rel="stylesheet" type="text/css"
href="http://192.168.100.215/g-macs/lib/stylesheet.css">
<script>
<!--
// browser detection
// "InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;"
// This check is unreliable - apparently browsers forge the appName
value on a regular basis.
//
// checks should be made using the javascript that will be in the page
for certain safety
/**/
var s_browser = "";
// W3C & Netscape 6
if(document.getElementById) {
s_browser = "netscape6";
}
// browser is IE 4+:
else if (document.all) {
s_browser = "ie4";
}
// browser is Netscape 4+:
else if (document.layers) {
s_browser = "netscape4";
}
else {
s_browser = "";
}

//-->
</script>

<script type="text/javaScript" >
// JavaScript Document
// lib/js_functions.js - contents:

// setClaimID
// AllCheck_onclick
// mWillSave
// showHide
//calculateTab(3) used to calculate values in individual pages esp.
03_page.asp
<!--

var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
var globalChanged = false;
var globalNewRowChanged = false;
var globalClaimLnsRowNum = 1;
var isIE = false;

isIE = true;

function ex_amount(s_cur){
switch (s_cur)
{
case '1':
return '1.2';
break;
case '2':
return '0.6';
break;
case '3':
return '1.5';
break;
case '4':
return '2';
break;
case '5':
return '1';
break;
default:
return 0;
}
}

function detail_row(s_goods_id,s_unit_price,s_currency_id,s _quantity,s_uplift,s_total_line,s_incl_uplift,s_in cl_uplift_euro)
{
var body=document.body;
var Table,theRow,aCell,aTextBox,tablebody2,rowSec2;
var theTable;
var rowSec1,currenttext;
var opt1,sel2;
var cellSec1,cellSec2,cellSec3,cellSec4,cellSec5;
var cellSec6,cellSec7,cellSec8,cellSec9,cellSec10;
var formation = document.getElementById('formation');
var tablebody2=formation.getElementsByTagName('tbody')[0];
rowSec1=document.createElement('TR');
cellSec1=document.createElement('TD');
currenttext=document.createTextNode('Intitul');
rowSec2=document.createElement('TR');
rowSec2.id = 'row_' + globalClaimLnsRowNum;
cellSec2=document.createElement('TD');
sel2=document.createElement('select');
sel2.style.width ='100';
sel2.name='two_d_cmb_goods__' +
globalClaimLnsRowNum;
sel2.onchange=calculateAll;
opt1=document.createElement('option');
opt1.value='6';
if
(opt1.value==s_goods_id){opt1.setAttribute('select ed', true);}
opt1.innerHTML='Vacuum Cleaner';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='2';
if
(opt1.value==s_goods_id){opt1.setAttribute('select ed', true);}
opt1.innerHTML='Video Camera';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='1';
if
(opt1.value==s_goods_id){opt1.setAttribute('select ed', true);}
opt1.innerHTML='Video Recorder';
sel2.appendChild(opt1);
cellSec2.appendChild(sel2);
rowSec2.appendChild(cellSec2);

cellSec3=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_unit_price);
aTextBox.size = '10';
aTextBox.name = 'two_d_txt_unit_price__' +
globalClaimLnsRowNum;
aTextBox.onchange=calculateAll;
cellSec3.appendChild(aTextBox);
rowSec2.appendChild(cellSec3);

cellSec4=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='two_d_cmb_currency__' +
globalClaimLnsRowNum;
sel2.onchange=calculateAll
opt1=document.createElement('option');
opt1.value='1';
if
(opt1.value==s_currency_id){opt1.setAttribute('sel ected', true);}
opt1.innerHTML='US$';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='2';
if
(opt1.value==s_currency_id){opt1.setAttribute('sel ected', true);}
opt1.innerHTML='£STG';
sel2.appendChild(opt1);
sel2.appendChild(opt1);
cellSec4.appendChild(sel2);
rowSec2.appendChild(cellSec4);

cellSec5=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_quantity);
aTextBox.size = '5';
aTextBox.name = 'two_d_txt_quantity__' +
globalClaimLnsRowNum;
aTextBox.onchange=calculateAll
cellSec5.appendChild(aTextBox);
rowSec2.appendChild(cellSec5);

cellSec6=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_total_line);
aTextBox.size = '5';
aTextBox.name = 'two_d_txt_total_line__' +
globalClaimLnsRowNum;
aTextBox.onchange=calculateAll
cellSec6.appendChild(aTextBox);
rowSec2.appendChild(cellSec6);

cellSec7=document.createElement('TD');
sel2=document.createElement('select');
sel2.name='two_d_cmb_uplift__' +
globalClaimLnsRowNum;
sel2.onchange=function(){calculateTab(2,globalClai mLnsRowNum);}
opt1=document.createElement('option');
opt1.value='100';
if
(opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='100%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='105';
if
(opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='105%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='110';
if
(opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='110%';
sel2.appendChild(opt1);
opt1=document.createElement('option');
opt1.value='0';
if
(opt1.value==s_uplift){opt1.setAttribute('selected ', true);}
opt1.innerHTML='other';
sel2.appendChild(opt1);
cellSec7.appendChild(sel2);
rowSec2.appendChild(cellSec7);

cellSec8=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_incl_uplift);
aTextBox.size = '3';
aTextBox.name = 'two_d_txt_incl_uplift__' +
globalClaimLnsRowNum;
aTextBox.onchange=calculateAll
cellSec8.appendChild(aTextBox);
rowSec2.appendChild(cellSec8);

cellSec9=document.createElement('TD');
aTextBox=document.createElement('input');
aTextBox.type = 'text';
aTextBox.value = nz(s_incl_uplift_euro);
aTextBox.name = 'two_d_txt_incl_uplift_euro__' +
globalClaimLnsRowNum;
aTextBox.size = '5';
aTextBox.onchange=calculateAll
cellSec9.appendChild(aTextBox);
rowSec2.appendChild(cellSec9);

cellSec10=document.createElement('TD');
ButtonSupprimer=document.createElement('input');
ButtonSupprimer.type = 'button';
ButtonSupprimer.value = 'remove';
ButtonSupprimer.onclick=removeRow;
cellSec10.appendChild(ButtonSupprimer);
rowSec2.appendChild(cellSec10);
tablebody2.appendChild(rowSec2);
formation.appendChild(tablebody2);
globalClaimLnsRowNum = globalClaimLnsRowNum + 1;
}

function calculateTab(n_tab_no,n_line_no){

var oForm = document.forms[0];
var n;
var t;
var a_ids = new Array;
var j=0;

switch (n_tab_no)
{
case 1: // header
break;
case 2: // detail

var s_cur = 0;
var n_uplift = 0;
var n_uplift_euro = 0;

if(s_browser = "ie4"){
fixFormBug(oForm)
}

// make array of ids were dealing with
for (i=0; i<oForm.elements.length; i++){
if(oForm.elements[i].name.indexOf("two_d_") == 0){
if(oForm.elements[i].name.indexOf("two_d_cmb_goods__") == 0){
n = oForm.elements[i].name.replace(/two_d_cmb_goods__/g,'');
a_ids[j] = n;
j = j+1;
}
}
}

// use array of ids to calculate all values in all rows
for (i=0; i<j; i++){
//alert(n_tab_no+' ' +n_line_no + ' ' + a_ids[i]);
oForm.elements['two_d_txt_total_line__' + a_ids[i]].value =
(parseFloat(nz(oForm.elements['two_d_txt_unit_price__' +
a_ids[i]].value)) * parseFloat(nz(oForm.elements['two_d_txt_quantity__'
+ a_ids[i]].value)));
oForm.elements['two_d_txt_incl_uplift__' + a_ids[i]].value =
(parseFloat(nz(oForm.elements['two_d_txt_total_line__' +
a_ids[i]].value)) * (parseFloat(nz(oForm.elements['two_d_cmb_uplift__'
+ a_ids[i]].value))/100));
oForm.elements['two_d_txt_incl_uplift_euro__' + a_ids[i]].value =
(parseFloat(oForm.elements['two_d_txt_incl_uplift__' +
a_ids[i]].value) * (ex_amount(oForm.elements['two_d_cmb_currency__' +
a_ids[i]].value)));
n_uplift = n_uplift + nz(oForm.elements['two_d_txt_incl_uplift__'
+ a_ids[i]].value);
n_uplift_euro = n_uplift_euro +
nz(oForm.elements['two_d_txt_incl_uplift_euro__' + a_ids[i]].value);
}

// if currencies are not all equal, cannot show sum of incl.
uplift, only sum of euro
for (i=0; i<j; i++){
if((s_cur != oForm.elements['two_d_cmb_currency__' +
a_ids[i]].value) & (s_cur != 0)){
n_uplift = 0
break;
}
s_cur = oForm.elements['two_d_cmb_currency__' + a_ids[i]].value;
}

// assign total values
oForm.elements['two_d_txt_detail_total'].value = nz(n_uplift);
oForm.elements['two_d_txt_detail_total_euro'].value =
nz(n_uplift_euro);
break;
case 3: // pay rec
break;
case 4: // banking
break;
case 5: // p uk
break;
default:
false;
}
}

function makeFieldUnionByName(oEls, name)
{
var result = null;
var resultArray = false;
for( var i = 0; i < oEls.length; ++i)
{
if( oEls[i].name!=name)
continue;
if( result && !resultArray)
{ result = [result];
resultArray = true;
}
if(resultArray)
result[result.length]=oEls[i];
else
result=oEls[i];
}
return result;
}

function fixFormBug(oForm) // Internet Explorer only
{
var oEls = oForm.elements;
var name;
for( var i = 0; i < oEls.length; ++i)
{
name = oEls[i].name;
if(name && !oForm[ name])
oForm[name] = makeFieldUnionByName(oEls,name);
}
}

function calculateAll()
{
for( var node = this.parentNode; node; node=node.parentNode){
//if(node.tagName=="TR"){
//alert('node name and current row id: ' + node.Name);
//alert('node name and current row id: ' +
document.forms[0].elements.node.name);
//alert('node name and current row id: ' +
document.forms[0].elements[node].name);
//alert('node name and current row id: ' + node);
alert('node name and current row id: ' +
document.getElementById(node));
// }
}
calculateTab(2,globalClaimLnsRowNum);
}

function removeRow() // method of form element within row
{
for( var node = this.parentNode; node; node=node.parentNode)
if(node.tagName=="TR")
break;
node.parentNode.removeChild(node);
calculateAll();
}
function nz(s_val){
var s_datatype = "undefined";
if(s_val==null || s_val=='' || isNaN(s_val) ||
typeof(s_val)==s_datatype){
//return isNaN(num)?0:num;
return 0;
}
else{
//alert(s_val);
return parseFloat(s_val);
}
}

function setLabel(objectId,s_label_name,is_element) {
if (is_element=='true'){
var n=document.all(objectId).length;
for(i=0;i<n;++i) {
if(document.all(objectId).options[i].selected) {
document.all(s_label_name).innerText =
document.all(objectId).options[i].text;
}
}
}else{
document.getElementById(s_label_name).innerHTML = objectId;
}
}
//-->
</script>

</HEAD>
<BODY>
<form method="post" action="" id="form_h" name="form_h">
<table>
<tr>
<td width='4%'>
<tr>
<td colspan='6'> </td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
</td>
<td>&nbsp;</td>
<td colspan='1' align='right'>&nbsp;</td>
<td>
<input name='cmd_detail_new' type='button'
id='cmd_detail_new' value='ADD DETAIL [CLICK HERE]'
onclick=detail_row();>
</td>
<td>&nbsp;</td>
<td colspan='3' align='right'>DETAIL TOTAL / LOCAL </td>
<td>
<input name='two_d_txt_detail_total' type='text'
id='two_d_txt_detail_total' value='' size='10'>
</td>
<td width='16%'>=EUR</td>
<td width='30%'>
<input name='two_d_txt_detail_total_euro' type='text'
id='two_d_txt_detail_total_euro' value='' size='10'></td>
</td>
</tr>
<tr>
<td colspan='6'></td>
</tr>
</table>
</td>
</tr>
</table>
<table>
<tr>
<td height='20' valign='top'>
<table width='100%' border='1' cellpadding='0' cellspacing='0'
valign='top' id='formation'>
<thead>
<tr>
<td width='15%'>&nbsp;<b>GOODS</b></td>
<td width='5%'>&nbsp;<b>UNIT PRICE</b></td>
<td width='10%'>&nbsp;<b>CURRENCY</b></td>
<td width='5%'>&nbsp;<b>QUANTITY</b></td>
<td width='5%'>&nbsp;<b>TOTAL LINE</b></td>
<td width='5%'>&nbsp;<b>UPLIFT (%)</b></td>
<td width='5%'>&nbsp;<b>INCL. UPLIFT</b></td>
<td width='5%'>&nbsp;<b>=EUR</b></td>
<td width='5%'>&nbsp;<b>&nbsp;</b></td>
</tr>
<thead>
<tbody>
<tr>
<td colspan='10'>
<label id='label_detail'>NO RECORDS FOUND</label>
</td>
</tr>
</tbody>
<input type='hidden' id='two_d_txt_detail_ids'
name='two_d_txt_detail_ids' value=''>
<input type='hidden' id='txt_update_ids' name='txt_update_ids'
value=''>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>
Jul 20 '05 #5
ki*****@yahoo.com (kie) writes:

[adding DOCTYPE that selects standard mode]
I have done this, one thing I noticed was that I couldn't control the
size of my select boxes:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
.... <SELECT id='test' name='test' style='width:50'>
In CSS, all (non-zero) lengths must have a unit. In this case, I assume
you mean 50 pixels, so it should be "style='width:50px'".

I quirks mode, browsers allow some errors, and missing units is one of
them. It is still illegal CSS.
if I remove the first 2 lines from the code above, the select box will
become 50 pixels in width.
Yes, because the browser humors you instead of following standards.

.... I tried adding the line:
"sel2.style.width ='100';"
That is no better. It should still be '100px'.
Are the style.width used in createElement and the style='width:50' in
HTML much different commands?


No, they are completely equivalent. The elem.style property corresponds
directly with the style attribute in HTML.

Still, the browser might be more linient in Javascript than in the
HTML/CSS parser.

(That was a lot of code to post!)
/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 20 '05 #6
kie wrote:

<snip>
I have tried and failed to extract the row number or "TR" id

function calculateAll()
{
for( var node = this.parentNode; node; node=node.parentNode){
//if(node.tagName=="TR"){
//alert('node name and current row id: ' + node.Name);
//alert('node name and current row id: ' +
document.forms[0].elements.node.name);
//alert('node name and current row id: ' +
document.forms[0].elements[node].name);
//alert('node name and current row id: ' + node);
alert('node name and current row id: ' +
document.getElementById(node));
// }
}
calculateTab(2,globalClaimLnsRowNum);
}

I would expect that if "node" is an object, then it should have a
name. And I expected that name to be "row_1", "row_2" etc, from the
line:

"rowSec2.id = 'row_' + globalClaimLnsRowNum;"

am I mistaking "node" for an "element"? I have changed the attributes
of "TR" elements in the past using lines such as:

"document.getElementById(tdId).style.backgroundCol or = '#000000';"

"node" refers to the primary datatype of objects in the DOM which
support the Node interface, described in W3C DOM recommendations [1]. In
the above code, the variable named "node" simply means a DOM node
without regard to whether it is an element or something else (document,
text node, document fragment or whatever).

An element is a *node* which supports the Element interface. Elements
correspond to HTML tags. Under the Element interface the tag name is
available as node.tagName. Under the node interface of an element, the
tag name is also availabe as node.nodeName. A subtle difference is that
node.tagName is undefined on nodes which are *not* elements.

Name and id are separate attributes of element nodes, so if row number
information has been placed in the id attribute, id would be used to
retrieve it as in:

function getRowNumber(element) // for element within row id "row_xxxx"
{
for( var node = element.parentNode; node; node=node.parentNode)
{ if(node.tagName == "TR")
return + node.id.substring(4);
}
}

[The unary plus operator applied to a string is equivalent to
parseFloat(string,10)]

With the "TBODY" element missing, the browser creates it. does that
mean before i was unnecesasarily creating a new "TBODY" element each
time the user clicks "Add Row"? That is something only you can answer - yes I assumed inserting multiple
TBODY elements was unnecessary, but didn't look up the HTML DTD either:
<cite>
<!ELEMENT TABLE - -
(CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>
</cite>
which says one or more TBODY elements are permitted.
Memory dissipation is also halted by calling a function instead of
inserting the code into the elements onchange handler? True to the extent that multiple function objects and closures are not
created. The main reason for the suggestion, however, was to avoid
memory leaks in IE6. These are caused by *circular* references between
document nodes and javascript. The scope chain of a nested function
(assigned as an event handler) contains the activation object of the
call to its outer function, so if variables of the outer function refer
back to the DOM node, the circle is complete.

For example,

function detail_row(s_goods_ ...

var sel2; ...

sel2.onchange=function(){calculateTab(2,globalClai mLnsRowNum);}

is prime suspect material.

An alternative solution to your problem occured to me after the original
reply. Why not use a static *factory* function to create a handler,
which can pass a line number and avoid the requirement for an id value
on the TR. Untested, but along lines of

function calculateCall( tab_no, line_no)
{
return function(){ calculateTab(tab_no, line_no)}
}

and then

sel2.onchange = calculateCall( 2, globalClaimLnsRowNum);

on the understanding of that calculateTab would receive
globalClaimLnsRowNum as at the time calculateCall was called, not as
updated afterwards.

This approach will create multiple function objects and closures, but at
least they are on the smallish side :)

I need to find out more about nodes,
[1].
thanks again, You're welcome. As Lasses noted for the style-pixel-width question, the
amount of code has become excessive for email posting [2]. Providing a
URL or posting separate cut-down code and code usage questions is the
way to go.

<snip>
var s_browser = "";
// W3C & Netscape 6
if(document.getElementById) {
s_browser = "netscape6";
}
// browser is IE 4+:
else if (document.all) {
s_browser = "ie4";
}
// browser is Netscape 4+:
else if (document.layers) {
s_browser = "netscape4";
}
else {
s_browser = "";
}

An observation: page design and code are unlikely to ever work in
browsers lacking document.getElementById support. IIRC, IE4 does not
support nested functions, and NS4 does not support layers within forms
(forms within layers are ok).

<snip> </tbody>
<input type='hidden' id='two_d_txt_detail_ids'
name='two_d_txt_detail_ids' value=''>
<input type='hidden' id='txt_update_ids' name='txt_update_ids'
value=''>
</table>


INPUT elements are not amongst the permitted child elements of TABLE.
Basically they go outside all tables or within TD cells.

Happy testing,
Dom
==============
[1] W3C
<URL http://www.w3.org/TR/DOM-Level-2-Core >
<URL http://www.w3.org/TR/DOM-Level-2-HTML >
[2] Newgroup FAQ:
<URL: http://www.jibbering.com/faq/ >

Jul 20 '05 #7
Lasse Reichstein Nielsen wrote:

<snip>


No, they are completely equivalent. The elem.style property corresponds
directly with the style attribute in HTML.

Still, the browser might be more linient in Javascript than in the
HTML/CSS parser.


Mozilla (at least) has an "almost" standards mode [1], triggered by the
HTML loose DTD, which IIRC permits setting dimensions as pixels by
default from within javascript as for NS4. Using the strict DTD triggers
full standards mode and ignores dimensions without unit values.

Also, thanks for the tip about IE conditional comments [2]. For
accuracy, the end comment uses the form:
<![endif]-->
which certainly wasn't my first guess :)

cheers,
Dom

=======
[1]
http://msdn.microsoft.com/library/de...omment_ovw.asp


Jul 20 '05 #8
JRS: In article <7H*******************@nnrp1.ozemail.com.au>, seen in
news:comp.lang.javascript, Dom Leonard <do*************@senet.andthis.co
m.au> posted at Sun, 14 Sep 2003 04:01:55 :-

[The unary plus operator applied to a string is equivalent to
parseFloat(string,10)]


It is not equivalent. Consider the string "3k".

It is true that, in many cases where a programmer uses parseFloat, unary
+ would be better. "3l" should generally give an error, not 3.

And parseFloat only uses one argument.

--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME. ©
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
Proper <= 4-line sig. separator as above, a line exactly "-- " (SonOfRFC1036)
Do not Mail News to me. Before a reply, quote with ">" or "> " (SonOfRFC1036)
Jul 20 '05 #10
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
JRS: In article <7H*******************@nnrp1.ozemail.com.au>, seen in
news:comp.lang.javascript, Dom Leonard <do*************@senet.andthis.co
m.au> posted at Sun, 14 Sep 2003 04:01:55 :-

[The unary plus operator applied to a string is equivalent to
parseFloat(string,10)]


It is not equivalent. Consider the string "3k".


Yes, unary plus is equivalent to the function "Number" (not used as a
constructor). The "Number" conversion function works exactly like the
automatic type conversions induced by operators, which is what unary
plus is (just like Boolean is equivalent to double-negation and the
implicit conversion performed by conditionals).

I can't really find a reason to use parseInt or parseFloat.

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 20 '05 #11
Dom Leonard wrote:
function fixFormBug( oForm) // Internet Explorer only

[A cautionary note on this code fix. As written, it patches an IE form
object after elements have been added, but makes no repairs if field
elements have been removed. In this particular case that should be not
be a problem, but would test submission]


This has gone further. Testing shows what looks like two closely related
problems when inserting form field elements using DOM methods under IE:

Problem 1
==========

Form field elements given a "name" attribute alone (without an "id"),
are not made named properties of the FORM object when a field is
inserted into the document using appendChild().

The lack of the FORM property does not seem to upset form submission,
just programatic access to the fields. This problem occurs outside
tables so does not appear to be related to table usage in test code.

Providing an "id" attribute with the same value as the "name" attribute
of field elements appears to fix the problem, and is the work around I
would now suggest. It will not work, of course, for multiple field
elements, such as radio inputs, sharing the same name.

Problem 2
==========

Only the first radio inputs added to a FORM using appendChild() can be
navigated to using the keyboard. Any additional (radio) inputs can not
be set by clicking. Basically no radio group is created, and setting a
FORM property to an array of radio inputs sharing the same name fails to
improve the situation.

The only work around I could devise for this was to create radio inputs
by inserting HTML code into the innerHTML property of an outer element.

===========

Because of these findings, as well as the lack of handling for form
field deletes, I can only describe the fixFormBug() function as
intermediate test code. Kie, I would suggest monitoring this thread to
see if better solutions are proposed, but if not to remove the
fixFormBug code and supply id as well as name values for the form field
elements.

best regards,
Dom

====== cut down test code =======

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>IE6 DHTML Form Element test</title>

<script type="text/javascript">

var rowCount=0;

function addRow( form)
{
var tbody = document.getElementById("tableBody");
var tr = document.createElement("TR");
var td = document.createElement("TD");
var oText;
var oRadio;
var radioInnerHTML = "";
var oSel, oOpt;
var useInnerHTML = form.useInnerHTML.checked;
var includeId = form.includeId.checked;

oText = document.createElement("INPUT");
oText.type="text";
oText.name="text" + rowCount;
if(includeId)
oText.id = "text" + rowCount; // same as name
oText.value=rowCount;

if(useInnerHTML)
{ radioInnerHTML =
'<input type="radio" name="radioGroup" '
+ ' id="radio' + rowCount + '"'
+ ' value="radio' + rowCount + '"'
+ (rowCount ? "" : " checked")
+ ">";
}
else
{ oRadio = document.createElement("INPUT");
oRadio.name="radioGroup";
oRadio.type="radio";
oRadio.id = "radio" + rowCount;
oRadio.value = oRadio.id; // always set radio id
if(rowCount==0)
{ oRadio.defaultChecked = true; // ??
oRadio.checked = true;
}
else
oRadio.checked = false;
oRadio.disabled=false;
}

oSel = document.createElement("SELECT");
oSel.name = "sel" + rowCount;
if(includeId)
oSel.id = "sel" + rowCount;
oOpt = document.createElement("OPTION");
oOpt.innerHTML = "option1";
oOpt.value="opt1";
oSel.appendChild(oOpt);
oOpt = document.createElement("OPTION");
oOpt.innerHTML = "option2";
oOpt.value = "opt2";
oSel.appendChild(oOpt);

tbody.appendChild(tr);
tr.appendChild(td);
if(useInnerHTML)
td.innerHTML = radioInnerHTML;
else
td.appendChild(oRadio);
td.appendChild(oText);
td.appendChild(oSel);
alert("td.innerHTML: " + td.innerHTML);

++rowCount;
}
function checkForm( form)
{
var oEls = form.elements;
var el;
var msg;
for( var i = 0; i < oEls.length; ++i)
{
el = oEls[i];
if(el.tagName == "OPTION")
continue; // ignore for now
if(el.className == "test")
continue; // part of test chrome
if(el.id && !form[el.id])
alert("element with id " + el.id + " not in FORM");
if(el.name && !form[el.name])
{ msg = "element with name " + el.name + " not in FORM";
if(el.name && !oEls[el.name])
msg+="\nit is not a named property of the elements array
either";
if(el.id && form[el.id])
msg+="\nit IS in the FORM under it's id of " + el.id;
alert(msg);
}
if(!(el.name || el.id))
alert( el.tagName + " [type=" + el.type + "] "
+ "value: " + el.value + "without name or id encountered");
}
}

function makeFieldUnionByName(oEls, name)
{
var result = null;
var resultArray = false;
for( var i = 0; i < oEls.length; ++i)
{
if( oEls[i].name!=name)
continue;
if( result && !resultArray)
{ result = [result];
resultArray = true;
}
if(resultArray)
result[result.length]=oEls[i];
else
result=oEls[i];
}
return result;
}
function fixFormBug( oForm) // Internet Explorer only
{
var oEls = oForm.elements;
var name;
for( var i = 0; i < oEls.length; ++i)
{
name = oEls[i].name;
if(name && !oForm[ name])
oForm[name] = makeFieldUnionByName(oEls,name);
}
}
</script>
</head>
<body>
<p>Reload the page if changing check box values.
</p>
<p>Clicking "check Form" should produce no alerts. Mozilla and Opera pass.
</p>
<p>Clicking "test Form Fix" before "check Form" suppresses alerts in IE
but doesn't fix radio group behavior.
</p>
<hr>
<form name="testForm" action="test.html">

<!-- form field used as test controls have class "test" -->

<input type="checkbox" name="includeId" class="test">
include id attribute on text/select INPUT elements<br>
<input type="checkbox" name="useInnerHTML" class="test">
use innerHTML for radio inputs<br>

<button type="button" onclick="addRow(this.form)" class="test">add
row</button>
<button type="button" onclick="checkForm(this.form)" class="test">check
Form</button>
<button type="button" onclick="fixFormBug(this.form)" class="test">test
form fix</button>
<input type="submit" value="submit" class="test">
<table>
<tbody id="tableBody">

<tbody>
</table>

</form>

</body>
</html>

Jul 20 '05 #12
kie
thanks Lasse,

an add on of 'px' makes all the difference! something simple that i
haven't been practicing, but will from now on. including the use of:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">


at the top of all my HTML. do you and other developers you know use
'loose' or 'strict' as a rule of thumb?

with browsers allowing users such as myself to get away with emitting
cetain code, bad habits can be made. i wonder, does 'relaxed' coding
slow the browser down? or just make the page incompatible with less
tolerant browsers?

thanks for the tips,

kie
Jul 20 '05 #13
ki*****@yahoo.com (kie) writes:
at the top of all my HTML. do you and other developers you know use
'loose' or 'strict' as a rule of thumb?
I am not sure I would consider myself a "developer" with the (low)
number of pages I have made. But I do use "strict" whenever possible.
with browsers allowing users such as myself to get away with emitting
cetain code, bad habits can be made. i wonder, does 'relaxed' coding
slow the browser down? or just make the page incompatible with less
tolerant browsers?


I doubt it is slower. Most browsers are very tolerant of user mistakes
(they have to be with the amount of crap HTML out there), so that is
probably not a problem either (i.e., I don't know of a less tolerant
browser that doesn't understand HTML 4).

I always use the optional end tags, always quote attribute values, and
try to go strict by the standards, even where browsers don't require it.
That is just how I am. :) I follow standards very strictly because I
believe it to make code that is less error prone and more maintainable
in the long run.

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 20 '05 #14
JRS: In article <ll**********@hotpop.com>, seen in
news:comp.lang.javascript, Lasse Reichstein Nielsen <lr*@hotpop.com>
posted at Sun, 14 Sep 2003 18:24:54 :-
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
JRS: In article <7H*******************@nnrp1.ozemail.com.au>, seen in
news:comp.lang.javascript, Dom Leonard <do*************@senet.andthis.co
m.au> posted at Sun, 14 Sep 2003 04:01:55 :-
>
>[The unary plus operator applied to a string is equivalent to
>parseFloat(string,10)]


It is not equivalent. Consider the string "3k".


Yes, unary plus is equivalent to the function "Number" (not used as a
constructor). The "Number" conversion function works exactly like the
automatic type conversions induced by operators, which is what unary
plus is (just like Boolean is equivalent to double-negation and the
implicit conversion performed by conditionals).

I can't really find a reason to use parseInt or parseFloat.


Use parseInt for bases other than 10 (not needed for 0x<hex>).
Use parseInt to truncate a decimal part.

Use either if the string may contain non-whitespace to be ignored after
the numeric part.

Unary +, being stricter in what it accepts, is safer.
Math.floor(+value) is only a little longer than parseInt(value).

--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4 ©
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> JS maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/JS/&c., FAQ topics, links.
Jul 20 '05 #15
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
JRS: In article <ll**********@hotpop.com>, seen in
news:comp.lang.javascript, Lasse Reichstein Nielsen <lr*@hotpop.com>
I can't really find a reason to use parseInt or parseFloat.


Use parseInt for bases other than 10 (not needed for 0x<hex>).


Not neede for 0<octal> either, but that is a good point.
Use parseInt to truncate a decimal part.
Math.floor is build to do just that.
Use either if the string may contain non-whitespace to be ignored after
the numeric part.


If you were actually making a parser, that could be useful, but *only*
if you knew how many characters were used. However, parseInt and
parseFloat does not tell you that, and leaves no way to find out. So,
if you are parsing, you will have to find the length of the numeric
part of the string anyway ... and then you don't need parseInt/Float.

That was what I was thinking of, when I discounted parseInt/Float. I
can see that parseInt has a use in converting from different
non-standard bases.

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 20 '05 #16
JRS: In article <sm**********@hotpop.com>, seen in
news:comp.lang.javascript, Lasse Reichstein Nielsen <lr*@hotpop.com>
posted at Mon, 15 Sep 2003 20:07:47 :-
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
JRS: In article <ll**********@hotpop.com>, seen in
news:comp.lang.javascript, Lasse Reichstein Nielsen <lr*@hotpop.com>

>I can't really find a reason to use parseInt or parseFloat.


Use parseInt for bases other than 10 (not needed for 0x<hex>).


Not neede for 0<octal> either, but that is a good point.


As a code literal, 033 & +033 are twenty-seven; but +'033' is thirty-
three (and 0x33, +0x33, & +'0x33' are all fifty-one).

For input by non-programmers, it is more likely that 033 means thirty-
three than twenty-seven; +<string> gets it right.

Number('033') is thirty-three; Number('0x33') is fifty-one.

AFAICS, therefore there is no way for a string to say that, interpreted
numerically, it is Octal; but it can claim to be Hex with 0x.


It's a pity that +078 - +077 gives fifteen, when written in code.

It's a pity that a digit string that looks, to a layman, like a decimal
number can ever be interpreted otherwise.

But it does seem that, from outside the coding, leading zeroes do not
octalize.

Or is it different in other browsers?

--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4 ©
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> JS maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/JS/&c., FAQ topics, links.
Jul 20 '05 #17
kie
i see,

i always use id when making input elements in plain HTML so that they
can be picked up by getElementById() among other things. Leaving it
out meant that lines such as:

"oForm.elements['text_box'].value" inside the calculation function
failed.

so when using the above line, it must always be calling on the id of
an element for the value, and not the name?

it's a great test script Dom, i need to look at it further to get my
head around the radio button problem. i had't tried testing radio
buttons.

thanks!, kie
Jul 20 '05 #18
kie wrote:

i always use id when making input elements in plain HTML so that they
can be picked up by getElementById() among other things. Leaving it
out meant that lines such as:

"oForm.elements['text_box'].value" inside the calculation function
failed.

so when using the above line, it must always be calling on the id of
an element for the value, and not the name?

It depends on context. In older browsers, named lookup on the elements
collection returned a field element by name - id values were not even
implemented. In current browsers it should preferentially return an
element with id matching the string supplied for lookup, or if no id is
matched, a field element with name value matching the supplied string.

Some testing suggests, however, that form submission is performed using
element *name* values - they can't be left out simply because id has
been supplied for element access. This is why the work around suggested
for IE behavior is to supply id attributes with the same value as the
name attribute on field elements added programatically.

cheers,
Dom

Jul 20 '05 #19
kie
following on from the subject of assigning events to dynamically
created elements, i would like to ask some advice on how to assertain
when there is only one row in the table.

using a button marked 'remove row' a user can remove dynamic rows in a
table until there are none left

(see http://www.kieran.f2s.com/removeChild/working.htm)

i would like to inform the user that they are attempting to remove the
last row, and disallow the attempt.

i want to create a universal function, triggered from the onclick
event of the 'remove row' button.

so far my best attempt is to pass the element name of the button to
the function and search in all elements:

function removeRow(s_element_name) // method of form element within
row
{
//alert();
var oForm = document.forms[0];
var n = 0;

//if row is last row, it cannot be deleted

for (i=0; i<oForm.elements.length; i++){
//alert(oForm.elements[i].name);
if(oForm.elements[i].name.indexOf(s_element_name) == 0){
n += 1;
//alert(oForm.elements[i].name);
}
}
//alert(n);
if(n = 1){
for( var node = this.parentNode; node; node=node.parentNode)
if(node.tagName=="TR")
break;
node.parentNode.removeChild(node);
calculateTab(2,0);
}else{
alert('Cannot remove last remaining row');
}
}

(see http://www.kieran.f2s.com/removeChild/attempt.htm for a failing
example of this)

if you have any ideas on a better way to do this, please add it to
this thread,

kind regards, kie
Jul 20 '05 #20
ki*****@yahoo.com (kie) writes:
following on from the subject of assigning events to dynamically
created elements, i would like to ask some advice on how to assertain
when there is only one row in the table.
If you have a reference to the table, it is easy:
tableRef.rows.length == 1
if(n = 1){


You mean
if(n == 1){

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 20 '05 #21
kie
so something similar to this::?

function removeRow(){ //if row is last row, it cannot be deleted

for( var node = this.parentNode; node; node=node.parentNode)
if(node.parent.rows.length != 1){
alert('Cannot remove last remaining row');
break;
}else{
if(node.tagName=="TR"){
node.parentNode.removeChild(node);
break;
}
}
}

the object 'this' comes from the onClick event of the button in the
row of the dynamic table created by the 'createElement' function. see
(http://www.kieran.f2s.com/removeChild/working.htm)

is this "removeRow" function on the right track, and if so, can it be
modifed to remove all of the rows withing the table?
Jul 20 '05 #22
kie wrote:
so something similar to this::?

function removeRow(){ //if row is last row, it cannot be deleted

for( var node = this.parentNode; node; node=node.parentNode)
if(node.parent.rows.length != 1){
alert('Cannot remove last remaining row');
break;
}else{
if(node.tagName=="TR"){
node.parentNode.removeChild(node);
break;
}
}
}

the object 'this' comes from the onClick event of the button in the
row of the dynamic table created by the 'createElement' function. see
(http://www.kieran.f2s.com/removeChild/working.htm)

is this "removeRow" function on the right track, and if so, can it be
modifed to remove all of the rows withing the table?


Personally I would prefer to step back and modify the approach a little.
Basically the page starts with one table row defined in HTML, more rows
can be added and deleted, each row has a unique sequence number, and at
some point you wish to have an index of the rows. Rather than create
this index from the DOM, I would use a "factory" object to create and
delete rows and take care of indexing as well. A simple "tableRow"
object might go:

var tableRow = { // factory object

// initialise to account for first row generated in HTML
// with lineId of 1

lineId: 2, // next line sequence number for new rows
lineExists: [false,true], // lookup table by lineId
lineIndex: [1], // array of lineId's on page

create: function ()
{
var oRow = document.createElement('TR');
var lineId = this.lineId++;
var rowId = "row+" + lineId;
var delFunction =
this.makeDelFunction(this, lineId, rowId);

oRow.id = rowId;
this.lineExists[ lineId] = true;
this.reIndex();
return {oRow: oRow,
lineId: lineId,
delFunction: delFunction};
},
makeDelFunction: function( tableRow, lineId, rowId)
{
return function() {tableRow.remove( lineId, rowId)};
},
remove: function( lineId, rowId)
{ var oRow;
if(this.lineIndex.length <= 1)
{ alert("Cannot remove last remaining row");
return;
}
oRow = document.getElementById( rowId);
oRow.parentNode.removeChild(oRow);
delete this.lineExists[ lineId];
this.reIndex();
calculateTab(2,0); // whatever needs doing
},
reIndex: function()
{
this.lineIndex.length=0; // start again;
for(var i = 0; i < this.lineExists.length; ++i)
{
if(this.lineExists[i])
this.lineIndex.push(i);
}
},
getIndex: function()
{ return this.lineIndex;
}
}

Then in detail_row(), call tableRow.create and, from the returned
object, extract the TR element, the line number and the remove function
for setting on the ButtonSupprimer element - removeRow() above is no
longer used, and neither is globalClaimLnsRowNum made use of.

Later instead of recreating the index, try
a_ids = tableRow.getIndex();
j = a_ids.length;
and in the HTML row definition, include
onclick="tableRow.remove(1, 'row_1')"
as the click handler for the remove button.

As noted in another thread, there are complexities and probable bugs
remaining the code. One I noticed and commented out was in detail_row:
tablebody2.appendChild(oRow);
// formation.appendChild(tablebody2);
since tablebody2 is already a child node of formation!!!

You may wish to check the NG FAQ as well:
http://jibbering.com/FAQ/
It has some very useful trim and decimal formatting routines (amongst
other goodies)
HTH and Good luck!

Dom

Jul 20 '05 #23
kie
wow Dom, this is new ground for me, i've never used a factory
object/mthod before. i can find information on them in c++ groups, but
not much relating to javascript. so i can grasp the principle of it:

from comp.lang.c++ : "It's a standard OOP term for an object that
contains an interface for creating other objects--so like a factory it
builds things. Factory methods in the object allow derived classes to
specify what type of object is actually created using the virtual
mechanism."

if i call the object factory "tableRow.create;" after i have
discovered the 'tbody' element where the dynamic rows will go, i.e.:

var tablebody2=formation.getElementsByTagName('tbody')[0];
tableRow.create;
//rowSec2=document.createElement('TR');
then i encounter problems with the "appendChild" method. or should i
not comment out the object assigning of "rowSec2", because the
"tableRow" object factory is only concerned with the indexing and
removal of rows, and not assigning elements to the "TR" row object?

i know nothing about this, i should read up on the subject, do you own
or recommend any of the following:?

Principles of Object-Oriented Programming in Java 1.1: The Practical
Guide to Effective, Efficient Program Design by James W. Cooper,
Ventana Communications

Design patterns : elements of reusable object-oriented software
by Erich Gamma, et al

Concurrent Programming in Java: Design Principles and Patterns (The
Java Series)
by Doug Lea;

also if there are any links reading to examples of factory
objects/methods, i'd like to check them out.

thanks for all your help, kie

attempt link: http://www.kieran.f2s.com/remove_row...ory_object.htm
Jul 20 '05 #24
kie wrote:
this is new ground for me, i've never used a factory
object/mthod before.
<grin> I think you might have. </grin> I picked up the term from the
W3C DOM2 recommendation, core section "1.1.2 Memory Management",
referring to factory methods as creating instances of objects [without
the new operator provided in call]. In this sense document.createElement
is one example of a well known factory method.

i can find information on them in c++ groups, but not much relating to javascript. so i can grasp the principle of it:

from comp.lang.c++ : "It's a standard OOP term for an object that
contains an interface for creating other objects--so like a factory it
builds things. Factory methods in the object allow derived classes to
specify what type of object is actually created using the virtual
mechanism."
Glad to see the W3C guys knew what they were talking about :)

My reasons for noting the "tableRow" object as a factory object were
two-fold: for maintenance purposes it provides a clue that object
methods would create objects without themselves being called with the
"new" operator, and by placing table row creating, removing and indexing
in one spot, implementation code can be modififed or optimised with
minimal impact on outside code and testing. [FWIW the posted code is not
optimal, and has the typo "row+" instead of "row_" which to some extent
"worked" because it was not optimal. The beauty is that this can be
fixed with minimal or no changes to calling code.].

if i call the object factory "tableRow.create;" after i have
discovered the 'tbody' element where the dynamic rows will go, i.e.:

var tablebody2=formation.getElementsByTagName('tbody')[0];
tableRow.create;
//rowSec2=document.createElement('TR');
then i encounter problems with the "appendChild" method.
Sorry for any confusion, it was not intentional. detail_row code would
be ammended along the lines of:

var oResult = tableRow.create();
// returns an object with
// oResult.oRow = the TR element created
// oResult.lineId = a line sequence number
// oResult.delFunction = a function object
...
rowSec2 = oResult.oRow; // the TR element
...
sel2.id='two_d_cmb_goods__' + oResult.lineId;
// use the line sequence number provided wherever
// globalClaimLnsRowNum was used.
...
// and use the remove function returned by .create()
ButtonSupprimer.onclick = oResult.delFunction;

<snip>
Sorry can't comment on any of the books. I tend to use resources
available on the Internet - ebooks for preference, but articles when
needed. A good thing the Internet still functions for research (so far).

attempt link: http://www.kieran.f2s.com/remove_row...ory_object.htm


I would encourage you to continue asking questions of the group by
composing cut down pages and code samples related to individual
programming techniques - there is work involved in preparing the
question but it maximises the chances of assistance. I suspect further
line by line discussion of this page will be of diminishing interest, so
if you like (and this is not a general invitation) feel free to email me
with a working email address for return attachments. If nothing else, we
might be able to sort out a good text editor for you to use :)

kind regards,
Dom

Jul 20 '05 #25
kie
> if you like (and this is not a general invitation) feel free to email me
with a working email address for return attachments. If nothing else, we
might be able to sort out a good text editor for you to use :)


thanks, dom. i've just done it.

the object factory works well, and i understand how the code works, i
am having trouble finding other examples of js object factorys
however.

using the factory in conjunction with one table i changed the 'remove'
section to:

remove: function( lineId, rowId)
{ var oRow;
alert(this.lineIndex.length);
if(this.lineIndex.length <= 2)
{ alert("Cannot remove last remaining row");
return;
}

to make it work. i'm wondering, why when there is only one row in the
dynamic table remaining, does the 'this.lineIndex.length' emerge as
the value 2? is it taking into account the none dynamic '<tr>'
elements?

so i added a second table, and then a third, each with one row.
on two tables the 'lineIndex.length' was 3, on three is was 4.

this causes a problem when detecting the presence of a last row in a
table. the conclusion i jump to is to make a loop using the table id
or parentNode, like:

remove: function( lineId, rowId)
{ var oRow;
//alert(this.lineIndex.length);
var i;
var n_count_rows = 0;
for( var node = this.parentNode; node; node=node.parentNode){
if(node.tagName=="TR"){
for (i=0; i<this.lineIndex.length; i++){
n_count_rows = n_count_rows + 1
alert(n_count_rows);
}
}
}
if(n_count_rows < 2)
{ alert("Cannot remove last remaining row");
return;
}
//if(this.lineIndex.length <= 2)
//{ alert("Cannot remove last remaining row");
// return;
//}
oRow = document.getElementById(rowId);
oRow.parentNode.removeChild(oRow);
delete this.lineExists[lineId];
this.reIndex();
calculateTab(2,0); // whatever needs doing

do you know a more concise way of doing this, such as replacing:

if(this.lineIndex.length <= 2)
{ alert("Cannot remove last remaining row");
return;
}

for

if(this.lineIndex.parentTableId.count = 1)
{ alert("Cannot remove last remaining row");
return;
}

the lengthy version of this code can be found at:
http://www.kieran.f2s.com/table(3).html
upon viewing the source of the html page, the object factory is at the
very top, followed by the dynamic table creation code.

thanks for any help, kie
Jul 20 '05 #26

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Mike Solomon | last post: by
7 posts views Thread by Andrew Poulos | last post: by
2 posts views Thread by The_Original_MB | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.