I am currently writing a simple calculator as an exercise.
I have a few input fields where the user can put certain values, then clicking a button a function is triggered where it does some calculations and shows the output in a table.
The input I am interested in is the following:
<p>Total eligible voters:
<input type="text" id="totalVoters" name="totalVoters" placeholder="0">
</p>
<p>Voter turnout:
<input type="text" id="voterTurnout" name="voterTurnout" placeholder="0">
</p>
<p>Percentage of ineligible bulletins:
<input type="text" id="ineligibleBulletins" name="ineligibleBulletins" placeholder="0">
</p>
<br><br>
Once that data is filled, the user has to fill however many votes they wish each party to receive. I can't figure out (a simple) way to show however many votes are still unaccounted for.
For example, if the user puts totalVoters = 1000 , voterTurnout = 50% , ineligibleBulletins = 10% the total unaccounted votes are (1-0.1)(0.51000) = 450.
And as the user starts filling the other field for voters per each party, say party1 = 50, I want to show (somewhere) however many (unaccounted) votes there are left, in this case 400.
I was considering some kind of a loop, but can't really figure out how to update the unaccountedVotes once a change occurs. Using JS.
CodePudding user response:
I would try setting up an event listener for changes made to the inputs. Then have it update the output whenever a change is made. But I'm fairly new to programming and there could be a simpler way.
CodePudding user response:
explanation in progress
function updateUnaccountedVotesFromBoundContext() {
const { output, total, turnout, ineligible } = this;
output
.value = Math.round(
(1 - (ineligible.valueAsNumber / 100)) *
(turnout.valueAsNumber / 100) *
total.valueAsNumber
);
}
function updateRangePseudoContent({ currentTarget }) {
currentTarget.setAttribute('value', currentTarget.value);
}
document
.querySelectorAll('[type="range"]')
.forEach(elmNode =>
elmNode.addEventListener('input', updateRangePseudoContent)
);
document
.querySelectorAll('fieldset')
.forEach(rootNode => {
const output = rootNode
.querySelector('output');
const total = rootNode
.querySelector('[data-name="total-voters"]');
const turnout = rootNode
.querySelector('[data-name="voter-turnout"]');
const ineligible = rootNode
.querySelector('[data-name="ineligible-bulletins"]');
rootNode
.addEventListener(
'input',
updateUnaccountedVotesFromBoundContext
.bind({ output, total, turnout, ineligible })
);
// initialization from all current elements data.
updateUnaccountedVotesFromBoundContext
.call({ output, total, turnout, ineligible });
});
fieldset { width: 70%; padding-top: 0; padding-bottom: 0; }
fieldset, label { margin: 5px 0; }
label { width: 90%; }
label, label > span, label > input {
position: relative;
display: block;
}
[type="range"] {
width: calc(100% - 10px - 4em);
}
[type="range"]::after {
position: absolute;
left: calc(100% 10px);
content: attr(value)' %';
width: 4em;
height: 1em,
}
output {
font-weight: bolder;
}
<fieldset>
<label>
<span>Total eligible voters</span>
<input type="number" min="0" step="1" value="1000" data-name="total-voters">
</label>
<label>
<span>Voter turnous</span>
<input type="range" min="0" max="100" value="50" step="0.1" data-name="voter-turnout">
</label>
<label>
<span>Percentage of ineligible bulletins</span>
<input type="range" min="0" max="100" value="10" step="0.1" data-name="ineligible-bulletins">
</label>
<label>
<span>Unaccounted votes</span>
<output>0</output>
</label>
</fieldset>
<fieldset>
<label>
<span>Total eligible voters</span>
<input type="number" min="0" step="1" value="25000" data-name="total-voters">
</label>
<label>
<span>Voter turnous</span>
<input type="range" min="0" max="100" value="70" step="0.1" data-name="voter-turnout">
</label>
<label>
<span>Percentage of ineligible bulletins</span>
<input type="range" min="0" max="100" value="5" step="0.1" data-name="ineligible-bulletins">
</label>
<label>
<span>Unaccounted votes</span>
<output>0</output>
</label>
</fieldset>