So I have this custom code I'm working on as a pet project, and I've been bug testing it and I thought I had finally gotten it to a point where I could clone it with other options, but apparently not? So when you give enough xp in current xp to roll over to level two, for example, level 1 requires 180 XP to roll over to level 2, and then it takes 360 for level 3, however... if I put in current existing xp is 180 and new xp gains as 0 it jumps up to level 11. I've included a picture for a visual of this error, it also does this for level 2 and I would assume all levels. Can anyone help me fix this weird error? This is the first time I've tried to code something in javascript before so I appreciate any assistance as a newbie to the language!
EDIT: As it turns out testing the code itself doesn't produce the right results either, I did fix the typo mentioned, and it still doesn't produce the right results in a normal scenario and I'm not sure why either.
Image example
https://i.imgur.com/gGNkPQY.png
The javascript itself
var xpToLevel = [180, 360, 540, 720, 900, 1080, 1260, 1440, 1620, 1800, 1980, 2160, 2340, 2520, 2700, 2880, 3060, 3240, 3420, 3600, 3780, 3960, 4140, 4320, 4500, 4680, 4860, 5040, 5220, 5400, 5580, 5760, 5940, 6120, 6300, 6480, 6660, 6840, 7020, 7200, 7380, 7560, 7740, 7920, 8100, 8280, 8460, 8640, 8820, 9000, 9180, 9360, 9540, 9720, 9900, 10080, 10260, 10440, 10620, 10800, 10980, 11160, 11340, 11520, 11700, 11880, 12060, 12240, 12420, 12600, 12780, 12960, 13140, 13320, 13500, 13680, 13860, 14040, 14220, 14400, 14580, 14760, 14940, 15120, 15300, 15480, 15660, 15840, 16020, 16200, 16380, 16560, 16740, 16920, 17100, 17280, 17460, 17640, 17820
],
xpToNext,
newXp,
currentLevel,
currentXp,
currentSpareXp,
goalLevel,
levelBaseXp,
nextLevelXp,
totalXp,
spareXp,
xpToGoal,
trainerBattle,
officialWin,
officialLoss,
wildPokemon = '<p>Enter your current level, Current XP, and new XP to add in. The new level and new remaining XP will be displayed.</p><p><b>Your Level:</b> <input class="forminput" type="number" min="1" max="100" onKeyUp="inputFullLevel(this, this.value)" id="currentLevel"><br> <b>Current XP:</b> <input class="forminput" type="number" min="0" max="17820" onKeyUp="inputSpareXp(this, this.value)" id="currentXp"><br><b>New XP:</b> <input class="forminput" type="number" min="1" max="17820" onKeyUp="inputXp(this, this.value)" id="newXp"></p><button class="forminput" type="button" onclick="runWildPokemon()">Calculate</button>';
function switchCalc() {
var c = document.getElementById("calc_select"),
calcActive = c.options[c.selectedIndex].value;
document.getElementById("calc-desc").innerHTML = eval(calcActive);
document.getElementById("calc-results").innerHTML = '';
}
function runWildPokemon(){
currentLevel = document.getElementById("currentLevel").value;
currentXp = document.getElementById("currentXp").value;
newXp = document.getElementById("newXp").value;
const cb = document.getElementById('xpShare');
const cb2 = document.getElementById('luckyEgg');
console.log(cb.checked);
xpToNext = xpToLevel[currentLevel - 1];
newTotalXp = parseInt(newXp) + parseInt(currentXp);
newTotalXp *= 0.5;
if (document.getElementById("xpShare").checked == true) {
newTotalXp *= 0.5;
}
if (document.getElementById("luckyEgg").checked == true) {
newTotalXp *= 1.5;
}
newTotalXp = Math.trunc(newTotalXp);
while(currentXp >= xpToNext) {
currentXp = currentXp - xpToNext;
currentLevel = currentLevel + 1;
xpToNext = xpToLevel[currentLevel - 1];
}
document.getElementById("calc-results").innerHTML = '<b>Level:</b> ' + currentLevel +' <b>XP:</b> ' + '[' + newTotalXp + '/' + xpToNext + ']';
}
function inputXp(field, input) {
if (input > 17820) {
field.value = 17820;
}
if (input < 0) {
field.value = 0;
}
}
function inputSpareXp(field, input) {
if (input > 17819) {
field.value = 17819;
}
if (input < 0) {
field.value = 0;
}
}
function inputFullLevel(field, input) {
if (input > 100) {
field.value = 100;
}
if (input <= 0) {
field.value = 1;
}
}
function inputLevel(field, input) {
if (input > 99) {
field.value = 99;
}
if (input <= 0) {
field.value = 1;
}
}
The HTML
<div id="calculator">
<span id="calcActive" class="wildPokemon"> <b>Select Encounter Type:</b><br> <select class="forminput" id="calc_select" onChange="switchCalc()" style="margin-bottom: 10px;text-align:center;">
<option selected="selected" value="wildPokemon">Wild Pokemon</option>
<option value="trainerBattle">Trainer/Social</option>
<option value="officialWin">Official Battle Win</option>
<option value="officialLoss">Official Battle Loss</option>
</select>
<input type="checkbox" id="xpShare" name="xpShare" value="xpShare">
<label for="xpShare"><b>XP Share</b></label>
<input type="checkbox" id="luckyEgg" name="luckyEgg" value="luckyEgg">
<label for="luckyEgg"><b>Lucky Egg</b></label><br>
</span><br>
<div id="calc-desc">
<p>Enter your current level, Current XP, and new XP to add in. The new level and new remaining XP will be displayed.</p><p><b>Your Level:</b> <input class="forminput" type="number" min="1" max="100" onKeyUp="inputFullLevel(this, this.value)" id="currentLevel"><br> <b>Current XP:</b> <input class="forminput" type="number" min="0" max="17820" onKeyUp="inputSpareXp(this, this.value)" id="currentXp"><br><b>New XP:</b> <input class="forminput" type="number" min="1" max="17820" onKeyUp="inputXp(this, this.value)" id="newXp"></p><button class="forminput" type="button" onclick="runWildPokemon()">Calculate</button>
</div><p>
</p>
<div id="calc-results">
</div>
</div>
The CSS
#calculator{
width: 300px;
background: var(--back1);
margin: auto;
padding: 10px;
border: 10px solid var(--outline);
}
#calc-desc {font-family: 'Dosis', sans-serif;}
#calc-results b{
font-family: 'Dosis', sans-serif;
font-size: 25px;
}
#calc-results {
display:flex;
justify-content: space-evenly;
font-size: 25px;}
It is simply a typo!
You search for the element with id currentLevel
currentLevel = document.getElementById("currentLevel").value;
But in your HTML it's named currentlevel
<input class="forminput" type="number" min="1" max="100" onKeyUp="inputFullLevel(this, this.value)" id="currentlevel">
JavaScript is case sensitive! Thus, you never get the current level's value for your computation.
I would suggest using a function to calculate the XP to upgrade instead of a huge array and your current incrementation method. The XP to reach level up is just 180 * current level. Therefore, calculate the XP it takes to get to a level as 90*(n^2+n).
Then just add together the XP to get to the current level, and the new XP (after the luckyEgg and xpShare stuff), and then calculate the level that the new XP corresponds to.
Something like:
currentLevel = document.getElementById("currentLevel").value;
currentLevel = parseInt(currentLevel);
currentXp = document.getElementById("currentXp").value;
newXp = document.getElementById("newXp").value;
const cb = document.getElementById('xpShare');
const cb2 = document.getElementById('luckyEgg');
const curXp = 90*((currentLevel*currentLevel)+currentLevel);
newTotalXp = parseInt(newXp) + parseInt(currentXp);
newTotalXp *= 0.5;
if (document.getElementById("xpShare").checked == true) {
newTotalXp *= 0.5;
}
if (document.getElementById("luckyEgg").checked == true) {
newTotalXp *= 1.5;
}
newTotalXp = Math.trunc(newTotalXp);
const newLevelXp = newTotalXp + curXp;
return Math.floor((((newLevelXp/90)+2) ** 0.5) - 1);
I have input like this
<input max="100" min="0" type="number">
But in this input users can put numbers like 01 02 03 004 itp...
And my question is how to prevent this? To only numbers from 0 to 100
0, 1, 2, 3 ... 100
In most cases JavaScript is the answer:
<input type="text" id="taskinput">
<script>
const input = document.getElementById('taskinput');
let lastValue = '';
input.oninput = () => {
if (!input.value) {
lastValue = '';
return;
}
const val = parseInt(input.value);
if (val > 100 || isNaN(val)) {
input.value = lastValue;
return;
}
lastValue = val;
input.value = lastValue;
}
</script>
You could archive this by adding a onchange eventlistener on the input.
The regex will remove the leading zero.
document.getElementById('number').onchange = function(){
this.value = this.value.replace(/\b0+[0-9]/g, '');
};
<input id="number" min="0" max="100" step="1" type="number" >
I should work with two input values that store only Integers when I increase the value of one, the other should decrease. This must stop if the second value hit 0.
The field that contains the value to be decreased is named with ID form_val62_1, and field that can be increased by the user input is called form_val63_1. I'm calling this function onChange() cause I need to pass the ID of the form (that's cause form fields are dynamically generated depending on a PHP array length).
function check(i) {
$("#form_val63_" + i ).change(function () {
var direction = this.defaultValue < this.value;
this.defaultValue = this.value;
var val;
val = parseInt($("#form_val62_" + i).val());
if (direction) {
if (val > 0) {
$('#form_val62_' + i).val(parseInt($(this).val()) - 1);
} else {
var thvar = $(this).val();
$(this).val(thvar - 1);
}
console.log("increase 503");
console.log(val);
} else {
$('#form_val62_' + i).val(parseInt($(this).val()) + 1);
console.log("decrease 503");
console.log(val);
}
});
}
Fiddle
I got many problems here, the first decrease one time, that increase with no reason (I know there is but can't see why).
Using the solution provided by #Ph0b0x i've updated my code as
var v = $("#form_val62_" + i).val(); //Let's say this is the value from PHP....
var preVal = 0;
$("#form_val62_" + i).val(v);
$("#form_val63_" + i).on("change keyup keydown", function(event) {
let currVal = parseInt($("#form_val63_" + i).val());
console.log(preVal);
console.log(currVal);
if (currVal == 0) {
preVal = 0;
$("#form_val62_" + i).val(v);
} else if (currVal <= v) {
$("#form_val62_" + i).val((v - currVal) == 0 ? 0 : (v - currVal));
preVal = currVal;
} else {
$("#form_val63_" + i).val(v);
}
});
Now I can increase the result but when i try decrease the each value remain 0.
I guess, if i understood correctly, i will keep track of the previous value on the second input then i will start decreasing the first one until it reaches 0 and increase it until it reaches 10? Fiddle
HTML
<form>
<input id="form_val62_1" type="number" min="0" value="10" />
<input id="form_val63_1" type="number" min="0" value="0" />
</form>
JS
var v = 13; //Let's say this is the value from PHP....
var preVal = 0;
$("#form_val62_1").val(v);
$("#form_val63_1").on("change keyup keydown", function(event) {
let currVal = parseInt($("#form_val63_1").val());
console.log(preVal);
console.log(currVal);
if (currVal == 0) {
preVal = 0;
$("#form_val62_1").val(v);
} else if (currVal <= v) {
$("#form_val62_1").val((v - currVal) == 0 ? 0 : (v - currVal));
preVal = currVal;
} else {
$("#form_val63_1").val(v);
}
});
Edit: I have updated my code based on your comment. Please see this Fiddle
So bind change event handlers on both elements. I would just use data attributes so you do not have to worry about selecting by ids to bind between both.
$('[data-num-grp]').on('input', function () {
// input that was interacted with
const inp1 = $(this);
// get the group number
const grp = inp1.data('num-grp')
// select the other element with the grp
const inp2 = $('[data-num-grp="' + grp + '"]').not(inp1);
// alter the other element so it's value changes
inp2.val(this.max - this.value)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" data-num-grp="1" min="0" max="10" value="10"/>
<input type="number" data-num-grp="1" min="0" max="10" value="0"/>
<br/>
<input type="number" data-num-grp="2" min="0" max="10" value="10"/>
<input type="number" data-num-grp="2" min="0" max="10" value="0"/>
I have a field that will round up to the nearest .25. This is working fine in Chrome but for some reason it will not allow me to type say 2.25 in IE or Firefox. It ignores that I am typing a dot. Is there something obvious I'm missing here?
Edit One thing I have noticed is that if I change keyup to blur it will work fine. I need this to run on keyup though. It will also accept .25 by itself but not a number then decimal. For example 2.25.
$(document).on('keyup', '.Monday', findTotalMon);
function findTotalMon() {
var arr = document.getElementsByClassName('Monday');
var tot = 0;
for (var i = 0; i < arr.length; i++) {
if (parseFloat(arr[i].value)) {
var newValue;
newValue = (.25 * Math.round(4 * arr[i].value));
arr[i].value = newValue;
tot += parseFloat(newValue);
}
}
document.getElementById('totalHoursMon').value = tot;
if (tot === 0) {
document.getElementById('totalHoursMon').value = '';
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input class="form-control full-width Monday" name="monday" id="monday" type="number" step="any" /><br><br>
<input class="form-control full-width totalBox" name="total" id="totalHoursMon" type="text" readonly="readonly"/>
The issue lies in the use of keyup and the overwriting of your fields value with the newly parsed / rounded float.
After typing your decimal separator, the input is parsed and rounded and the separator disappears, because "1." or "1," is parsed to 1.
One way to solve this is to only overwrite your field when the rounded input is different than the original input.
$(document).on('keyup', '.Monday', findTotalMon);
function findTotalMon() {
var arr = document.getElementsByClassName('Monday');
var originalValue, newValue, tot = 0;
for (var i = 0; i < arr.length; i++) {
originalValue = arr[i].value;
if (parseFloat(originalValue)) {
newValue = (.25 * Math.round(4 * arr[i].value));
tot += parseFloat(newValue);
if (newValue != originalValue) {
// we're only overwriting input when the rounded value is different than the original
arr[i].value = newValue;
}
}
}
document.getElementById('totalHoursMon').value = tot;
if (tot === 0) {
document.getElementById('totalHoursMon').value = '';
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input class="form-control full-width Monday" name="monday" id="monday" type="number" step="any" /><br><br>
<input class="form-control full-width totalBox" name="total" id="totalHoursMon" type="text" readonly="readonly"/>
On a side note :
Using keyup and overwriting your user's input is really annoying. For instance, while testing, I realized you can't use backspace to correct your input. I know you said you had to use keyup, but I strongly advise you to use blur or keypress. For your user's sake :)
I have a input type="range"in jquery mobile code. Based on some condition, I want to restrict the slider handle to go further after a certain limit ( but it can go backward )
For example, this is what I want to achieve in jQuery Mobile - http://jsfiddle.net/EL4tf/ ( Total is not exceeding 150 for all the three sliders )
The problem I am facing is that jQuery Mobile converts input type="range" into input type="number" therefore I am not able to put the condition event.preventDefault(); return false on $('.mySlider').bind('change') like they have put in the above fiddle example.
Any help will be appreciated!
From my comment, i prepared a simple solution which calculates the sliders total value and stops them increasing if greater than the total 150.
** Update from #ezanker. using the same process on change event. stops the slider in its tracks
Demo
http://jsfiddle.net/8jddyftc/
Jquery
var tota, totb, totc, alltot, altval, getslider;
var chktot = 150;
var scrore = 151;
//On Change event
$(document).on("change", "#range1, #range2, #range3", function (e) {
// Get the sliders Id
getslider = $(this).attr("id");
//Gather all slider values
tota = parseInt($("input#range1").val());
totb = parseInt($("input#range2").val());
totc = parseInt($("input#range3").val());
alltot = tota + totb + totc;
//check sliders total if greater than 150 and re-update slider
if (alltot > chktot) {
if (getslider == "range1") {
altval = chktot - totb - totc;
$("input#range1").val(altval).slider("refresh");;
}
if (getslider == "range2") {
altval = chktot - tota - totc;
$("input#range2").val(altval).slider("refresh");;
}
if (getslider == "range3") {
altval = chktot - tota - totb;
$("input#range3").val(altval).slider("refresh");;
}
}
//Update Total
if (alltot < scrore) {
$("#total").text(alltot);
}
})
If you want to limit the slider already during dragging, you can modify the CSS of the <a> component that is used to render the slider.
Demo: http://jsfiddle.net/ukaxkej0/2/
Try yourself: the slider will not move further if the sum is already at its limit.
To change the CSS:
var MAX = 150; // maximum allowed sum
var DEFAULT = 50; // slider default
var SMAX = 100; // slider max
var old1=DEFAULT, old2=DEFAULT, old1=DEFAULT;
// sliders trigger number changes; prevent them if sum exceeds maximum
$("input[type='number']").change(function(e){
var val1 = $("#range1").val();
var val2 = $("#range2").val();
var val3 = $("#range3").val();
var sum = parseInt(val1) + parseInt(val2) + parseInt(val3);
if (sum <= MAX) {
$("#total").text(sum);
old1=val1;
old2=val2;
old3=val3;
}
else {
if (val1 != old1) {
$("#range1").val(old1);
$("a[aria-labelledby='range1-label']").css('left', (100*old1/SMAX)+'%');
}
if (val2 != old2) {
$("#range2").val(old2);
$("a[aria-labelledby='range2-label']").css('left', (100*old2/SMAX)+'%');
}
if (val3 != old3) {
$("#range3").val(old3);
$("a[aria-labelledby='range3-label']").css('left', (100*old3/SMAX)+'%');
}
}
});
In addition, you have to prevent slider interaction if the sum exceeds the maximum.
$('.ui-slider-handle').mousemove(function(e){
var val1 = $("#range1").val();
var val2 = $("#range2").val();
var val3 = $("#range3").val();
var sum = parseInt(val1) + parseInt(val2) + parseInt(val3);
if (sum > MAX) {
e.preventDefault();
return false;
}
return true;
});
HTML (as suggested by Tasos):
<div data-role="page">
<input id="range1" type="range" min="0" max="100" value="50" />
<input id="range2" type="range" min="0" max="100" value="50" />
<input id="range3" type="range" min="0" max="100" value="50" />
<div>total: <strong id="total">0</strong>/150</div>
</div>