简体   繁体   中英

How to dynamically select elements with document.querySelectorAll() for function call?

I have been working on this fiddle:

https://jsfiddle.net/j1vrb7to/165/

The code in that fiddle is this:

HTML:

<div id="CalculationContainer">
  <input type="numbers" class="form-control new-tuition" /> <br />
  <input type="numbers" class="form-control new-tuition" /> <br />
  <input type="numbers" class="form-control new-tuition" /><br /><br />
  <input type="numbers" id="new-tuition-total" disabled="disabled" /><br /> <br />

  <input type="numbers" class="form-control new-state" /> <br />
  <input type="numbers" class="form-control new-state" /> <br />
  <input type="numbers" class="form-control new-state" /><br /><br />
  <input type="numbers" id="new-state-total" disabled="disabled" />
</div>

JavaScript:

const NewTuitionInputs = document.querySelectorAll("div#CalculationContainer > input.new-tuition");
const NewStateInputs = document.querySelectorAll("div#CalculationContainer > input.new-state");

NewTuitionInputs.forEach(function(input) {
  input.onchange = function() {
    var total = 0;
    NewTuitionInputs.forEach(function(input) {
      total += parseInt(input.value);
    });
    document.getElementById("new-tuition-total").value = total;
  }
});

NewStateInputs.forEach(function(input) {
  input.onchange = function() {
    var total = 0;
    NewStateInputs.forEach(function(input) {
      total += parseInt(input.value);
    });
    document.getElementById("new-state-total").value = total;
  }
});

As the users enter values into the textboxes, I want to update the value of another field to display running totals. Ultimately I will need to keep track of 20+ running totals on my form. Instead of maintaining 20+ functions, is it possible to use a single function to calculate running totals on the fly? Here is some pseudocode to demonstrate what I'm thinking:

var ThisInput = document.querySelectorAll("div#CalculationContainer > input.[INPUT_CLASS_PARAMETER_HERE]");

ThisInput.forEach(function(input) {
  input.onchange = function() {
    var total = 0;
    ThisInput.forEach(function(input) {
      total += parseInt(input.value);
    });
    document.getElementById("[DYNAMICALLY_CHOOSE_WHERE_TO_DISPLAY").value = total;
  }
});

You have a convention that the inputs have a class and then the total has an id with that class name plus -total . You can use this to your advantage in making a general purpose function:

function trackTotals(className){
    var inputs = document.querySelectorAll(`div#CalculationContainer > input.${className}`);
    inputs.forEach(input => {
      input.addEventListener("change",()=>{
        var total = [...inputs].reduce((acc,i) => acc + (parseInt(i.value,10) || 0),0);
        document.getElementById(`${className}-total`).value = total;
      })
    })
}

Usage would then be:

trackTotals("new-tuition");
trackTotals("new-state");
// whatever else that follows same conventions

Live example follows:

 trackTotals("new-tuition"); trackTotals("new-state"); function trackTotals(className){ var inputs = document.querySelectorAll(`div#CalculationContainer > input.${className}`); inputs.forEach(input => { input.addEventListener("change",()=>{ var total = [...inputs].reduce((acc,i) => acc + (parseInt(i.value,10) || 0),0); document.getElementById(`${className}-total`).value = total; }) }) }
 <div id="CalculationContainer"> <input type="numbers" class="form-control new-tuition"/> <br/> <input type="numbers" class="form-control new-tuition"/> <br/> <input type="numbers" class="form-control new-tuition"/><br/><br/> <input type="numbers" id="new-tuition-total" disabled="disabled"/><br /><br /> <input type="numbers" class="form-control new-state"/> <br/> <input type="numbers" class="form-control new-state"/> <br/> <input type="numbers" class="form-control new-state"/><br/><br/> <input type="numbers" id="new-state-total" disabled="disabled"/> </div>

Yes, you can create a function that takes the id:

function doTotal(name) {
    var ThisInput = document.querySelectorAll(`div#CalculationContainer > input.${name}`);
    
    ThisInput.forEach(function(input) {
        input.onchange = function() {
            var total = 0;
            ThisInput.forEach(function(input) {
                total += parseInt(input.value);
            });
            document.getElementById(`${name}-total`).value = total;
        }
    });
}

Note that I'm using string templates to build the selector strings.

You can use the event delegation method:

 const calcContainer = document.getElementById('CalculationContainer'), sumElms = { tuition: { sum: document.getElementById('new-tuition-total'), elms: [...document.querySelectorAll('input.new-tuition')] }, state: { sum: document.getElementById('new-state-total'), elms: [...document.querySelectorAll('input.new-state')] } }; calcContainer.oninput= ({target}) => { if (.target.matches(',new-tuition. .new-state')) return let sumElm = target.matches('?new-tuition'). sumElms:tuition. sumElms.state sumElm.sum.value = sumElm.elms,reduce((se)=>s+e,valueAsNumber,0) }
 #CalculationContainer input { float: left; clear:both; width: 5em; } #CalculationContainer input:disabled { margin-bottom: 1em; font-weight: bold; color:black; }
 <div id="CalculationContainer"> <input type="number" class="form-control new-tuition" value="0"> <input type="number" class="form-control new-tuition" value="0"> <input type="number" class="form-control new-tuition" value="0"> <input type="number" id="new-tuition-total" disabled="disabled" value="0"> <input type="number" class="form-control new-state" value="0"> <input type="number" class="form-control new-state"value="0"> <input type="number" class="form-control new-state"value="0"> <input type="number" id="new-state-total" disabled="disabled"value="0"> </div>

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