SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 28
  1. #1
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Multiple Row Auto Calculation and CheckBox

    Hi...guys!I have a multiple row table,the structure as declared below.

    Code HTML4Strict:
    <table id ="claim_dtl">
    <form name="claim_dtl">
    <tr>
    <td><input name="trainingCost" rel="calculate_input" type="text" size="5" /></td>
     <td ><input name="travelCost" rel="calculate_input" type="text" size="7" /></td>
    <td ><input name="entCost" rel="calculate_input" type="text" size="5" /></td>
      <td><input name="miscCost" rel="calculate_input" type="text" size="5" /></td>
    <td><input type="checkbox" name="fc" value="checkbox" /></td>
    <td><input name="subTotalRM" rel="calculate_output_rm" type="text" size="5" disabled="disabled" /></td>
    <td><input name="subTotalFC" rel="calculate_output_fc" type="text" size="10" disabled="disabled" /></td> 
     </tr>
    <tr>
    <td><input name="trainingCost" rel="calculate_input" type="text" size="5" /></td>
     <td ><input name="travelCost" rel="calculate_input" type="text" size="7" /></td>
    <td ><input name="entCost" rel="calculate_input" type="text" size="5" /></td>
      <td><input name="miscCost" rel="calculate_input" type="text" size="5" /></td>
    <td><input type="checkbox" name="fc" value="checkbox" /></td>
    <td><input name="subTotalRM" rel="calculate_output_rm" type="text" size="5" disabled="disabled" /></td>
    <td><input name="subTotalFC" rel="calculate_output_fc" type="text" size="10" disabled="disabled" /></td> 
     </tr>
    <tr>
     <td><input name="totalRM" id ="totalRM" type="text" size="5" disabled="disabled" /></td>
    <td><input name="totalFC" id ="totalFC" type="text" size="10" disabled="disabled" /></td>
    </tr>
    </form>
    </table>

    I need the summation of "calculate_input" to be displayed at the subTotalFC field if checkbox is checked rather than subTotalRM field which I have already implemented it.And also the summation of subTotalFC to be displayed at totalFC field.

    Here is the function for auto calculation:
    Code JavaScript:
    function setupAutoCalc() {
    	var table = document.getElementById("claim_dtl");
        if(!table) {  
    		alert("Error:No table found!");
            return;
        }
        if(table.tBodies.length == 0) {
    		alert("Error:No row found!");
            return;
        }            
     
    	for(var i = 0; i < table.tBodies[0].rows.length; i++) {
    		var inputs = table.tBodies[0].rows[i].getElementsByTagName("input");
    		for(var inp = 0; inp < inputs.length; inp++) {
    			if(inputs[inp].getAttribute("rel") == "calculate_input") {
    				inputs[inp].onkeyup = function() {
    					var tmp = this;
    					while(tmp.nodeName != "TR")
    						tmp = tmp.parentNode;
    					autocalc(tmp, this);
    				}
    			}
    		}
    	}
    }
     
    function autocalc(row, v) {
    	if(isNaN(v.value)) {
    		alert("Please enter number only");
    		v.value = "";
    		return;
    	}
    else
        if(v.value == 0) {
    		alert("Please enter number greater than zero only");
    		v.value = "";
    		return;
        }
    	// if(document.claim_dtl.fc.checked == false) {
    		var tmp= row.getElementsByTagName("input");
    		var inputs = new Array();
    		var output = false;
     
    		for(var i = 0;i<tmp.length;i++) {
    			if(tmp[i].getAttribute("rel") == "calculate_output_rm") 
    				output = tmp[i];
             else
    				inputs[inputs.length] = tmp[i];
           }
           if(!output) {
    			alert("Error:No output calculated");
    			return;
           }
     
    		var subTotal = 0;
    		for(var i = 0;i < inputs.length; i++) {
    			var val = Number(inputs[i].value);
    			var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
    			if(!isNaN(num))
    				subTotal += num; 
            }
            output.value = subTotal; // subtotal of RM
     
            tmp = row.parentNode.getElementsByTagName("input");
            var total = 0;
    		for (var i = 0; i < tmp.length; i++) {
    			if (tmp[i].getAttribute("rel") === "calculate_output_rm") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
    			    if(!isNaN(num)) {
                           total += num; 
                   }
               }
           }
           var totalRM = document.getElementById("totalRM");
    	   totalRM.value = total; // total of RM
        // }
     
    	if(document.claim_dtl.fc.checked == true) {
    		 tmp= row.getElementsByTagName("input");
     
    		 for(var i = 0;i<tmp.length;i++) {
    			if(tmp[i].getAttribute("rel") == "calculate_output_fc") 
    				output = tmp[i];
               else
    				inputs[inputs.length] = tmp[i];
    	   }
    	   if(!output) {
    			alert("Error:No output calculated");
    			return;
           }
     
           subTotal = 0;
           for(var i = 0;i < inputs.length; i++) {
    			var val = Number(inputs[i].value);
    			var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
    			if(!isNaN(num))
    				subTotal += num; 
          }
          output.value = subTotal; // subtotal of FC
     
         tmp = row.parentNode.getElementsByTagName("input");
              total = 0;
    		for (var i = 0; i < tmp.length; i++) {
    			if (tmp[i].getAttribute("rel") === "calculate_output_fc") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
    			    if(!isNaN(num)) {
                           total += num; 
                   }
               }
           }
           var totalFC = document.getElementById("totalFC");
    	   totalFC.value = total; // total of FC
        }
    }

    Why the condition if(document.claim_dtl.fc.checked == true) is not worked?This is the logic that I use to control the assignment of subtotal and total to the correct field.Thank for your pleasure help...

  2. #2
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    anybody can help me?I feel so lost....

  3. #3
    SitePoint Wizard gRoberts's Avatar
    Join Date
    Oct 2004
    Location
    Birtley, UK
    Posts
    2,439
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oops, I wasn't thinking straight. Give me 5 minutes..

    edit. Sorry about that, give this a try:

    Code Javascript:
    function autocalc(row, v) {
        if(isNaN(v.value)) {
            alert("Please enter number only");
            v.value = "";
            return;
        } else if(v.value == 0) {
            alert("Please enter number greater than zero only");
            v.value = "";
            return;
        }
        if(checkbox == null || checkbox.checked == false) {
            var tmp = row.getElementsByTagName("input");
            var inputs = new Array();
            var output = false;
            var checkbox = null;
     
            for(var i = 0;i<tmp.length;i++) {
                if(tmp[i].getAttribute('type') == 'checkbox')
                    checkbox = tmp[i];
                else {
                    if(tmp[i].getAttribute("rel") == "calculate_output_rm")
                        output = tmp[i];
                    else
                        inputs[inputs.length] = tmp[i];
                }
           }
           if(!output) {
                alert("Error:No output calculated");
                return;
           }
     
            var subTotal = 0;
            for(var i = 0;i < inputs.length; i++) {
                var val = Number(inputs[i].value);
                var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
                if(!isNaN(num))
                    subTotal += num;
            }
            output.value = subTotal; // subtotal of RM
     
            tmp = row.parentNode.getElementsByTagName("input");
            var total = 0;
            for (var i = 0; i < tmp.length; i++) {
                if (tmp[i].getAttribute("rel") === "calculate_output_rm") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
                    if(!isNaN(num)) {
                           total += num;
                   }
               }
           }
           var totalRM = document.getElementById("totalRM");
           totalRM.value = total; // total of RM
        }
     
        if(document.claim_dtl.fc.checked == true) {
             tmp= row.getElementsByTagName("input");
     
             for(var i = 0;i<tmp.length;i++) {
                if(tmp[i].getAttribute("rel") == "calculate_output_fc")
                    output = tmp[i];
               else
                    inputs[inputs.length] = tmp[i];
           }
           if(!output) {
                alert("Error:No output calculated");
                return;
           }
     
           subTotal = 0;
           for(var i = 0;i < inputs.length; i++) {
                var val = Number(inputs[i].value);
                var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
                if(!isNaN(num))
                    subTotal += num;
          }
          output.value = subTotal; // subtotal of FC
     
         tmp = row.parentNode.getElementsByTagName("input");
              total = 0;
            for (var i = 0; i < tmp.length; i++) {
                if (tmp[i].getAttribute("rel") === "calculate_output_fc") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
                    if(!isNaN(num)) {
                           total += num;
                   }
               }
           }
           var totalFC = document.getElementById("totalFC");
           totalFC.value = total; // total of FC
        }
    }


  4. #4
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The code is not worked,problem remain.Anyone can help me?

  5. #5
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Could anyone help me to exploit it?I'm quite urgent on it...

  6. #6
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone please?I am still suffered on it...

  7. #7
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    Try changing document.claim_dtl.fc to checkbox
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  8. #8
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What do you mean??
    document.document.claim_dtl.fc is already referred to the checkbox

  9. #9
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    There are two checkboxes with the same name, "fc" so you will end up with an array that contains all of the checkboxes.

    Beacuse of that, gRoberts assigned to a variable called 'checked' a reference to the checkbox that should be looked at.

    Instead of using document.document.claim_dtl.fc, which will return an array in which you don't know which arary index to use, you should use the variable checked instead, which has already been pointed to the correct location.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  10. #10
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well..thank for reply.Now if checkbox is checked.The summation assign to subtotalFC and totalFC.However,the summing is incorrect.The value in subtotalFC and totalFC will multiply three what I enter and there still display the correct value in subtotalRM and totalRM.

    Code JavaScript:
    function autocalc(row, v) {
        if(isNaN(v.value)) {
            alert("Please enter number only");
            v.value = "";
            return;
        } else if(v.value == 0) {
            alert("Please enter number greater than zero only");
            v.value = "";
            return;
        }
     
        if(checkbox == null || checkbox.checked == false) {
            var tmp = row.getElementsByTagName("input");
            var inputs = new Array();
            var output = false;
            var checkbox = null;
     
            for(var i = 0;i<tmp.length;i++) {
                if(tmp[i].getAttribute('type') == 'checkbox')
                    checkbox = tmp[i];
                else {
                    if(tmp[i].getAttribute("rel") == "calculate_output_rm")
                        output = tmp[i];
                    else
                        inputs[inputs.length] = tmp[i];
                }
           }
           if(!output) {
                alert("Error:No output calculated");
                return;
           }
     
            var subTotal = 0;
            for(var i = 0;i < inputs.length; i++) {
                var val = Number(inputs[i].value);
                var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
                if(!isNaN(num))
                    subTotal += num;
            }
            output.value = subTotal; // subtotal of RM
     
            tmp = row.parentNode.getElementsByTagName("input");
            var total = 0;
            for (var i = 0; i < tmp.length; i++) {
                if (tmp[i].getAttribute("rel") === "calculate_output_rm") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
                    if(!isNaN(num)) {
                           total += num;
                   }
               }
           }
           var totalRM = document.getElementById("totalRM");
           totalRM.value = total; // total of RM
        }
     
        if(checkbox.checked == true) {
             tmp= row.getElementsByTagName("input");
     
             for(var i = 0;i<tmp.length;i++) {
                if(tmp[i].getAttribute("rel") == "calculate_output_fc")
                    output = tmp[i];
               else
                    inputs[inputs.length] = tmp[i];
           }
           if(!output) {
                alert("Error:No output calculated");
                return;
           }
     
           subTotal = 0;
           for(var i = 0;i < inputs.length; i++) {
                var val = Number(inputs[i].value);
                var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
                if(!isNaN(num))
                    subTotal += num;
          }
          output.value = subTotal; // subtotal of FC
     
         tmp = row.parentNode.getElementsByTagName("input");
              total = 0;
            for (var i = 0; i < tmp.length; i++) {
                if (tmp[i].getAttribute("rel") === "calculate_output_fc") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
                    if(!isNaN(num)) {
                           total += num;
                   }
               }
           }
           var totalFC = document.getElementById("totalFC");
           totalFC.value = total; // total of FC
        }
    }

  11. #11
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone can help me please.... What else should I change to produce a correct result when checkbox is checked.The value is assigned to correct field but calculation itself is incorrect.

  12. #12
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    You do not need to recalculate the field values near the end of the function, because you already have them in the subtotal and total variables.

    At the end of the autocalc function, change the code from this:

    Code javascript:
    subTotal = 0;
    for(var i = 0;i < inputs.length; i++) {
        var val = Number(inputs[i].value);
        var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
        if(!isNaN(num))
            subTotal += num;
    }
    output.value = subTotal; // subtotal of FC
     
    tmp = row.parentNode.getElementsByTagName("input");
    total = 0;
    for (var i = 0; i < tmp.length; i++) {
        if (tmp[i].getAttribute("rel") === "calculate_output_fc") {
            var val = Number(tmp[i].value);
            var num = Math.round(val * 100) / 100;
            if(!isNaN(num)) {
                    total += num;
            }
        }
    }
    var totalFC = document.getElementById("totalFC");
    totalFC.value = total; // total of FC

    to this:

    Code javascript:
    output.value = subTotal; // subtotal of FC
    totalFC.value = total; // total of FC
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  13. #13
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well..thanks for reply..For having checkbox checking,the calculation itself is weird.For instance,I key in 1,the subtotal and total become which fine,but if I having 1 in another input,the summation become 3??
    Somemore it still have value stick at the subtotalRM and totalRM fields

    Code:
    function autocalc(row, v) {
        if(isNaN(v.value)) {
            alert("Please enter number only");
            v.value = "";
            return;
        } else if(v.value == 0) {
            alert("Please enter number greater than zero only");
            v.value = "";
            return;
        }
    	
        if(checkbox == null || checkbox.checked == false) {
            var tmp = row.getElementsByTagName("input");
            var inputs = new Array();
            var output = false;
            var checkbox = null;
       
            for(var i = 0;i<tmp.length;i++) {
                if(tmp[i].getAttribute("type") == "checkbox")
                    checkbox = tmp[i];
                else {
                    if(tmp[i].getAttribute("rel") == "calculate_output_rm")
                        output = tmp[i];
                    else
                        inputs[inputs.length] = tmp[i];
                }
           }
           if(!output) {
                alert("Error:No output calculated");
                return;
           }
     
            var subTotal = 0;
            for(var i = 0;i < inputs.length; i++) {
                var val = Number(inputs[i].value);
                var num = Math.round(val*Math.pow(10,2)) / Math.pow(10,2);
                if(!isNaN(num))
                    subTotal += num;
            }
            output.value = subTotal; // subtotal of RM
     
            tmp = row.parentNode.getElementsByTagName("input");
            var total = 0;
            for (var i = 0; i < tmp.length; i++) {
                if (tmp[i].getAttribute("rel") === "calculate_output_rm") {
                    var val = Number(tmp[i].value);
                    var num = Math.round(val * 100) / 100;
                    if(!isNaN(num)) {
                           total += num;
                   }
               }
           }
           var totalRM = document.getElementById("totalRM");
           totalRM.value = total; // total of RM
        }
     
        if(checkbox.checked == true) {
             tmp= row.getElementsByTagName("input");
       
             for(var i = 0;i<tmp.length;i++) {
                if(tmp[i].getAttribute("rel") == "calculate_output_fc")
                    output = tmp[i];
               else
                    inputs[inputs.length] = tmp[i];
           }
           if(!output) {
                alert("Error:No output calculated");
                return;
           }
     
          
          output.value = subTotal; // subtotal of FC
     
         
           var totalFC = document.getElementById("totalFC");
           var fcValue = document.getElementById("fcValue");
           totalFC.value = total; // total of FC
        }
    }

  14. #14
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    Your code is becoming a mess and hard to understand. It's past time to refactor it.

    Many parts have been moved out to separate functions, which enables us to remove duplication and focus more clearly on the program logic instead.

    The setup section has been overly complicated. Instead of looping through each row looking for input elements, we can just get all the input elements from the table itself.

    Now the logic for the script is reduced to the following

    Code javascript:
    var row = getTRFrom(this);
    var data = getData(row);
    if (data.checkbox === null || data.checkbox.checked === false) {
    	data.output.rm.value = total(data.inputs); // subtotal of RM
    	data.output.fc.value = '';
    } else {
    	data.output.rm.value = '';
    	data.output.fc.value = total(data.inputs); // subtotal of FC
    }
     
    var outputs = getOutputs(row.parentNode);
    document.getElementById("totalRM").value = total(outputs.rm); // total of RM
    document.getElementById("totalFC").value = total(outputs.fc); // total of FC

    The rel attributes on the input elements aren't needed anymore, except for the total fields, so the html is now

    Code html4strict:
    <table id ="claim_dtl">
    <form name="claim_dtl">
    <tr>
    <td><input name="trainingCost" type="text" size="5" /></td>
     <td ><input name="travelCost" type="text" size="7" /></td>
    <td ><input name="entCost" type="text" size="5" /></td>
      <td><input name="miscCost" type="text" size="5" /></td>
    <td><input type="checkbox" name="fc" value="checkbox" /></td>
    <td><input name="subTotalRM" rel="calculate_output_rm" type="text" size="5" disabled="disabled" /></td>
    <td><input name="subTotalFC" rel="calculate_output_fc" type="text" size="10" disabled="disabled" /></td>
     </tr>
    <tr>
    <td><input name="trainingCost" type="text" size="5" /></td>
     <td ><input name="travelCost" type="text" size="7" /></td>
    <td ><input name="entCost" type="text" size="5" /></td>
      <td><input name="miscCost" type="text" size="5" /></td>
    <td><input type="checkbox" name="fc" value="checkbox" /></td>
    <td><input name="subTotalRM" rel="calculate_output_rm" type="text" size="5" disabled="disabled" /></td>
    <td><input name="subTotalFC" rel="calculate_output_fc" type="text" size="10" disabled="disabled" /></td>
     </tr>
    <tr>
     <td><input name="totalRM" id ="totalRM" type="text" size="5" disabled="disabled" /></td>
    <td><input name="totalFC" id ="totalFC" type="text" size="10" disabled="disabled" /></td>
    </tr>
    </form>
    </table>

    The setupAutoCalc() function has been tidied up to be the following:

    Code javascript:
    function setupAutoCalc() {
    	function isValidTable(table) {
    	    if (!table) { 
    	        alert("Error:No table found!");
    	        return false;
    	    }
    	    if (table.tBodies.length === 0) {
    	        alert("Error:No row found!");
    	        return false;
    	    }
    		return true;
    	}
        var table = document.getElementById("claim_dtl");
    	if (!isValidTable(table)) {
    		return;
    	}
    	var els = table.getElementsByTagName("input"),
    		elsLen = els.length,
    		i,
    		el;
    	for (i = 0; i < elsLen; i += 1) {
    		el = els[i];
    		if (el.type === 'checkbox') {
    			el.onchange = autocalc;
    		} else {
    			el.onkeyup = autocalc;
    		}
    	}
    }
    onload = setupAutoCalc;

    with that last line running the script when the page loads, so it's not needed on the body tag of the page anymore.

    Here is the autocalc() function, which should make a lot more sense now than what has been worked with.

    I have even run the script through jslint, which picked up a couple of issues that slipped by me.

    Code javascript:
    function autocalc() {
    	function isValidValue(val) {
    		if (isNaN(val.value)) {
    	        alert("Please enter number only");
    	        val.value = "";
    	        return false;
    	    } else if (val.value === 0) {
    	        alert("Please enter number greater than zero only");
    	        val.value = "";
    	        return false;
    	    }
    		return true;
    	}
    	function walkUpToElementFrom(target, source) {
    		var el = source;
    		while (el.nodeName !== target.toUpperCase() && el.nodeName !== 'BODY') {
    			el = el.parentNode;
    		}
    		if (el.nodeName === 'BODY') {
    			return null;
    		}
    		return el;
    	}
    	function getData(row) {
    		var result = {
    			inputs: [],
    			output: {}
    		};   
    		var els = row.getElementsByTagName("input"),
    			elsLen = els.length,
    			el,
    			i;
    		for (i = 0; i < elsLen; i += 1) {
    			el = els[i];
    			if (el.getAttribute("type") === "checkbox") {
    				result.checkbox = el;
    			} else if (el.getAttribute("rel")) {
    				if (el.getAttribute("rel") === "calculate_output_rm") {
    					result.output.rm = els[i];
    				} else if (el.getAttribute("rel") === "calculate_output_fc") {
    					result.output.fc = el;
    				}
    			} else {
    				result.inputs.push(el);
    			}
    		}
    	    return result;
    	}
    	function getOutputs(row) {
    		var result = {rm: [], fc: []};
    		var els = row.getElementsByTagName("input"),
    			elsLen = els.length,
    			el,
    			i;
    		for (i = 0; i < elsLen; i += 1) {
    			el = els[i];
    			if (el.getAttribute("rel") === "calculate_output_rm") {
    				result.rm.push(el);
    			}
    			if (el.getAttribute("rel") === "calculate_output_fc") {
    				result.fc.push(el);
    			}
    	    }
    		return result;
    	}
    	function total(els) {
    		var sum = 0,
    			elsLen = els.length,
    			i,
    			val;
    		for (i = 0;i < elsLen; i += 1) {
    			val = Number(els[i].value);
    			val = Math.round(val * 100) / 100;
    			if (!isNaN(val)) {
    				sum += val;
    			}
    		}
    		if (sum === 0) {
    			sum = '';
    		}
    		return sum;
    	}
    	if (this.type === 'text' && !isValidValue(this)) {
    		return;
    	}
    	var row = walkUpToElementFrom('tr', this);
    	var data = getData(row);
    	if (data.checkbox === null || data.checkbox.checked === false) {
    		data.output.rm.value = total(data.inputs); // subtotal of RM
    		data.output.fc.value = '';
    	} else {
    		data.output.rm.value = '';
    		data.output.fc.value = total(data.inputs); // subtotal of FC
    	}
     
    	var outputs = getOutputs(row.parentNode);
    	document.getElementById("totalRM").value = total(outputs.rm); // total of RM
    	document.getElementById("totalFC").value = total(outputs.fc); // total of FC
     
    }
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  15. #15
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well..thanks for great initiative pmw57...

    I am a learner for js,may i know why you define the result as this way.

    Code JavaScript:
     var result = {
                inputs: [],
                output: {}
            };  
     var result = {rm: [], fc: []};

    I wonder it is an array,but why in such format?And why you adopt strict equal and strict not equal instead == and != in the entire script?Thanks...

  16. #16
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Now we are getting all the input elements from the table itself in one shot.However,how about if there have some elements which are not going to involve in this calculation and I need to escape them from the alert.

    I could comment out the alert statement and directly return false but the invalid value is still remain at the cell,for instance the "A" i type in cost field.Just curious to know that is there any solution to escape it by using the same logic?It is the form that I going to submit later,so some sort of validation need to be done before submission.

    Code JavaScript:
    function isValidValue(val) { 
            if (isNaN(val.value)) {
                alert("Please enter number only");
                val.value = "";
                return false;
            } else if (val.value === 0) {
                alert("Please enter number greater than zero only");
                val.value = "";
                return false;
            }
            return true;
        }

    Secondly,I need to added a field named exchange rate to convert the totalFC to domestic currency and finally calculate the grandTotal.The formula of grandTotal is grandtotal= totalFC * exchange rate +totalRM,because it is possible to have mixture total of domestic and foreign currency.

    I have written a function for it,however the script not worked...

    For added HTML view,fcValue is the field that hold same value as totalFC
    Code HTML4Strict:
    <tr>
    <td colspan="8" align="right"><b>&nbsp;</b><b>Exchange Rate @</b></td>
    <td colspan="2" align="right" >
    <input name="excrate" id ="excrate" type="text" size="10" />&nbsp;</td>
    <input name="fcValue" id = "fcValue" type="text" size="5" disabled="disabled" /></td>
    </tr>
     <tr>
    <td colspan="10" align="right"><b>Grand Total: </b></td>
    <td colspan="2">
    <input name="grandTotal" id ="grandTotal" rel = "calculate_output_gt" disabled="disabled" type="text" size="10" /></td>
    </tr>

    For autocalc,the commented statements are ammended portion which for grandtotal calculation.

    Code JavaScript:
    function autocalc() {
        function isValidValue(val) { 
            if (isNaN(val.value)) {
                //alert("Please enter number only");
                //val.value = "";
                return false;
            } else if (val.value === 0) {
                //alert("Please enter number greater than zero only");
                //val.value = "";
                return false;
            }
            return true;
        }
        function walkUpToElementFrom(target, source) { 
            var el = source;
            while (el.nodeName !== target.toUpperCase() && el.nodeName !== 'BODY') {
                el = el.parentNode;
            }
            if (el.nodeName === 'BODY') {
                return null;
            }
            return el;
        }
        function getData(row) { 
            var result = {inputs: [],output: {}};   
            var els = row.getElementsByTagName("input"),
                elsLen = els.length;
     
            for (var i = 0; i < elsLen; i += 1) {
                var el = els[i];
                if (el.getAttribute("type") === "checkbox") {
                    result.checkbox = el;
                } else if (el.getAttribute("rel")) {
                    if (el.getAttribute("rel") === "calculate_output_rm") {
                        result.output.rm = els[i];
                    } else if (el.getAttribute("rel") === "calculate_output_fc") {
                        result.output.fc = el;
                    }/*else if (el.getAttribute("rel") === "calculate_output_gt") {
    					result.output.gt = els[i];
    				}*/
                } else {
                    result.inputs.push(el);
                }
            }
            return result;
        }
        function getOutputs(row) { 
            var result = {rm: [], fc: []};
            var els = row.getElementsByTagName("input"),
                elsLen = els.length;
     
            for (var i = 0; i < elsLen; i += 1) {
                var el = els[i];
                if (el.getAttribute("rel") === "calculate_output_rm") {
                    result.rm.push(el);
                }
                if (el.getAttribute("rel") === "calculate_output_fc") {
                    result.fc.push(el);
                }
    			/*if(el.getAttribute("rel") === "calculate_output_gt") {
    				result.gt.push(el); // new length of result
    			}*/
            }
            return result;
        }
        function total(els) { 
            var sum = 0,
                elsLen = els.length;
     
            for (var i = 0;i < elsLen; i += 1) {
                var val = Number(els[i].value);
                val = Math.round(val * 100) / 100;
                if (!isNaN(val)) {
                    sum += val;
                }
            }
            if (sum === 0) {
                sum = '';
            }
            return sum;
        }
    	/*
    	function grandtotal(els) { 
    		var rm = 0,
    		     elsLen = els.length;
            if( total(outputs.rm) != 0) {
    			rm = total(outputs.rm);
         else
    			rm = '';
           }
           var grand = 0;
           var fc = total(outputs.fc);
    	   var excrate = document.getElementById("excrate");
    	   var val = Number(excrate.value);
    	   var num = Math.round(val * 100) / 100;
    	   if (!isNaN(num)) {
    		   var grand = (num * fc) + rm;
    	   }
           if (grand === 0) {
                grand = '';
            }
            return grand;
    	}*/
     
        if (this.type === 'text' && !isValidValue(this)) {
            return;
        }
        var row = walkUpToElementFrom('tr', this);
        var data = getData(row);
        if (data.checkbox === null || data.checkbox.checked === false) {
            data.output.rm.value = total(data.inputs); // subtotal of RM
            data.output.fc.value = '';
        } else {
            data.output.rm.value = '';
            data.output.fc.value = total(data.inputs); // subtotal of FC
        }
     
        var outputs = getOutputs(row.parentNode);
        document.getElementById("totalRM").value = total(outputs.rm); // total of RM
        document.getElementById("totalFC").value = total(outputs.fc); // total of FC
    	if(total(outputs.fc) == 0) {
    		document.getElementById("grandTotal").value = total(outputs.rm);
    	} else {
    	if(data.checkbox !== null || data.checkbox.checked === true) 
    		document.getElementById("grandTotal").value = '';
    	}
        //document.getElementById("grandTotal").value = grandtotal(outputs.gt); // grand total
    }

    The last part of the autocalc is actually control the assigning of grandtotal,it could only have value if no FC total,mean when checkbox is not checked.

    Code JavaScript:
    if(total(outputs.fc) == 0) {
    		document.getElementById("grandTotal").value = total(outputs.rm);
    	} else {
    	if(data.checkbox !== null || data.checkbox.checked === true) 
    		document.getElementById("grandTotal").value = '';
    	}
    Last edited by devil_vin; May 27, 2008 at 09:00.

  17. #17
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I just want the calculation of the grandTotal to be done when exchange rate is entered.Thank for you guys pleasure....

  18. #18
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    Quote Originally Posted by devil_vin View Post
    may i know why you define the result as this way.

    Code JavaScript:
     var result = {
                inputs: [],
                output: {}
            };  
     var result = {rm: [], fc: []};

    I wonder it is an array,but why in such format?
    The purpose of returning the object is so that multiple results can be returned from the function at the same time.

    It could also have been defined as follows

    Code javascript:
    var result = new Object();
    result.inputs = new Array();
    result.output = new Array();

    but it's more clear what's going on when it's declared in a JSON type manner.

    Quote Originally Posted by devil_vin View Post
    And why you adopt strict equal and strict not equal instead == and != in the entire script?Thanks...
    That is purely because it's almost always better than using == and != which are type-converting comparison operators.

    See http://developer.mozilla.org/en/docs...ison_Operators for details on how they differ.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  19. #19
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    Quote Originally Posted by devil_vin View Post
    I could comment out the alert statement and directly return false but the invalid value is still remain at the cell,for instance the "A" i type in cost field.
    You can return false from the test, but it will only remove the value if it hasn't been accepted. The onkeyup event is too late, so you need to validate the key onkeydown instead.


    Code javascript:
    function isSpecialKey(keyCode) {
    	// special keys are 0 to 47
    	if (keyCode <= 46) {
    		return true;
    	}
    	return false;
    }
    function isValidInteger(keyCode) {
    	// numbers are 48 to 57
    	if (keyCode >= 48 || keyCode <= 57) {
    		return true;
    	}
    }
    function isValidNumber(keyCode) {
    	var key = String.fromCharCode(keyCode);
    	if (keyCode === 190) {
    		key = '.';
    	}
    	var value = String(this.value) + String(key);
    	if (isNaN(Number(value))) {
    		return false;
    	}
    	return true;
    }
    ...
    if (el.type === 'checkbox') {
    	el.onchange = autocalc;
    } else {
    	el.onkeydown = function (evt) {
    		var evt = evt || window.event;
    		var keyCode = evt.keyCode;
    		if (isSpecialKey(keyCode)) {
    			return true;
    		}
    		if (this.name === 'excrate') {
    			if (!isValidNumber.call(this, keyCode)) {
    				return false;
    			}
    		} else if (!isValidInteger.call(this, keyCode)) {
    			return false;
    		}
    	}
    	el.onkeyup = autocalc;
    }

    I've called the isValidNumber in such a way that the this keyword is retained. Even though a period is allowable in a fractional number, there are some cases where it's not, so this allows us to check if the newly created value will be valid, and lets us cancel the keypress if it's not.

    You may want to place some text on the screen stating the valid values too, to prevent visitors from getting frustrated, and to give an example exchange rate to let people know it's a decimal value rather than a percentage.

    Quote Originally Posted by devil_vin View Post
    Secondly,I need to added a field named exchange rate to convert the totalFC to domestic currency and finally calculate the grandTotal.The formula of grandTotal is grandtotal= totalFC * exchange rate +totalRM,because it is possible to have mixture total of domestic and foreign currency.

    I have written a function for it,however the script not worked...
    Here's how it can be done. I've also added an update function which allows us to update multiple fields with the same value.

    Code javascript:
    	function updateMultiple(fields, value) {
    		var fieldsLen = fields.length,
    			i;
    		for (i = 0; i < fieldsLen; i += 1) {
    			fields[i].value = value;
    		}
    	}
    	var row = walkUpToElementFrom('tr', this);
    	var data = getData(row);
    	if (data.checkbox === null || data.checkbox.checked === false) {
    		updateMultiple(data.outputs.rm, total(data.inputs)); // subtotal of RM
    		updateMultiple(data.outputs.fc, '');
    	} else {
    		updateMultiple(data.outputs.rm, '');
    		updateMultiple(data.outputs.fc, total(data.inputs)); // subtotal of FC
    	}
     
    	var outputs = getData(row.parentNode).outputs,
    		totalRM = document.getElementById("totalRM"),
    		totalFC = document.getElementById("totalFC"),
    		excrate = document.getElementById("excrate"),
    		fcValue = document.getElementById("fcValue"),
    		grandTotal = document.getElementById("grandTotal");
    	totalRM.value = total(outputs.rm); // total of RM
    	totalFC.value = total(outputs.fc); // total of FC
    	fcValue.value = total(outputs.fc); // total of FC
    	if (fcValue.value) {
    		grandTotal.value = Number(excrate.value * fcValue.value) + Number(totalRM.value);
    		if (Number(grandTotal.value) === 0) {
    			grandTotal.value = '';
    		}
    	} else {
    		grandTotal.value = '';
    	}		
    }

    Here is the whole script as it stands right now.

    Code javascript:
    function autocalc() {
    	function walkUpToElementFrom(target, source) {
    		var el = source;
    		while (el.nodeName !== target.toUpperCase() && el.nodeName !== 'BODY') {
    			el = el.parentNode;
    		}
    		if (el.nodeName === 'BODY') {
    			return null;
    		}
    		return el;
    	}
    	function getData(row) {
    		var result = {
    			checkbox: {},
    			inputs: [],
    			outputs: {
    				rm: [],
    				fc: []
    			}
    		};   
    		var els = row.getElementsByTagName("input"),
    			elsLen = els.length,
    			el,
    			i;
    		for (i = 0; i < elsLen; i += 1) {
    			el = els[i];
    			if (el.getAttribute("type") === "checkbox") {
    				result.checkbox = el;
    			} else if (el.getAttribute("rel")) {
    				if (el.getAttribute("rel") === "calculate_output_rm") {
    					result.outputs.rm.push(el);
    				} else if (el.getAttribute("rel") === "calculate_output_fc") {
    					result.outputs.fc.push(el);
    				}
    			} else {
    				result.inputs.push(el);
    			}
    		}
    	    return result;
    	}
    	function total(els) {
    		var sum = 0,
    			elsLen = els.length,
    			i,
    			val;
    		for (i = 0;i < elsLen; i += 1) {
    			val = Number(els[i].value);
    			val = Math.round(val * 100) / 100;
    			if (!isNaN(val)) {
    				sum += val;
    			}
    		}
    		if (sum === 0) {
    			sum = '';
    		}
    		return sum;
    	}
    	function updateMultiple(fields, value) {
    		var fieldsLen = fields.length,
    			i;
    		for (i = 0; i < fieldsLen; i += 1) {
    			fields[i].value = value;
    		}
    	}
    	var row = walkUpToElementFrom('tr', this);
    	var data = getData(row);
    	if (data.checkbox === null || data.checkbox.checked === false) {
    		updateMultiple(data.outputs.rm, total(data.inputs)); // subtotal of RM
    		updateMultiple(data.outputs.fc, '');
    	} else {
    		updateMultiple(data.outputs.rm, '');
    		updateMultiple(data.outputs.fc, total(data.inputs)); // subtotal of FC
    	}
     
    	var outputs = getData(row.parentNode).outputs,
    		totalRM = document.getElementById("totalRM"),
    		totalFC = document.getElementById("totalFC"),
    		excrate = document.getElementById("excrate"),
    		fcValue = document.getElementById("fcValue"),
    		grandTotal = document.getElementById("grandTotal");
    	totalRM.value = total(outputs.rm); // total of RM
    	totalFC.value = total(outputs.fc); // total of FC
    	fcValue.value = total(outputs.fc); // total of FC
    	if (fcValue.value) {
    		grandTotal.value = Number(excrate.value * fcValue.value) + Number(totalRM.value);
    		if (Number(grandTotal.value) === 0) {
    			grandTotal.value = '';
    		}
    	} else {
    		grandTotal.value = '';
    	}		
    }
    function setupAutoCalc() {
    	function isValidTable(table) {
    	    if (!table) { 
    	        alert("Error:No table found!");
    	        return false;
    	    }
    	    if (table.tBodies.length === 0) {
    	        alert("Error:No row found!");
    	        return false;
    	    }
    		return true;
    	}
    	function isSpecialKey(keyCode) {
    		// special keys are 0 to 47
    		if (keyCode <= 46) {
    			return true;
    		}
    		return false;
    	}
    	function isValidInteger(keyCode) {
    		// numbers are 48 to 57
    		if (keyCode >= 48 || keyCode <= 57) {
    			return true;
    		}
    	}
    	function isValidNumber(keyCode) {
    		var key = String.fromCharCode(keyCode);
    		if (keyCode === 190) {
    			key = '.';
    		}
    		var value = String(this.value) + String(key);
    		if (isNaN(Number(value))) {
    			return false;
    		}
    		return true;
    	}
        var table = document.getElementById("claim_dtl");
    	if (!isValidTable(table)) {
    		return;
    	}
    	var els = table.getElementsByTagName("input"),
    		elsLen = els.length,
    		i,
    		el;
    	for (i = 0; i < elsLen; i += 1) {
    		el = els[i];
    		if (el.type === 'checkbox') {
    			el.onchange = autocalc;
    		} else {
    			el.onkeydown = function (evt) {
    				var evt = evt || window.event;
    				var keyCode = evt.keyCode;
    				if (isSpecialKey(keyCode)) {
    					return true;
    				}
    				if (this.name === 'excrate') {
    					if (!isValidNumber.call(this, keyCode)) {
    						return false;
    					}
    				} else if (!isValidInteger(keyCode)) {
    					return false;
    				}
    			}
    			el.onkeyup = autocalc;
    		}
    	}
    }
    onload = setupAutoCalc;
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  20. #20
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well..thanks for your great initiative again...
    Again I saw a specific method that you used call().I notice you are calling another method by passing different set of arguement.What is it for?

    Code JavaScript:
      if (this.name === 'excrate') {
                        if (!isValidNumber.call(this, keyCode)) {
                            return false;
                        }
     }

  21. #21
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I need you guys again, in each row of my table have 5 columns which are not going to involved in the calculation.How do I escape them to take part in the calculation when number is entered in these columns?

    The first five elements are not going to take part in the calculation.
    Code HTML4Strict:
    <tr>
    <td><input name="date" type="text" size="12" /></td>
    <td><input name="billno" type="text" size="8" /></td>
    <td><input name="desc" type="text" size="11" /></td>
    <td><input name="purpose" type="text" size="20" /></td>
    <td><input name="proName" type="text" size="6" /></td>
    <td><input name="trainingCost" type="text" size="5" /></td>
    <td><input name="travelCost" type="text" size="7" /></td>
    <td><input name="entCost"  type="text" size="5" /></td>
    <td><input name="miscCost" type="text" size="5" /></td>
    <td><input type="checkbox" name="fc" value="checkbox" /></td>
    <td><input name="subTotalRM" rel="calculate_output_rm" type="text" size="5" disabled="disabled" /></td>
    <td><input name="subTotalFC" rel="calculate_output_fc" type="text" size="10"  disabled="disabled" /></td>
    </tr>

    Secondly,please allow me to ask a question about Java here.I am using Java as the backend form processing.The submitted form data need to be inserted in db.How could I retrieve multiple row elements which share the same name with request.getParameter?I am using Struts+Spring+iBatis architecture.Thanks advance for your pleasure...

  22. #22
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I do create a function for null validation for date and purpose(1st and 4th elements).Since there has multiple row here,so the alert will only display when that row itself contain other data but date and purpose are null.Why it is not working when form is submitted?

    Code JavaScript:
    function doValidate(obj) {
        var tb = obj.getElementById("claim_dtl");
     
    	// iterate through the rows in the table
    	var trs = tb.getElementsByTagName("tr");
    	for (var i=0; i < trs.length; i++) {
    		// the columns that must have data
    		var inputs = trs[i].getElementsByTagName("input");
     
    		if(inputs[0] === '') {
    			alert("Please enter date");
    			return false;
    	    } else if(inputs[3] === '') {
    				alert("Please enter purpose");
    				return false;
    		}    
        }
            return true;
    }

    For the action part,even if I submit the form to itself,it also wont work.
    Code HTML4Strict:
    <table id ="claim_dtl" width="760" border="1" align="center">
    <form name ="claim_dtl" action="xxx.do" method="post" onsubmit="return doValidate(this.obj);">
    ......
    </form>
    </table>

  23. #23
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well...I believe this is my last question in this thread.
    In my design,on top of the table claim_dtl,I have another table which is not going to involve any calculation,but need a date validation.

    It has 2 cells here seperated by slash,how could I validate the date format as mm/YYYY ?
    Code HTML4Strict:
    <table>
    <tr>
    <td>Month / Year:</td>
    <td>
    <input name="month" type="text" size="2" /> / <input name="year" type="text" size="4" />
    <span>(For example: 01/2008)</span>
    </td>
     </tr>
    </table>

    However,same goes in the table claim_dtl,the first element is a date which need to validate as YYYY/mm/dd.
    Code HTML4Strict:
    <table id ="claim_dtl">
    <tr>
    <td><input name="date" type="text" size="12" /></td>
    </tr>
    Is it possible to achieve both date validation which reside in different table and having different format by using one function? Thanks thousand..

  24. #24
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,526
    Mentioned
    83 Post(s)
    Tagged
    3 Thread(s)
    Quote Originally Posted by devil_vin View Post
    Well..thanks for your great initiative again...
    Again I saw a specific method that you used call().I notice you are calling another method by passing different set of arguement.What is it for?
    While it's possible to have passed the this keyword to the function as another term, it's more flexible the way that I've done it, and has been done because I was working towards a better way of doing things.

    The call method was to allow the this keyword to be assigned to the function. Here's a reimagining of that section where the call method isn't used, but instead where the function is directly assigned to the event, that being the intended final purpose of those functions.

    Code javascript:
    function isValidNumber(evt) {
    	var evt = evt || window.event;
    	var keyCode = evt.keyCode;
    	if (isSpecialKey(keyCode)) {
    		return true;
    	}
    	var key = String.fromCharCode(keyCode);
    	if (keyCode === 190) {
    		key = '.';
    	}
    	// check the future value
    	var value = String(this.value) + String(key);
    	if (!isNaN(Number(value))) {
    		return true;
    	}
    	return false;
    }
    function isValidInteger(evt) {
    	var evt = evt || window.event;
    	var keyCode = evt.keyCode;
    	if (isSpecialKey(keyCode)) {
    		return true;
    	}
    	// is the keycode in the numbers range
    	if (keyCode >= 48 && keyCode <= 57) {
    		return true;
    	}
    	return false;
    }

    This allows us to make the program logic a lot easier to follow, it's very clear what's happening now.

    Code javascript:
    if (el.type === 'checkbox') {
    	el.onchange = autocalc;
    } else {
    	if (el.name !== 'excrate') {
    		el.onkeydown = isValidNumber;
    	} else {
    		el.onkeydown = isValidInteger;
    	}
    	el.onkeyup = autocalc;
    }

    It can be very difficult to make your code clear, so if it can be achieved, those are good patterns to stay with.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  25. #25
    SitePoint Addict
    Join Date
    Aug 2007
    Posts
    256
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for reply pmw57, Can you help me regarding the problems on #21,#22,#23.I have to complete it in this two days ,thank thousond for your help...


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •