简体   繁体   中英

summation of values in dynamically created textboxes

I am using java script to dynamically create textboxes in rows (their id's have a digit to represent the row number which is incremented by one for every row created so as to differentiate the inputs). And calculate the sum of all the dynamic text box values to be displayed in a static text box using the function

function updateAmount(row_num) 
     {
        TOTAL = document.getElementById('garage_total');
        var COST = document.getElementById('cost'+ row_num).value;

        var i;
        sum = 0;
        for(i=0;i <= row_num; i++)
        {
           sum = parseInt(sum) + parseInt(document.getElementById('cost'+ i).value); 
        }
        TOTAL.value = sum
     }

which is called on the textbox keyup event. My problem is it only displays the value of the first textbox correctly in the total miscalculates added textbox values and when the value of an existing input is edited, it is also miscalculated

instead of keyup i would suggest onchange event. the problem you had, was you do not loop.

function updateAmount(row_num) {
    var cost, i, sum = 0;
    for (i = 0; i <= row_num; i++) {
        cost = document.getElementById('cost' + i).value;
        if (!isNaN(cost)) {
            sum += cost;
        }
    }
    document.getElementById('garage_total').value = sum;
}

You don't need to give the rows, id s. By combining map, filter, and reduce; you can get each field, validate it, and add it to the sum.

 function updateAmount(row_num) { document.getElementById('garage_total').value = [] .slice.call( document.getElementsByClassName('cost_field') // NodeList to Array ) .map(function(costField) { return parseInt(costField.value, 10); // String to Integer }) .filter(function(value) { return !Number.isNaN(value); // Validate }) .reduce(function(sum, value) { return sum + value; // Add to sum. }, 0); } updateAmount(); 
 input { display: block; } 
 <input type="text" class="cost_field" value="5" /> <input type="text" class="cost_field" value="4" /> <input type="text" class="cost_field" value="3" /> <input type="text" class="cost_field" value="2" /> <input type="text" class="cost_field" value="1" /> <input type="text" id="garage_total" value="" /> 

You could also replace the filter function with just:

.filter(isFinite)

The signature of this function will act as a callback in the filter.


In the following example: You could either give each of the inputs a class name to query for, or you can find the parent of the input and then find its children.

 const NUMBER_FIELDS = document.getElementById('number-fields'); // Main addField(NUMBER_FIELDS); function updateSum(childNodes, findNumFields) { var sum = calculateSum((function(children) { return findNumFields ? children.map(function(child) { return child.firstChild; }) : children; }([].slice.call(childNodes)))); document.getElementById('sum-val').innerHTML = sum; } function calculateSum(items) { return items .map(function(item) { return parseNumber(item.value); }) .filter(function(val) { return !Number.isNaN(val); }) .reduce(function(sum, val) { return sum + val; }, 0); } function addField(targetEl) { var children = []; var wrapper = createElement('div', { className: 'number-field-wrapper' }); children.push(addEvent(createElement('input', { type: 'number', class: 'num-val', value: '' }), 'change', function(e) { // FIND CHILDREN BY PARENT SELECTOR updateSum(findParent(e.target, '#number-fields').childNodes, true); })); children.push(createElement('input', { type: 'button', class: 'add-btn', value: '+' }, { 'click': function(e) { addField(NUMBER_FIELDS); } })); if (targetEl.hasChildNodes()) { children.push(createElement('input', { type: 'button', class: 'add-btn', value: '-' }, { 'click': function(e) { removeElement(e.target); // FIND CHILDREN BY CLASS NAME updateSum(document.getElementsByClassName('num-val'), false); } })); } return appendChildren(targetEl, appendChildren(wrapper, children)); } function createElement(tagName, options, listeners) { var el = document.createElement(tagName), i; if (options) { var attrs = Object.keys(options); for (i = 0; i < attrs.length; i++) { el.setAttribute(attrs[i], options[attrs[i]]); } } if (listeners) { var events = Object.keys(listeners); for (i = 0; i < events.length; i++) { addEvent(el, events[i], listeners[events[i]]); } } return el; } function appendChildren(targetEl, childElements) { if (arguments.length == 2 && !Array.isArray(childElements)) { childElements = [childElements]; } else if (arguments.length > 2) { childElements = [].slice.call(arguments, 1); } for (var i = 0; i < childElements.length; i++) { targetEl.appendChild(childElements[i]); } return targetEl; } function removeElement(targetEl) { targetEl.parentElement.parentElement.removeChild(targetEl.parentElement); } function findParent(el, selector) { while (el.parentNode) { if (el.id) { if ('#' + el.id === selector) { return el; } } else { if (el == el.ownerDocument.documentElement) { if (el.tagName === selector) { return el; } } else { for (var c = 1, e = el; e.previousElementSibling; e = e.previousElementSibling, c++); if (el.tagName + ":nth-child(" + c + ")" === el) { return el; } } el = el.parentNode; } } return null; } // Cross-Browser: Add event function addEvent(el, evt, fn) { if (el.addEventListener) { el.addEventListener(evt, fn, false); } else { el.attachEvent("on" + evt, function() { // set the this pointer same as addEventListener when fn is called return (fn.call(el, window.event)); }); } return el; } function parseNumber(str, radix) { return str.indexOf('.') > -1 ? parseFloat(str) : parseInt(str, radix || 10); } 
 <h2>Number Summation</h2> <form id="summation-form"> <div id="number-fields"></div> <div id="summation-field"> <label>Total:</label> <span id="sum-val">0</span> </div> </form> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM