I'm working on a website and wanting to do advanced stuff (at least for me) that is way over my head. My javascript knowledge is extremely limited and need help with this.
I have an html form that accepts 5 text input fields labeled 1-5 representing a percentage distribution. I want to use javascript to do the following:
Read all fields and make sure the total sum is equal to 100.
Disable unnecessary fields when total sum equals 100.
Disable Submit button if total sum is not 100%.
Add the % at the end of the user entry.
I found two separate scripts to accomplish all this, one is javascript and the other one is JQuery. For some reason the JQuery is not working and it is yielding the following error:
Uncaught TypeError: $ is not a function
I've tried modifying the JQuery code, as suggested in multiple solutions online, like the following:
(function($){ "JQuery Code here" })(jQuery);
This get's rid of the error, however the JQuery code does not work.
Both the javascript.js and the JQuery.js files are being propperly enqueued in the WP theme's functions.php file.
Any help will be greately appreciated!!
HTML
<label for="entryFee">Entry Fee:</label>
<input id="entryFee" name="entry_fee" onblur="this.value = '$' + formatNumber(this.value, 1, 2, true)" type="text" value="" placeholder="$100.00" />
<h4>Prize Distribution</h4>
<label for="1stPlace">1st Place:</label> <input id="1stPlace" name="1st_place" type="text" onblur="this.value = formatNumber(this.value, 1, 0, true) + '%'" placeholder="60%" maxlength="3" size="4" class="percentageField" required />
<label for="2ndPlace">2nd Place:</label> <input id="2ndPlace" name="2nd_place" type="text" onblur="this.value = formatNumber(this.value, 1, 0, true) + '%'" placeholder="30%" maxlength="3" size="4" class="percentageField" />
<label for="3rdPlace">3rd Place:</label> <input id="3rdPlace" name="3rd_place" type="text" onblur="this.value = formatNumber(this.value, 1, 0, true) + '%'" placeholder="10%" maxlength="3" size="4" class="percentageField" />
<label for="4thPlace">4th Place:</label> <input id="4thPlace" name="4th_place" type="text" onblur="this.value = formatNumber(this.value, 1, 0, true) + '%'" placeholder="0%" maxlength="3" size="4" class="percentageField" />
<label for="5thPlace">5th Place:</label> <input id="5thPlace" name="5th_place" type="text" onblur="this.value = formatNumber(this.value, 1, 0, true) + '%'" placeholder="0%" maxlength="3" size="4" class="percentageField" />
<span id="percent">0</span>%
<input id="submitButton" type="submit" value="Submit" disabled>
</form>
Javascript
// Reformats a number by inserting commas and padding out the number of digits
// and decimal places.
//
// Parameters:
// number: The number to format. All non-numeric characters are
// stripped out first.
// digits: The minimum number of digits to the left of the decimal
// point. The extra places are padded with zeros.
// decimalPlaces: The number of places after the decimal point, or zero to
// omit the decimal point.
// withCommas: True to insert commas every 3 places, false to omit them.
function formatNumber(number, digits, decimalPlaces, withCommas)
{
number = number.toString();
var simpleNumber = '';
// Strips out the dollar sign and commas.
for (var i = 0; i < number.length; ++i)
{
if ("0123456789.".indexOf(number.charAt(i)) >= 0)
simpleNumber += number.charAt(i);
}
number = parseFloat(simpleNumber);
if (isNaN(number)) number = 0;
if (withCommas == null) withCommas = false;
if (digits == 0) digits = 1;
var integerPart = (decimalPlaces > 0 ? Math.floor(number) : Math.round(number));
var string = "";
for (var i = 0; i < digits || integerPart > 0; ++i)
{
// Insert a comma every three digits.
if (withCommas && string.match(/^\d\d\d/))
string = "," + string;
string = (integerPart % 10) + string;
integerPart = Math.floor(integerPart / 10);
}
if (decimalPlaces > 0)
{
number -= Math.floor(number);
number *= Math.pow(10, decimalPlaces);
string += "." + formatNumber(number, decimalPlaces, 0);
}
return string;
}
JQuery
(function($){
$('.percentageField').keyup( function () {
//limit the value to between 0 and 100
var thisVal = parseInt($(this).val(), 10);
if (!isNaN(thisVal)) {
thisVal = Math.max(0, Math.min(100, thisVal));
$(this).val(thisVal);
}
//get total of values
var total = 0;
$('.percentageField').each(function() {
var thisVal = parseInt($(this).val(), 10);
if (!isNaN(thisVal))
total += thisVal;
});
//change the value of the current entry to limit sum to 100
if (total > 100) {
$(this).val(thisVal - (total - 100));
total = 100;
}
if (total == 100) {
//enable submit button
$('#submit_button').removeAttr('disabled');
//disable empty input fields
$('.percentageField').each(function() {
var thisVal = parseInt($(this).val(), 10);
if (isNaN(parseInt($(this).val(), 10)) || thisVal == 0)
$(this).attr('disabled','disabled');
});
}
else {
//disable submit button
$('#submitButton').attr('disabled','disabled');
//enable all input fields
$('.percentageField').removeAttr('disabled');
}
//update percentage
$('#percent').html(total);
});
})(jQuery);
The JQuery script was running before the DOM was ready.
Enclosing the entire code set within $('document').ready(function() did the trick:
(function($){
$('document').ready(function()
{ <<JQuery Code>> });
})(jQuery);
Related
i want to make input percentage using javascript
<input type="text" class="form-control" id="amount" name="amount">
i made the js so when i input, it's adding %
var amount = document.getElementById('amount');
amount.addEventListener('input', function(e){
amount.value = amount.value.replace('%','') + '%';
})
but it still can input character, i want to only allow number 1-100, is it possible?
or maybe you have suggestion about what is better to input for percentage
HTML input type attribute allows number value so that it will only be able to accept number values.
And you can also pass a max attribute that will set a limit for entered number.
e.g.:
<input type="number" class="form-control" id="amount" name="amount" max="[YOUR_NUMBER]">
Edit:
You can still validate your input with a JS function.
<input type="text" class="form-control" id="amount" name="amount">
let amount = document.getElementById('amount');
amount.addEventListener('input', function(e){
amount.value = amount.value.replace('%','')
let tmpValue = +amount.value
amount.value = 0 <= tmpValue <= 100 ? tmpValue + '%' : "[VALUE IF NOT 1<AMOUNT<100]";
})
A little late. This is an interesting example. One could incorporate some more logic here. The example below only allows numbers between 0 and 100 and adds the % at the end. Once you have entered a number up to max one, you have to start again. a new logic would have to be built in here.
let amount = document.getElementById('amount');
amount.addEventListener('input', function(){
const n = amount.value.replace('%','');
if ( n >= 0 && n <= 100 ) {
amount.value = amount.value.replace('%','') + '%'
} else {
amount.value = n.slice(0, -1) + '%'
}
})
<input type="text" class="form-control" id="amount" name="amount">
I am new to Javascript/Jquery and I would like to compute the final rating based from the value in the text box for each function name [1st column of the table] (core function, support function, research services).
The formula based from example:
Final Rating Core Administrative Function = (4.6 + 4.3)/2 (because there are only 2 core functions average value is available) * 0.65
Final Rating Support Function = (4.3 + 4.3)/2 * 0.2275
Final Rating for Research Function = (4 + 4)/2 * 0.1225
The requirement is that everytime the A value column of each row changes the final rating change as well.
Here is the Jquery of on how I get the A value:
//GET THE AVERAGE PER ROW
$(".q-value, .e-value, .t-value").change(function(){
let currentRow = $(this).closest('tr');
let EValue = parseInt(currentRow.find('.e-value').val());
let QValue = parseInt(currentRow.find('.q-value').val());
let TValue = parseInt(currentRow.find('.t-value').val());
currentRow.find('.a-value').val((EValue + QValue + TValue ) / 3);
});
the .q-value, .e-value, .t-value, .a-value are all inside a class.
I add 3 input type for each final rating functions
<input type="number" class="form-control form-control-sm" id="core-total" name="total_core" readonly>
<input type="number" class="form-control form-control-sm" id="support-total" name="total_support" readonly>
<input type="number" class="form-control form-control-sm" id="research-total" name="total_research" readonly>
so the value for each function will be dump in there.
Please help me on this. Im stuck in a days.
With the help of my colleague, this is already resolved. I actually hardcoded an if statement in each input type for each functions (core, support etc..)
#if($row->function_name == 'Core Functions')
<input type="number" onchange="setFourNumberDecimal(this)" class="form-control form-control-sm a-value-core" name="A[]" style="width: 50px" readonly>
#elseif($row->function_name == 'Support Functions')
<input type="number" onchange="setFourNumberDecimal(this)" class="form-control form-control-sm a-value-support" name="A[]" style="width: 50px" readonly>
#endif
#if($row->function_name == 'Research and Extension Services')
<input type="number" onchange="setFourNumberDecimal(this)" class="form-control form-control-sm a-value-research" name="A[]" style="width: 50px" readonly>
#endif
After that. He created a JS function for computation.
//COMPUTE AVERAGE FOR EACH FUNCTION
function computeAvg() {
// For Core Functions
const corevalues = document.getElementsByClassName("a-value-core")
let avg = 0
let total = 0
let count = 0
for (let x = 0; x < corevalues.length; x++) {
if (corevalues[x].value !== "") {
count++
total = total + parseFloat(corevalues[x].value)
}
}
avg = (total / count) * 0.65
$('#core-total-average').val(isNaN(avg) ? "" : avg)
// For Support Functons
avg = 0
total = 0
count = 0
const supvalues = document.getElementsByClassName("a-value-support")
for (let x = 0; x < supvalues.length; x++) {
if (supvalues[x].value !== "") {
count++
total = total + parseFloat(supvalues[x].value)
}
}
avg = total / count * 0.2275
$('#support-total-average').val(isNaN(avg) ? "" : avg)
// For Research Services
avg = 0
total = 0
count = 0
const resvalues = document.getElementsByClassName("a-value-research")
for (let x = 0; x < resvalues.length; x++) {
if (resvalues[x].value !== "") {
count++
total = total + parseFloat(resvalues[x].value)
}
}
avg = total / count * 0.1225
$('#research-total-average').val(isNaN(avg) ? "" : avg)
}
I have two inputs that get multiplied and I need the result to be rounded down without trailing zeros. I have tried a few different built-in methods, such as number.toFixed(2), but they did not produce the desired result.
This issue can be reproduced by typing the numbers 20 and 6 into the first and second inputs here:
$(document).on("change", ".p-cell, .s-cell", () => {
var val1 = $(".p-cell").val();
var val2 = $(".s-cell").val();
var total = val1 / 100 * val2;
$(".w-cell").val(total).trigger("input");
});
<input class="p-cell" type="text" value="0" />
<input class="s-cell" type="text" value="0" />
<input class="w-cell" type="text" value="0" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You could use Number.prototype.toFixed(), .toFixed(2) if you want to show two decimals:
const $pCell = $(".p-cell");
const $sCell = $(".s-cell");
const $wCell = $(".w-cell");
$(document).on('input', '.p-cel, .s-cell', () => {
const val1 = $pCell.val() || 0;
const val2 = $sCell.val() || 0;
const total = (val1 / 100 * val2).toFixed(2);
$wCell.val(total);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="p-cell" type="text" value="0" />
<input class="s-cell" type="text" value="0" />
<input class="w-cell" type="text" value="0" readonly />
Additionally, if you want to remove any number of trailing zeroes, so 1.20 becomes 1.2 and 2.00 becomes 2, you could use String.prototype.replace() with a RegExp: total.replace(/\.?0+$/, ''):
const $pCell = $(".p-cell");
const $sCell = $(".s-cell");
const $wCell = $(".w-cell");
$(document).on('input', '.p-cel, .s-cell', () => {
const val1 = $pCell.val() || 0;
const val2 = $sCell.val() || 0;
const total = (val1 / 100 * val2).toFixed(2);
$wCell.val(total.replace(/\.?0+$/, ''));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="p-cell" type="text" value="0" />
<input class="s-cell" type="text" value="0" />
<input class="w-cell" type="text" value="0" readonly />
You can rounding without trailing zero with Math.round. Here I give you a trick of it.
$(document).on("change", ".p-cell, .s-cell", function () {
var val1 = $(".p-cell").val();
var val2 = $(".s-cell").val();
var total = Math.round((val1/100 * val2)*100)/100;
$(".w-cell").val(total).trigger("input");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="p-cell" type="text" value="0" />
<input class="s-cell" type="text" value="0" />
<input class="w-cell" type="text" value="0" />
There are several common ways to round to a fixed number of decimal places in JavaScript. Each one has certain problems.
Number.protototype.toFixed method
Number(x).toFixed(digits)
This method produces a string with the requested number of digits. However it rounds numbers that end in 5 incorrectly about 9% of the time.
Multiply-then-divide method
Math.round( x * (10 ** digits) ) / (10 ** digits);
This produces a number rounded to digits, but it rounds incorrectly about 0.7% of the time.
exponent add-and-subtract method
Math.round( x + 'e' + digits ) + 'e-' + digits;
This produces a number rounded to digits, and rounds correctly. But it has a fatal flaw—for input values smaller than 1e-6, it returns NaN.
I've written a function that uses the exponent add-and-subtract method, but it avoids the fatal error for small input values. Available on github.
/**
* round number `x` to `digits` number of digits after decimal point
*/
function roundToFixed (val, digits = 0) {
if (typeof val === 'number' && typeof digits === 'number'
&& Number.isInteger(digits) &&
(digits === 0 || Math.sign(digits) === 1)) {
const valF = numToFloat(val);
const valFNew = numToFloat(
Math.round(+(valF.mant + 'e' + (valF.exp + digits)))
);
return +(valFNew.mant + 'e' + (valFNew.exp - digits));
}
return NaN;
}
/**
* convert number to Float object
*/
function numToFloat (val) {
const [mant, exp] = Number(val)
.toExponential()
.split('e')
.map(str => +str);
return {
mant,
exp
};
}
I have a form including number inputs which are supposed to represent percentages, which are set up approximately like below:
<input type="number" min="0" max="1" step="0.01" />
Currently, the values show up as decimals, for example, 0.25. I think it'd be a lot more user-friendly if the number displayed in the text field showed up as a percentage instead. I've already disabled keyboard input on the field using the below jQuery code, so I'm not worried about users inputting rogue values:
$('input[type="number"]').keypress(function (field) {
field.preventDefault();
});
Is there an easy way to change the number fields to display a percentage?
Thank you!
There are two ways which I hope will work.
If you want percentages in input and need to convert it to decimals in js then:
<input type="number" min="1" max="100" id="myPercent"/>
in js:
document.getElementById('myForm').onsubmit = function() {
var valInDecimals = document.getElementById('myPercent').value / 100;
}
If scenario is reverse then:
<input type="number" min="0" max="1" step="0.01" id="myPercent"/>
in js:
document.getElementById('myForm').onsubmit = function() {
var valInDecimals = document.getElementById('myPercent').value * 100;
}
While not a HTML5 input type='number', the solution bellow uses input type='text' to the same effect. The rational of not using type='number' being humans require a nicely formatted string like "23.75%" while robots prefer to read integers and floating points should be avoided. The snippet bellow does just that to 2 decimal places.
I haven't tested it on a mobile, but I think the number pad should appear as with input type='number'.
Codepen.io: Commented code can be found here
document.querySelector('.percent').addEventListener('input', function(e) {
let int = e.target.value.slice(0, e.target.value.length - 1);
if (int.includes('%')) {
e.target.value = '%';
} else if (int.length >= 3 && int.length <= 4 && !int.includes('.')) {
e.target.value = int.slice(0, 2) + '.' + int.slice(2, 3) + '%';
e.target.setSelectionRange(4, 4);
} else if (int.length >= 5 & int.length <= 6) {
let whole = int.slice(0, 2);
let fraction = int.slice(3, 5);
e.target.value = whole + '.' + fraction + '%';
} else {
e.target.value = int + '%';
e.target.setSelectionRange(e.target.value.length - 1, e.target.value.length - 1);
}
console.log('For robots: ' + getInt(e.target.value));
});
function getInt(val) {
let v = parseFloat(val);
if (v % 1 === 0) {
return v;
} else {
let n = v.toString().split('.').join('');
return parseInt(n);
}
}
<input class="percent" type="text" value="23.75%" maxlength="6">
Maybe add a function, the outputted number (for example 0.25) * 100 + "%", on this way you always have it in percents.
function topercentage() {
var outputnumber = outputnumber * 100 + "%";
}
In this example outputnumber is the number for example 0.25. I hope this works.
I made a button that when you click it, adds +1 to a textbox value, and when you click another button, it should see if the first text box, the clicks box, is under or over 50. If the textbox value is over 50, it will take 50 clicks away, and add +5 gold to the second text box. And if the value is under 50, it will do nothing to the values and just say "Insufficient amount of clicks, sorry!"
Now the problem is, if the click value is specifically 7, it will take 50 clicks and add 5 gold, and leave you with -43 clicks. The point of the if statement in javascript, is that it shouldn't let any values go below 0. Now if the click value gets passed 200, it says "Insufficient amount of clicks, sorry!" I just want to know whats wrong with my code, so I'm going to paste my javascript and my buttons here, thanks for the help!
<script>
function clk1(){
document.f1.t1.value += '+1';
document.f1.t1.value = eval(f1.t1.value);
}
function prz1(){
var x=document.f1.t1.value;
if (x >= "50"){
document.f1.t1.value += '-50';
document.f1.t1.value = eval(f1.t1.value);
document.f1.g1.value += '+5';
document.f1.g1.value = eval(f1.g1.value);
}
else if (x <= "50"){
alert("Insufficient amount of clicks, sorry!");
}
}
function prz2(){
}
</script>
Clicks: <input type="text" value="0" name="t1" id="a1" disabled><br>
<input type="button" value="Click me!" id="a1" onClick="clk1()"><br>
Gold: <input type="text" value="0" name="g1" id="a1" disabled><br>
Cost: 50 Clicks <input type="button" value="5 gold" id="a1" onClick="prz1()"><br>
Cost: 100 Clicks <input type="button" value="10 gold" id="a1" onClick="prz2()"><br>
You are comparing strings, not numbers. Strings are compared in alphanumeric order. So:
"200" > "50"
is false. Because 2 comes before 5.
And:
"7" > "50"
Is true because 7 comes after 5.
You need to convert all your strings to numbers if you want to compare them numerically.
For example:
var x = parseInt(document.f1.t1.value, 10);
if (x >= 50){
//....
}
parseInt will convert your string into a number in the base specified (10 in this case).
Also you can get rid of all those eval statements once you are doing math with actual numbers. Here's a working fiddle:
http://jsfiddle.net/X7kCF/
function clk1() {
document.f1.t1.value = parseInt(document.f1.t1.value, 10) + 1;
}
function prz1() {
var x = parseInt(document.f1.t1.value, 10);
if (x >= 50) {
document.f1.t1.value = x - 50;
document.f1.g1.value = parseInt(document.f1.g1.value, 10) + 5;
} else {
alert("Insufficient amount of clicks, sorry!");
}
}
Try taking the quotes off where you are checking the value:
if (x >= 50)
You're comparing an integer to a string.
The solution to your problem is the following:
function increaseClickCount() {
var clickCountField = document.getElementById('clickAmount');
var currentClicks = parseFloat(clickCountField.value);
currentClicks = currentClicks + 1;
clickCountField.value = currentClicks;
}
function exchangeToGold() {
var clickCountField = document.getElementById('clickAmount');
var currentClicks = parseFloat(clickCountField.value);
if (currentClicks > 50) {
currentClicks = currentClicks - 50;
var goldCountField = document.getElementById('goldAmount');
var currentGold = parseFloat(goldCountField.value);
currentGold = currentGold + 1;
goldCountField.value = currentGold;
} else {
alert('Insufficient amount of clicks, sorry!');
}
}
HTML
Clicks: <input type="text" value="0" name="t1" id="clickAmount" disabled><br>
<input type="button" value="Click me!" id="a1" onClick="increaseClickCount()"><br>
Gold: <input type="text" value="0" name="g1" id="goldAmount" disabled><br>
Cost: 50 Clicks <input type="button" value="5 gold" id="a1" onClick="exchangeToGold()"><br>
What you were doing wrong, is comparing strings to integers. When working with numbers, I always prefer to parse the variable to an integer (or float) and then process it.