How can I get difference between old value and the changed one?
$('input[name ="refresh"]').on("change paste keyup", function() {
???
});
So, this code (from another question) detects an input change, the input itself is number only, user set input's value from 10 to 25, how to get the difference between old and new values without pre-loading default values? By the way, default values bigger than 0.
Read the defaultValue of the element and it will have the initial value.
$('input').on("input", function() {
var defaultValue = +this.defaultValue;
var currentValue = +this.value;
console.log("defaultValue", currentValue, defaultValue, currentValue - defaultValue);
});
$('input').on("change", function() {
var lastValue = this.dataset.last || this.defaultValue;
var currentValue = +this.value;
this.dataset.last = currentValue;
console.log("last value", currentValue, lastValue, currentValue - lastValue);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="number" value="10" />
<input type="number" value="0" />
<input type="number" value="7" />
Or if you want to know what it was from the last time it was changed
$('input').on("change", function() {
var lastValue = this.dataset.last || this.defaultValue;
var currentValue = +this.value;
this.dataset.last = currentValue;
console.log("last value", currentValue, lastValue, currentValue - lastValue);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="number" value="10" />
<input type="number" value="0" />
<input type="number" value="7" />
You can store the previous value with the dataset property of the element. Just wrap your listener to access and update the appropriate properties/attributes.
const valueChangeWrapper = (e, func) => {
const
currVal = e.target.value,
prevVal = e.target.dataset.previousValue;
func(currVal, prevVal, e);
e.target.dataset.previousValue = e.target.value;
}
const changeListener = (curr, prev, e) => {
console.log(`Id: ${e.target.id}, Curr: ${curr}, Prev: ${prev}`);
};
const wrappedChangeListener = e => valueChangeWrapper(e, changeListener);
document.querySelectorAll('.listen').forEach(el => {
el.addEventListener('change', wrappedChangeListener);
el.addEventListener('paste', wrappedChangeListener);
el.addEventListener('keyup', wrappedChangeListener);
});
.as-console-wrapper { max-height: 4em !important; }
body {
display: grid;
grid-auto-flow: row;
grid-row-gap: 0.5em;
padding: 0.25em;
}
<input type="text" class="listen" id="input-1" />
<input type="text" class="listen" id="input-2" />
<input type="text" class="listen" id="input-3" />
<input type="text" class="listen" id="input-4" />
Related
I have a working script but I don't know how to use addEventlistener instead of onfocus & onmousewheel. And how to apply it to many elements?
const input = document.getElementsByClassName("change-onscroll")[0];
input.value = input.min ? input.min : 0;
input.onfocus = () => {
input.onmousewheel = (e) => {
if (deltaY > 0 && +input.value <= +input.min) return;
e.deltaY < 0 ? input.value++ : input.value--;
};
};
<input type="number" name="num" class="change-onscroll" min="0" />
In case the OP wants to enable the scroll behavior for just focused input elements the OP needs to explicitly do both registering such a handling on any such element's 'focus' or 'focusin' event and deregistering the handling again on any such element's 'blur' or 'focusout' event
function handleNumberTypeMouseScroll(evt) {
const { currentTarget: input, deltaY } = evt;
const minValue = parseInt(input.min, 10);
if (deltaY > 0 && input.value <= minValue) return;
deltaY < 0 ? input.value++ : input.value--;
}
function deregisterMousewheelHandling({ currentTarget }) {
currentTarget
.removeEventListener('mousewheel', handleNumberTypeMouseScroll);
}
function registerMousewheelHandling({ currentTarget }) {
currentTarget
.addEventListener('mousewheel', handleNumberTypeMouseScroll);
}
document
.querySelectorAll('.change-on-focused-scroll')
.forEach(elmNode => {
elmNode.addEventListener('blur', deregisterMousewheelHandling);
elmNode.addEventListener('focus', registerMousewheelHandling);
});
<input type="number" name="num" class="change-on-focused-scroll" min="0" value="0" />
<input type="number" name="num" class="change-on-focused-scroll" min="5" value="5" />
<input type="number" name="num" class="change-on-focused-scroll" min="20" value="20" />
I have three fields that are calculated: coef, cost of materials, and manufacturing cost.
First, calculate its coef * cost of materials, result in manufacturing cost input.
The calculation of the total amount is the cost of materials * manufacturing cost, but I need the ability to change the amount of Manufacturing cost and get the total result
How to do this?
My code:
function sum(el) {
let coefEl = document.getElementById('coef');
let entrPriceEl = document.getElementById('enterence_price');
let extraEl = document.getElementById('extra');
let priceEl = document.getElementById('price');
let extraresultEl;
let result;
if (el.id === "enterence_price" || el.id === "extra" || el.id === "coef") {
extraextraresultEl = parseFloat(coefEl.value) * parseFloat(entrPriceEl.value);
extraEl.value = extraextraresultEl;
result = (parseFloat(entrPriceEl.value) * parseFloat(coefEl.value) + parseFloat(extraEl.value));
if (!isNaN(result)) {
priceEl.value = result.toFixed(2);
}
} else if (el.id === "enterence_price" || el.id === "extra" || el.id === "coef") {
result = parseFloat(entrPriceEl.value) * parseFloat(extraEl.value);
if (!isNaN(result)) {
priceEl.value = result;
}
}
}
<label>Coefficient<br></label>
<input type="text" value="2" id="coef" onkeyup="sum(this);">
<br>
<label>The cost of materials<br></label>
<input type="text" value="2000" id="enterence_price" onkeyup="sum(this);">
<br>
<label>Manufacturing cost<br></label>
<input type="text" id="extra" onkeyup="sum(this);">
<br>
<label>Sum<br></label>
<input type="text" id="price" onkeyup="sum(this);">
<br>
You need to apply a different function on mf cost input, because if you will use the same function, it will never let you alter the value, because its value also getting generated from the same function you write for above 2 values
if you need something else, pls feel free to comment
let coefEl = document.getElementById('coef');
let entrPriceEl = document.getElementById('enterence_price');
let extraEl = document.getElementById('extra');
let priceEl = document.getElementById('price');
function sum(el) {
let extraresultEl;
if (el.id === "enterence_price" || el.id === "extra" || el.id === "coef") {
extraextraresultEl = parseFloat(coefEl.value) * parseFloat(entrPriceEl.value);
extraEl.value = extraextraresultEl;
result = (parseFloat(entrPriceEl.value) * parseFloat(coefEl.value) + parseFloat(extraEl.value));
if (!isNaN(result)) {
priceEl.value = result.toFixed(2);
}
} else if (el.id === "enterence_price" || el.id === "extra" || el.id === "coef") {
result = parseFloat(entrPriceEl.value) * parseFloat(extraEl.value);
if (!isNaN(result)) {
priceEl.value = result;
}
}
}
function canBeChnaged(el){
var coefVal = parseInt(coefEl.value);
var costofMatVal = parseInt(entrPriceEl.value);
var mfCostVal = parseInt(extraEl.value);
var finalSum = (coefVal * costofMatVal) + mfCostVal;
priceEl.value = finalSum.toFixed(2);
}
<label>Coefficient<br></label>
<input type="text" value="2" id="coef" onkeyup="sum(this);">
<br>
<label>The cost of materials<br></label>
<input type="text" value="2000" id="enterence_price" onkeyup="sum(this);">
<br>
<label>Manufacturing cost<br></label>
<input type="text" id="extra" onkeyup="canBeChnaged(this);">
<br>
<label>Sum<br></label>
<input type="text" id="price" onkeyup="sum(this);">
<br>
A more succinct way is to is to wrap everything into a <form> then listen for the input event. The input event will trigger a call to an event handler (in the example below it is function calc(e)) whenever the user enters data in a form control (in this case all <input>s of <form>). Use properties of HTML elements like type and step to control and validate user input. References to previously mentioned topics are located after the example below.
Details are commented in example below
// Register the <form>
const form = document.forms[0];
// Register all form controls of <form>
// In this case all <input> and <output>
const data = form.elements;
// Run function calc() if any valid user input is entered in <form>
form.oninput = calc;
// Pass the event
function calc(e) {
// Convert any valid user input of the <input>s into a real number
const c = parseFloat(data.cof.value);
const m = parseFloat(data.mat.value);
const l = parseFloat(data.lab.value);
// Reference the <output>
const s = data.sum;
// Realistic formula
const t = (c * m) + l;
// Display the value of output as the result of formula
s.value = t.toFixed(2);
}
:root,
input,
output {
font: 400 6vh/10vh Consolas;
}
label,
input,
output {
display: inline-block;
}
label {
width: 9ch;
}
input,
output {
height: 1.5ch;
width: 12ch;
text-align: right;
}
#cof {
width: 6ch;
text-align: center;
color: blue;
}
<form>
<label>Markup</label>
<input id="cof" type="number" value="2">
<br>
<label>Materials</label>
<input id='mat' type="number" value="0.00" step=".01">
<br>
<label>Labor</label>
<input id='lab' type="number" value='0.00' step=".01">
<hr>
<label>Total: </label>
<output id='sum'>0.00</output>
</form>
Reference
HTMLFormControlCollection
HTMLFormElement
<input> Element
I am attempting to in React JS to get the sum of a group inputs, and put the sum of their total values in a div tag.
I am trying to run this event whenever a user types in any of the inputs
The problem is I am sure React has a proper way to do this!
This is my feeble attempt (please go easy - I am new to coding :)
HTML
<input type="number" id="comp1" name="comp1" onChange={this.handleTotal} />
<input type="number" id="comp2" name="comp2" onChange={this.handleTotal} />
<input type="number" id="comp3" name="comp3" onChange={this.handleTotal} />
<input type="number" id="comp4" name="comp4" onChange={this.handleTotal} />
<input type="number" id="comp5" name="comp5" onChange={this.handleTotal} />
<input type="number" id="comp6" name="comp6" onChange={this.handleTotal} />
<div id=total></div>
JS
handleTotal = e => {
// Grab all inputs that start with ID 'comp'
let inputs = document.querySelectorAll('[id^="comp"]');
// Trying to loop through the values and get the sum of all inputs
for (var i = 0; i < inputs.length; i++) {
let totalVal = inputs[i].value
console.log(totalVal);
}
//Trying to grab total values of all inputs and put in element
document.getElementById('total').innerHTML = totalVal;
}
At the moment you are not utilizing any of the React's data binding.
Best to use React's state to hold the values of the total and all the comp inputs.
I've also used the .reduce method in order to calculate the total for each of the input fields' values. But you can achieve the same thing with a for loop.
JSFiddle: Alternative "calculateTotal" function with for loop
More information on Input handling in React
class App extends React.Component {
constructor() {
super();
this.state = {
total: 0,
numbers: {
comp1: 1,
comp2: 0,
comp3: 4,
comp4: 0,
comp5: 0,
comp6: 0
}
};
}
componentDidMount() {
// Calculates the total after component is mounted
this.setState({ total: this.calculateTotal(this.state.numbers) });
}
calculateTotal = (numbers) => {
return Object.entries(numbers).reduce((finalValue, [key, value]) => {
if (value === "") {
// if entered value is empty string "", omits it
return finalValue;
}
return finalValue + value;
}, 0);
}
handleTotal = (e) => {
const { value, name } = e.target; // gets the name and value from input field
const parsedValue = value === "" ? "" : parseFloat(value); // parses the value as a number or if empty treats it as empty string ""
this.setState((prevState) => {
// creates new immutable numbers object, using previous number values and the currently changed input value
const updatedNumbers = {
...prevState.numbers,
[name]: parsedValue
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
};
// calculates the new total from updated numbers:
const newTotal = this.calculateTotal(updatedNumbers);
return {
numbers: updatedNumbers,
total: newTotal
}
})
}
render() {
return (
<div>
<input type="number" name="comp1" onChange={this.handleTotal} value={this.state.numbers.comp1} />
<input type="number" name="comp2" onChange={this.handleTotal} value={this.state.numbers.comp2}/>
<input type="number" name="comp3" onChange={this.handleTotal} value={this.state.numbers.comp3}/>
<input type="number" name="comp4" onChange={this.handleTotal} value={this.state.numbers.comp4}/>
<input type="number" name="comp5" onChange={this.handleTotal} value={this.state.numbers.comp5}/>
<input type="number" name="comp6" onChange={this.handleTotal} value={this.state.numbers.comp6}/>
<div id="total">{this.state.total}</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You just re-assign variable in every iteration of a loop. Change to smth like this:
handleTotal = e => {
// Grab all inputs that start with ID 'comp'
let inputs = document.querySelectorAll('[id^="comp"]');
// Trying to loop through the values and get the sum of all inputs
let totalVal=0
for (var i = 0; i < inputs.length; i++) {
totalVal += inputs[i].value
console.log(totalVal);
}
//Trying to grab total values of all inputs and put in element
document.getElementById('total').innerHTML = totalVal;
}
+= operator just adds value of next element to total variable. it is equal to totalVal = totalVal + inputs[i].value
const handleFormSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
let total = 0;
for (let [key, value] of formData.entries()) {
total += value * 1;
}
document.querySelector('#total').textContent = total;
};
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('form');
form.addEventListener('submit', handleFormSubmit, false);
});
<form>
<input type="number" id="comp1" name="comp1" />
<input type="number" id="comp2" name="comp2" />
<input type="number" id="comp3" name="comp3" />
<input type="number" id="comp4" name="comp4" />
<input type="number" id="comp5" name="comp5" />
<input type="number" id="comp6" name="comp6" />
<button type="submit">submit</button>
</form>
<span>total</span>
<div id=total></div>
i know this has been asked before but i can't seem to get this right. I need to take input values from two text boxes and add it to another and that answer should appear in the 3rd textbox after both boxes are typed in. Nothing seems to be happening however though. Thanks
Here's the HTML
//Input 1
<input name="attribute_campaign_addon_one_time_cost_value" id="am_attribute_campaign_addon_one_time_cost_value">
//Input 2
<input name="attribute_campaign_addon_total_monthly_cost_value" id="attribute_campaign_addon_total_monthly_cost_value">
//Input 3 where added answer should go
<input name="attribute_campaign_addon_total_monthly_cost_calculated_value" id="am_attribute_campaign_addon_total_monthly_cost_calculated_value" value="">
//JQ
var $oneTimeCostField = $('#am_attribute_campaign_addon_one_time_cost_value');
var $recurringTotalCostField = $('#am_attribute_campaign_addon_total_monthly_cost_value');
var $totalRetailAmountField = $('#am_attribute_campaign_addon_total_monthly_cost_calculated_value');
function calcVal() {
var num1 = $oneTimeCostField.val();
var num2 = $recurringTotalCostField.val();
var result = parseInt(num1) + parseInt(num2);
if (!isNaN(result)) {
$totalRetailAmountField.val() = result;
}
}
calcVal();
$(num1, num2).on("keydown keyup", function() {
calcVal();
});
Your selector for the onkeyup/down is wrong, and your total field has the wrong id.
The result can be set like this: $totalRetailAmountField.val(result);
//JQ
var $oneTimeCostField = $('#am_attribute_campaign_addon_one_time_cost_value');
var $recurringTotalCostField = $('#am_attribute_campaign_addon_total_monthly_cost_value');
var $totalRetailAmountField = $('#am_attribute_campaign_addon_total_monthly_cost_calculated_value');
function calcVal() {
var num1 = $oneTimeCostField.val();
var num2 = $recurringTotalCostField.val();
var result = parseInt(num1, 10) + parseInt(num2, 10);
console.log("calcVal ", num1,num2, result);
if (!isNaN(result)) {
$totalRetailAmountField.val(result);
}
}
calcVal();
$oneTimeCostField.on("keydown keyup", function() {
calcVal();
});
$recurringTotalCostField.on("keydown keyup", function() {
calcVal();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
//Input 1
<input name="attribute_campaign_addon_one_time_cost_value" id="am_attribute_campaign_addon_one_time_cost_value">
//Input 2
<input name="attribute_campaign_addon_total_monthly_cost_value" id="am_attribute_campaign_addon_total_monthly_cost_value">
//Input 3 where added answer should go
<input name="attribute_campaign_addon_total_monthly_cost_calculated_value" id="am_attribute_campaign_addon_total_monthly_cost_calculated_value" value="">
http://api.jquery.com/val/
Jquery input value is set as follows:
$totalRetailAmountField.val(result);
First thing, I have never seen name & id such big value. this is not only cause problem in readability but also introduce error like unwanted space in id
Secondly num1 & num2 are already jquery object then what is the use of $(num1, num2)
Thirdly update the value of the third input by passing the vale as function argument $totalRetailAmountField.val(result);
var $oneTimeCostField = $('#am_attribute_campaign_addon_one_time_cost_value');
var $recurringTotalCostField = $('#attribute_campaign_addon_total_monthly_cost_value');
var $totalRetailAmountField = $('#am_attribute_campaign_addon_total_monthly_cost_calculated_value');
function calcVal() {
var num1 = $oneTimeCostField.val();
var num2 = $recurringTotalCostField.val();
var result = parseInt(num1) + parseInt(num2);
if (!isNaN(result)) {
$totalRetailAmountField.val(result);
}
}
$('#attribute_campaign_addon_total_monthly_cost_value,#am_attribute_campaign_addon_one_time_cost_value').on("keydown keyup", function() {
calcVal();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input name="attribute_campaign_addon_one_time_cost_value" id="am_attribute_campaign_addon_one_time_cost_value">
<input name="attribute_campaign_addon_total_monthly_cost_value" id="attribute_campaign_addon_total_monthly_cost_value">
<input name="attribute_campaign_addon_total_monthly_cost_calculated_value" id="am_attribute_campaign_addon_total_monthly_cost_calculated_value" value=" ">
This is a fairly verbose solution to your query.
Listen to change on each input and apply their respective values to the final answer input (input#fa)
const a1 = document.querySelector('#a1')
const a2 = document.querySelector('#a2')
const fa = document.querySelector('#fa')
const answers = []
const _handleFinalAnswer = () => (fa.value = (+answers[0] || 0) + (+answers[1] || 0))
a1.addEventListener('change', e => {
const { value } = e.target
answers[0] = value
_handleFinalAnswer()
})
a2.addEventListener('change', e => {
const { value } = e.target
answers[1] = value
_handleFinalAnswer()
})
<input type="number" step="any" name="answer 1" id="a1" />
<input type="number" step="any" name="answer 2" id="a2" />
<input name="final answer" id="fa" />
Or here is a more dynamic way to calculate all possible amount of inputs to achieve a final sum but it could still be done with two inputs :-)
const answersInputs = document.querySelectorAll('input.answer')
const finalAnswer = document.querySelector('#fa')
const _getSummedValues = () => (
[...answersInputs]
.map(input => +input.value || 0)
.reduce((prev, curr) => prev+curr, 0)
)
const _setFinal = () => finalAnswer.value = _getSummedValues()
answersInputs.forEach(input => input.addEventListener('change', _setFinal))
<input type="number" step="any" name="answer 1" class="answer" />
<input type="number" step="any" name="answer 2" class="answer" />
<input type="number" step="any" name="answer 3" class="answer" />
<input type="number" step="any" name="answer 4" class="answer" />
<input type="number" step="any" name="answer 5" class="answer" />
<input type="number" step="any" name="answer 6" class="answer" />
<input type="number" step="any" name="answer 7" class="answer" />
<input name="final answer" id="fa" />
I created two input fields where they should substract from each other keeping a max value at 100.
Currently it substracted value is shown in the second value. I want it to be interchangeable. Irrespective of whether I put in first or second input field, the answer shows in the other.
Could someone help?
function updateDue() {
var total = parseInt(document.getElementById("totalval").value);
var val2 = parseInt(document.getElementById("inideposit").value);
// to make sure that they are numbers
if (!total) { total = 0; }
if (!val2) { val2 = 0; }
var ansD = document.getElementById("remainingval");
ansD.value = total - val2;
var val1 = parseInt(document.getElementById("inideposit").value);
// to make sure that they are numbers
if (!total) { total = 0; }
if (!val1) { val1 = 0; }
var ansD = document.getElementById("remainingval");
ansD.value = total - val1;
}
<input type="hidden" id="totalval" name="totalval" value="100" onchange="updateDue()">
<div>
Enter Value:
<input type="text" name="inideposit" class="form-control" id="inideposit" onchange="updateDue()">
</div>
<div>
Substracted:
<input type="text" name="remainingval" class="form-control" id="remainingval" onchange="updateDue()">
</div>
The simple way to achieve this would be to group the inputs by class and attach a single event handler to them. Then you can take the entered value from 100, and set the result to the field which was not interacted with by the user. To do that in jQuery is trivial:
$('.updatedue').on('input', function() {
var total = parseInt($('#totalval').val(), 10) || 0;
var subtracted = total - (parseInt(this.value, 10) || 0);
$('.updatedue').not(this).val(subtracted);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="hidden" id="totalval" name="totalval" value="100" />
<div>
Enter Value:
<input type="text" name="inideposit" class="updatedue form-control" id="inideposit" />
</div>
<div>
Subtracted:
<input type="text" name="remainingval" class="updatedue form-control" id="remainingval" />
</div>
You can easily validate this so that outputs < 0 and > 100 can be discounted, if required.
Edit your code as below
function updateDue(box) {
var total = parseInt(document.getElementById("totalval").value);
if(box == 1){
var val = parseInt(document.getElementById("inideposit").value);
// to make sure that they are numbers
if (!total) { total = 0; }
if (!val) { val = 0; }
var ansD = document.getElementById("remainingval");
ansD.value = total - val;
}else if(box == 2){
var val = parseInt(document.getElementById("remainingval").value);
// to make sure that they are numbers
if (!total) { total = 0; }
if (!val) { val = 0; }
var ansD = document.getElementById("inideposit");
ansD.value = total - val;
}
}
<input type="hidden" id="totalval" name="totalval" value="100" onchange="updateDue(0)">
<div>
Enter Value:
<input type="text" name="inideposit" class="form-control" id="inideposit" onchange="updateDue(1)">
</div>
<div>
Substracted:
<input type="text" name="remainingval" class="form-control" id="remainingval" onchange="updateDue(2)">
</div>