Here's how it's supposed to work. By default there are two sets of input fields where the percentage fields have a value of 50% each. Now whenever a new input field is added, the percentage field value should be divided between all of them, for example, if there are 3 sets then percentage fields should have 33.33% each. If there are 4 then 25% each. Now this part works perfectly fine.
Now I'm trying to add more features on top of it. I'll just explain the features in brief and the problem associated with it.
When a user clicks on percentage input field, the previous value disappears and the user types a new percentage value and it gets divided between the two input fields. But the issue with this is it adds two "%" signs at the end of the value which the user just typed in.
The second issue is, suppose the user types in a new percentage value in the first or second percentage field and then adds a new input field through Add Field button, the percentages doesn't divide between all the input values. The new input field doesn't take into consideration the new percentage value. One reason I could think of is the percInput variable doesn't get updated somehow.
The third issue is similar to the second one. If the user adds a new input field first and then types in a percentage value in that new input field, then percentage values are not divided at all. This could also be because of percInput variable not being updated. Another issue associated with this is, clicking on the new percentage input field doesn't remove the previous value, like it does on the default fields.
This is a weird one. If the user clicks on the percentage input field but doesn't adds a value and moves on to adding a new field, then the percentage values just divide between all of them.
All of these issues are somewhat related to each other and I have feeling a that they are all because of one variable, which is, percInput. I guess it doesn't get updated when new input fields are added. Previously I used calculatePercentage function to update the percInput variable, where it worked. But it doesn't work when I tried to use it in the situations above.
Here's the code I tried so far:
const form = document.querySelector("form");
const span = document.querySelector("span");
const addBtn = document.querySelector("#addField");
const html = `
<div class="url-pair">
<input type="url" placeholder="3">
<input type="text" class="perc">
<button class="delete-btn" type="button">Delete</button>
</div>
`;
// percentage variable and percentage calculation for the first time
let percInput = document.querySelectorAll('.urls-container .perc');
let percentage = (100 / percInput.length).toFixed(0).toString() + "%";
percInput.forEach((item) => {
item.setAttribute("value", percentage);
});
const removeField = (e) => {
if (!e.target.classList.contains('delete-btn')) return;
e.target.parentElement.remove();
calculatePercentage();
}
// percentage input variable update and percentage calculation
const calculatePercentage = () => {
percInput = document.querySelectorAll('.urls-container .perc');
percentage = (100 / percInput.length).toFixed(0).toString() + "%";
percInput.forEach((item) => {
item.setAttribute("value", percentage);
});
}
// remove a field
form.addEventListener('click', removeField);
// add input field
addBtn.addEventListener('click', () => {
span.insertAdjacentHTML("beforeBegin", html);
calculatePercentage();
});
const percInputChange = function() {
let val = this.value,
$allInputs = $(percInput);
if(val > 100) {
$allInputs.val((100 / $allInputs.length) + "%");
calculatePercentage();
}else {
$(percInput).not(this).val( (100 - val) / ($allInputs.length - 1) + "%");
setTimeout(() => {
this.value = this.value + "%";
}, 500);
calculatePercentage();
return;
}
};
// event listener when user types in a new percentage value
$( percInput ).on('keyup', percInputChange);
// event listener to hide previous input value
$( percInput ).focus(function() {
this.value = "";
});
// event listener to divide the percetange values when the user clicks away
$( percInput ).blur(function() {
if(this.value === ""){
percInput.forEach(item => {
item.value = ( 100 / percInput.length ).toFixed(0).toString() + "%";
return;
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="#" method="POST">
<div class="urls-container">
<div class="url-pair">
<input type="url" placeholder="1">
<input type="text" class="perc">
<button class="delete-btn" type="button">Delete</button>
</div>
<div class="url-pair">
<input type="url" placeholder="2">
<input type="text" class="perc">
<button class="delete-btn" type="button">Delete</button>
</div>
<span></span>
</div>
<div>
<div>
<button type="button" id="addField">Add Field</button>
</div>
<div>
<button type="submit">Create</button>
</div>
</div>
</form>
I know this post is a weird one with so many problems. But please bear with me as I am still learning and I won't be able to learn if I don't push myself into these complex coding problems and get stuck. I've spent the whole day yesterday trying different methods based on the knowledge I have. The post would be really big if I put all the methods I tried. So please bear with me. Please help a fellow coder in need. Thanks
PS. I used jQuery and JS together which is not the right thing to do. But I will refactor and change them once I fix the issues.
PS.
I am not quite sure what exactly you want to achieve with your script. But I had a go at making a fresh start by removing redundant bits. The following snippet will allow you to add or remove input lines and it will adjust the percentages accordingly.
Maybe you can specifiy how you want the script to react on any user input?
// add flields:
function addfields(){
let all=$('.urls-container'), r=$('div:last',all).clone(),
url=r.find('input[type=url]')[0];
url.placeholder=+url.placeholder+1;
$('.perc',r).removeAttr('data-manual');
all.append(r); calcperc();
}
// even distribution:
function calcperc(){
let fix=$('.perc[data-manual]'),sum=0;
fix.each(function(){sum+=parseFloat(this.value)});
let rest= $('.perc').not(fix);
rest.val(((100-sum)/rest.length).toFixed(2)+'%')
}
// manual distribution:
function recalc(){let inps=$('.perc'),cur=parseFloat(this.value);
if (inps.length>1){
this.value=cur.toFixed(2)+'%'; this.dataset.manual=1;
calcperc();
} else this.value="100%"
}
// delegated event management:
$('form')
.on('submit',function(e){e.preventDefault()}) // de-activate submit for testing
.on('change','.perc',recalc)
.on('click','.delete-btn',function(){$(this).parent().remove();calcperc()})
.on('click','#addField',addfields);
// initial distribution:
calcperc();
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<form action="#" method="POST">
<div class="urls-container">
<div class="url-pair">
<input type="url" placeholder="1">
<input type="text" class="perc">
<button class="delete-btn" type="button">Delete</button>
</div>
<div class="url-pair">
<input type="url" placeholder="2">
<input type="text" class="perc">
<button class="delete-btn" type="button">Delete</button>
</div>
<span></span>
</div>
<div>
<div>
<button type="button" id="addField">Add Field</button>
</div>
<div>
<button type="submit">Create</button>
</div>
</div>
</form>
My curent version of recalc() allows you to overwrite one of the percentage values. All other values will then be adjusted, so the total is 100% again.
Please also note that in my version the recalc() gets fired on the input event and not the keyup event, otherwise the action of adding the percentage sign would seriously interfere with any input attempt by the user.
Edit
The lastet edit involves "marking" manually changed percentages with a data-manual attribute in the input field. This will protect that field from future recalculations. The remaining percentages will be distributed evenly among the non-fixed fields.
Related
I'm making site to make table game calculations easier. So, if simplify, I have a form like this:
<input id="x"/>
<input id="y"/>
And I want to collect data of this form in live time and process them like this immediately:
<span id="x-plus-y"/> in html and document.getElementById('x-plus-y').innerHTML = x*y in js
It's very simplified but I think you got the thought.
My question is how to process x+y immediately as the user enters the values into the input fields.
This is the simple approach you can go through. I have attached a keyup event listener on every input and then invoking the updateResult function which calculates the product and displays it within the result div.
HTML
Number 1 : <input type="number">
<br><br>
Number 2 : <input type="number">
<br><br>
<div id="result">
</div>
JS
const inputs = Array.from(document.querySelectorAll("input"));
const resultDiv = document.querySelector("div");
const numbers = [];
for(const input of inputs) {
input.addEventListener('keyup', updateResult);
}
function updateResult() {
let product = 1;
for(const input of inputs) {
product*= parseInt(input.value,10);
}
if(!isNaN(product)) {
resultDiv.innerHTML = "Product: " + product;
}
}
Please help me, i've the javascript allmost done. Only the last part is very difficult.
I've used the calculator plugin for contact form7, to calculate the BMI, this works perfectly.
To hide the BMIhigh text also works, and the click
Length (cm):
<label id="centi">[number* cm min:130 max: 220]</label>
Hight (kilo):
<label id="kilo">[number* kilo min:40 max:140]</label>
<label id="calcbutton">[calculate_button "calculate"]</label>
<label id="calc">[calculation calculate precision:1 "kilo / ((cm / 100) * (cm / 100))"]</label>
<label id="BMIhigh">
Your BMI is too high
</label>
[submit "Send"]
At the bottom i've got the following code:
// Hide the BMIhigh text field by default
document.getElementById("BMIhigh").style.display = 'none';
// On every 'click' on the calculator call the displayTextField function
document.getElementById("calcbutton").addEventListener("click", displayTextField);
function displayTextField() {
// Get the inserted values for centi and kilo and calculate the BMI again
// for the function without the help of the calculator build in into the extra plugin.
var centimeter = +document.getElementById("centi").value;
var kilogram = +document.getElementById("kilo").value;
var BMIvar = kilogram / ( ( centimeter / 100 ) * ( centimeter / 100 ) );
// If BMIvar higher than 30 it is too high, the text should show.
// THIS LAST PART DOES NOT WORK
if(BMIvar > 30) {
document.getElementById("BMIhigh").style.display = 'block';
} else {
document.getElementById("BMIhigh").style.display = 'none';
}
}
</script> ```
Your variable BMIvar never get evaluated because,
var centimeter = +document.getElementById("centi").value;
var kilogram = +document.getElementById("kilo").value;
these variables are not being populated properly. CF7 converts field tags into <span> encapsulated <input/> fields,
<label id="centi">
<span class="wpcf7-form-control-wrap cm">
<input type="number" name="cm" value="" class="wpcf7-form-control wpcf7-number wpcf7-validates-as-required">
</span>
</label>
and as such getElementById returns the <label/> element and not the <input/> one. element.value only works for <input/> fields. Try instead to use getElementsByName and replace the above 2 lines with,
var centimeter = 1.0*document.getElementsByName("cm")[0].value;
var kilogram = 1.0*document.getElementsByName("kilo")[0].value;
Here is a jsFiddle with a working example.
I’m looking for a way to automate a form.
Here are the details:
Extract a certain number (displayed in its html)
Do some calculations on the extracted number (percentage of that number)
Then automatically fill the remaining input fields with the result instead of typing it out.
This is a common occurrence in forms. The solution depends on what framework / libraries you're using. Assuming you're using none, here is how you might go about it:
https://jsfiddle.net/f52h1smj/1/
rough HTML:
<form>
<label for="number">Number: </label>
<input id="number" type="number" />
<br /> <br />
<label for="calculatedNumber">Calculated Number (50%): </label>
<input id="calculatedNumber" type="number" disabled="true" />
</form>
JS:
(() => {
//get the form element nodes
const $number = document.getElementById("number");
const $calculatedNumber = document.getElementById("calculatedNumber");
//add an event listen to the value you're going to use to pre calculate the other fields
$number.addEventListener("keyup", (e) => {
//it's value is available like so
const value = e.target.value;
//do some validation so that you're calculations don't throw exceptions
if (Number(value) !== 0 && !Number.isNaN(value)) {
//set the value of the other inputs to whatever you like by setting the 'value' property of the node.
$calculatedNumber.value = value / 2;
} else {
$calculatedNumber.value = null;
}
});
})();
These things become a lot simpler in frameworks like React and Angular.
I want to add two zeros to any number entered in a textbox when submitted.
For instance, if i enter 34 in a textbox and click on submit, it should be saved as 3400.
Could this be done on the fly too?
Depends on what you want to do after the submit. Especially: Do you want to interpret this as a number and simply multiply by 100 (34 * 100) or do you want to simply append something to the value? ("34" + "00")?
In the first case you would do this:
<input id="value" type="number" value="34"/>
<br>
<button onclick="submit()">Submit</button>
<script>
function submit() {
const input = document.getElementById("value");
const value = input.attributes.value;
input.value = parseInt(input.value) * 100;
}
</script>
In the second case this:
<input id="value" type="number" value="34"/>
<br>
<button onclick="submit()">Submit</button>
<script>
function submit() {
const input = document.getElementById("value");
const value = input.attributes.value;
input.value = input.value.toString() + '00';
}
</script>
A bit vague, but it sounds like you're looking for something like the following.
// Gather each element from the HTML, so you can access its input or update its display:
const input = document.getElementById('numberInput');
const button = document.getElementById('submit');
const display1 = document.getElementById('display1');
const display2 = document.getElementById('display2');
// Add a click event to the button, which gathers the text field value, ensures it's a number, and updates the display as requested:
button.addEventListener('click',() => {
const value = input.value;
// This if statement ensures that only numbers will be suffixed with be suffixed with two zeros:
if (isNaN(value)) {
alert('Please enter a valid number');
return;
}
// Update the display span's contents as requested. There are many ways of doing this. Here are a few;
// Here I'm taking the submitted value, and nesting it inside a string, alongside the two zeros. In cases of Infinity or .100, the result will still be the input suffixed with two zeros:
display1.innerHTML = `${value}00`;
// This method, on the other hand, will simply move the decimal to columns:
display2.innerHTML = value * 100;
});
<p>
Display 1: <span id="display1"></span>
</p>
<p>
Display 2: <span id="display2"></span>
</p>
<input type="text" id="numberInput">
<button id="submit">Submit</button>
You could always set an event listener that changes the number on exit of the form element, so something like this:
document.addEventListener('DOMContentLoaded', watchNums);
function watchNums() {
document.removeEventListener('DOMContentLoaded', watchNums);
Array.from(document.getElementsByClassName('number')).map(
number => {
number.addEventListener('blur', _ => {
number.value = parseInt(number.value) * 100;
})
}
)
}
<body>
<form action="/endpoint.htm" method="POST">
<input type="number" name="number-input" class="number">
<input type="number" name="other-number-input" class="number">
<button type="submit">Submit Numbers</button>
</form>
</body>
I have a bunch of div's that have the same functionality and I'm trying to write a function for them.
Basically they have a predetermined value and a user input value and those need to be multiplied.
I've looked through a bunch of other questions and this is the closest one I could find. Almost exactly, but none of those answers work.
Any help would be great. Thanks in advance!
<div>
<label>enter value for multiple here</label>
<input type="text" class="multiple" factor="foo1"/>
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
<label>enter value for multiple here</label>
<input type="text" class="multiple" factor="foo2"/>
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
</div>
Here's the JS:
$('.mulitplyBtn').click(function() {
var factor = $(this).closest('attr.factor').val();
var multiple = $(this)closest('.multiple').val();
answer = (factor * multiple);
};
This would work:
$('.multiplyBtn').click(function() { // you had multiplyBtn spelled wrong here
var cur = $('.multiplyBtn').index($(this)); // get index of clicked btn
var factor = $('.multiple').eq(cur).data('factor'); // get factor from matching input
var multiple = $('.multiple').eq(cur).val(); // get value from matching input
answer = (Number(factor) * Number(multiple)); // make sure both are numbers then multiply
alert(answer);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<label>enter value for multiple here</label>
<input type="text" class="multiple" data-factor="4" />
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
<br>
<label>enter value for multiple here</label>
<input type="text" class="multiple" data-factor="7" />
<button type="button" class="multiplyBtn">Click here to multiply these numbers</button>
</div>
In the first line you used " and ' try using the same quotes (I mean using ".multiplyBtn" or '.multiplyBtn' )
Second time, 3rd line you didn't use any quote when calling .multiple. So turn it in that format : var multiple = $(this)closest('.multiple').val()
let me know the result
You have at least two typos and are using the wrong jQuery function.
Typos:
$('.mulitplyBtn') should be $('.mulitplyBtn')
$(this)closest should be $(this).closest
Wrong function:
closest() searches the parents, and the only parent here is the DIV with no class. What you probably want is to use parent() to go up to the DIV, then find() to search the parent's children for a specific element:
$(this).parent().find('.multiple').val()
attr.factor does not work like this.
try it like this:
$('.multiplyBtn').click(function() {
var container = $(this).prev('.multiple'); //don't forget the "dot"
var multiple = container.val();
var factor = container.attr('factor'); //since it is the same container.
var answer = (factor * multiple); //what exactly are you tryin to multiply?
};