I've got this function to modify a string to a USD-like format
function formatAmount(el){
var val = el.value;
//Only Numbers
val = val.replace(/[^0-9]/gi, '');
// Pad with Zeros
val = val.padStart(3,0);
// Value with Period
val = val.slice(0, -2) + '.' + val.slice(-2);
// Append $
val = '$' + val;
console.log( val );
//el.value = val; // Breaks??
}
<input type="text" onkeyup="formatAmount(this);" />
When formatting the value, it works just fine: Typing 12345 into the input will log $123.45. As soon as I change the value with el.value = val;, the function seems to get a little weird, and I can't quite figure out why. 12345 now returns $0123.45 if you type fast or $00123.45 if you type slowly. Why is is appending the 0's to the string when changing the field value, but not when logging it without changing?
Edit:
Based on what #Dennis mentioned, wrapping it in a typing-timeout function seems to work, as long as the timeout is sufficiently high. 10ms doesn't work, but 100ms seems to? This doesn't seem very elegant, however:
var formatTimeout = null;
function formatAmount(el){
clearTimeout(formatTimeout);
formatTimeout = setTimeout(function(){
var val = el.value;
//Only Numbers
val = val.replace(/[^0-9]/gi, '');
// Pad with Zeros
val = val.padStart(3,0);
// Value with Period
val = val.slice(0, -2) + '.' + val.slice(-2);
// Append $
val = '$' + val;
//console.log( val );
el.value = val; // Breaks??
}, 100);
}
The function gets triggered at every key press.
If you type in 12345, it will get triggered 5 times.
Here's what your value will look like if typing sufficiently slowly:
1, the function will change it to $0.01
2, it gets added at the end of the existing string to make it $0.012, which gets formatted by the function as $00.12
3, the initial string will be $00.123, and it will get formatted as $001.23.
...
The final result will be $00123.45.
There are a few ways to deal with this problem. The simplest solution would be to trim the initial 0s to keep your number clean, right before padding with zeros.
This difference between results while console.log and actually assigning the value is because the input to the formatAmount function is different each time.
When you set the value of the input field, this is what happens;
-> User enter `1`
-> formatAmount takes the value, converts it to $0.01 and *sets the value* to the input box
-> user enter `2`
-> formatAmount takes the value ($0.012), converts it to $00.12 and *sets the value* to the input box
This continues until you finish 12345 and get $00123.45. This happens because the two 0s you added in the start never vanish after the first 1 is typed.
Also, console.log works fine because everytime, the value received is 1, 12,...12345. The logic works fine for these. Only fails when you set the value back
A keyup action in javascript seems to work fine. Tested with various speeds and works like a charm. Also, try pasting numbers and use regex to remove leading 0's like
var textInput = document.getElementById('hello');
textInput.onkeyup = function (e) {
formatAmount(textInput.value);
};
function formatAmount(el){
var val = el;
//Only Numbers
val = val.replace(/[^0-9]/gi, '');
// Pad with Zeros
val = val.padStart(3,0);
// replace leading 0's
val = val.replace(/^0+/, '');
// Value with Period
val = val.slice(0, -2) + '.' + val.slice(-2);
// Append $
val = '$' + val;
textInput.value = val;
}
<input type="text" id="hello" />
Just to show an alternative starting point using Intl.NumberFormat.prototype.format(). Feel free to adjust to your requirements.
function formatAmount(el){
el.value = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumIntegerDigits: 3 }).format(parseFloat(el.value.indexOf('$') === 0 ? el.value.substr(1) : el.value));
}
<input type="text" onblur="formatAmount(this);" />
My guess is that your function is being executed multiple times at the same time, the first execution is not even finished before the next one starts. You need to check if the function is already running.
Related
I've got some javascript to change the input value via plus/minus buttons.
I now need to save the value after the value has been decremented in a variable and output it as a number.
The javascript for the decrement looks something like this:
if (!isNaN(currentVal) && currentVal > 0) {
// Decrement one
$('input[id='+fieldName+']').val(currentVal - 1);
var test = parseInt($('input[id='+fieldName+']').val(currentVal - 1).val());
alert(test);
}
So as you can see I'm trying to get the updated value of the input in a variable called 'test', but all I'm getting is a NaN. Any ideas how to output the updated value of the input as a number within my test variable?
As #trincot said we cannot re-produce your situation. But the reason a NaN would be returned is because.
parseInt Returns an integer number parsed from the given string. If the first character cannot be converted to a number, NaN is returned.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
let a = '1'
let b = 'Two'
console.log(parseInt(a));
// 1
console.log(parseInt(b));
// NaN
console.log(parseInt(undefined))
// NaN
You can use double Tilda operator ~~ which behaves like Math.floor() except will return you 0 if the value is not a number.
I believe this is the solution you are looking for:
let inputField = document.querySelector('input[name="fieldName"]');
increment = () => {
let currentValue = ~~inputField.value;
alert(currentValue);
inputField.value = currentValue + 1;
};
decrement = () => {
let currentValue = ~~inputField.value;
alert(currentValue);
if (currentValue > 0) {
inputField.value = currentValue - 1;
}
};
<input type="number" name="fieldName" value="0" />
<button onclick="increment()">+</button>
<button onclick="decrement()">-</button>
Hope this helps,
Something showed up to me.
You are using jquery (I think it's right cause of the $ selector), and you are getting the ID with bracket notation.
Why not using something like
var selector = '#' + fieldName;
Then
$(selector)???
Another thing, usually when I'm trying something with javascript, I try it into the developer tool's console of my browser.
Doing it step by step avoid mistakes
Essentially what this function is supposed to do is take a list of words from input text and set it on a display at a client-chosen interval (WPM) from a drop-down menu.
If a word passed in the function contains a question mark, period, colon, semi-colon, exclamation point or comma, then it is removed, and the chosen interval is doubled. For example, if the delay between words was 117 ms, it would then be 234 ms.
I'm having the most trouble working out the part where you determine whether or not the passed word contains punctuation and removing it.
I'm getting an error:
Uncaught Type Error: Cannot read property 'indexOf' of undefined.
I'm not sure why this is happening since list[index++] is a String and indexOf is a method of Strings in Javascript and not a property.
I'm also not sure how I would implement the delay. Given that I've used setInterval() in this way (and I can only use setInterval for the purposes of this) I'm not sure how I would get it to set the String in the display twice while also including the delay.
function runDisplay(data, id) {
var reader = document.getElementById(id);
var index = 0;
if (timer) {
clearInterval(timer);
}
if (data.length) {
timer = setInterval(function() {
var punctuation = [".", ",", ":", ";", "!", "?"];
var textSpeed = 117; // default
for (var j = 0; j < punctuation.length; j++) {
// remove punctuation if found and double text delay
// if multiple found, remove only one
if (!(data[index++].indexOf(punctuation[j]) === -1)) {
data[index++] = string.replace(punctuation[j], '');
// set data[index++] to display twice to double delay?
}
}
reader.innerHTML = data[index++];
index = index % data.length;
}, textSpeed);
}
}
I'm getting an error: Uncaught Type Error: Cannot read property
'indexOf' of undefined.
I'm not sure why this is happening since list[index++] is a String and
indexOf is a method of Strings in Javascript and not a property.
First, methods are also properties of objects.
Second, the JS engine is telling you that you're calling indexOf on something undefined, so it's not a string. And data[index++] is undefined because index is probably not an index inside the range of the dataarray.
The main problem of the function is that if data is a word array, you don't iterate correctly on it. Here you're incrementing indexeach time you're reading the array, index should be incremented only once for each display.
I'm also not sure how I would implement the delay. Given that I've
used setInterval() in this way (and I can only use setInterval for the
purposes of this) I'm not sure how I would get it to set the String in
the display twice while also including the delay.
If the function has to display all the words in a infinite loop (that's the purpose of index = index % data.length, right ?), clearInterval and another setInterval could be called inside the anonymous function passed to the current setInterval, allowing to compute the textSpeed you want.
index++ will increase index variable every time it is called and you are calling it twice in your loop body.
In if (!(data[index++].indexOf(punctuation[j]) === -1)) {index is lets say i and in data[index++] = string.replace(punctuation[j], ''); it's i+1.
The code is messy but I hope that's what you wanted ...kind of:
var str = "some text with no punctuation. And some;: text. with, punctuation? symbols!!? to print"
var print = function(str) {
var re = /([^ .,:;!?]+)|([.,:;!?]+)/gi
var reSkip = /[.,:;!?]+/gi //remove + to add delay for each punctuation symbol instead of the group of symbols
var substrs = str.match(re)
var delay = 117
var timeToPrint = new Date().getTime() + delay
var i = 0
console.log(substrs.length)
var printWord = function() {
console.log(substrs[i])
if ( new Date().getTime() < timeToPrint ) {
console.log(new Date().getTime() +'<'+timeToPrint)
requestAnimationFrame(printWord)
return
}
if ( reSkip.test(substrs[i]) ) {
i++
timeToPrint += delay*5 //to make delay more obvious
console.log('skip punctuation')
requestAnimationFrame(printWord)
return
}
document.write(substrs[i++] + ' ') //replace this with your code to print where you want
timeToPrint += delay
console.log('written')
if (i < substrs.length)
requestAnimationFrame(printWord)
}
printWord()
}
print(str)
Just paste it to chrome console to test.
I have a string that contains a number, eg,
images/cerberus5
The desired result
images/cerberus4
How can I subtract 1 from the '5' in the first string to obtain the '4' in the second?
This is a raw example, but you could do something like this:
$old_var = 'images/cerberus4';
$matches = [];
$success = preg_match_all('/^([^\d]+)(\d+)$/', $old_var, $matches);
$new_val = '';
if (isset($matches[2]) && $success) {
$new_val = $matches[2][0].((int)$matches[2][0] + 1);
}
It's not meant to be the perfect solution, but just to give a direction of a possible option.
What the RegEx doesn't detect (because it's more strict) is that it won't work without a trailing number (like images/cerberus), but as it seems an 'expected' pattern I also wouldn't allow the RegEx to be more loose.
By putting this code into a function or class-method you could add a parameter to automatically be able to tell the code to add, subtract or do other modifications to the trailing number.
function addOne(string){
//- Get first digit and then store it as a variable
var num = string.match(/\d+/)[0];
//- Return the string after removing the digits and append the incremented ones on the end
return (string.replace(/\d+/g,'')) + (++num);
}
function subOne(string){
var num = string.match(/\d+/)[0];
//- Same here just decrementing it
return (string.replace(/\d+/g,'')) + (--num);
}
Don't know if this is good enough but this is just two functions that return the string. If this has to be done via JavaScript so doing:
var test = addOne("images/cerberus5");
Will return images/cerberus6
and
var test = subOne("images/cerberus5");
Will return images/cerberus4
Can't seem to get Not a Number NaN error to be replaced with a 0. Tried using rapply but not working for me.
window.onload = function () {
var first = document.getElementById('firstFieldId'),
second = document.getElementById('secondFieldId'),
third = document.getElementById('thirdFieldId'),
fourth = document.getElementById('fourthFieldId');
first.onkeyup = function () {
var value;
// Get the value and remove the commas
value = first.value.replace(/,/g, "");
// Make it a number
value = parseInt(value, 10);
// Add one to it
++value;
// Turn it back into a string
value = String(value);
// Put it in the other text box, formatted with commas
second.value = numberWithCommas(value);
};
third.onkeyup = function () {
var value;
// Get the value and remove the commas
value = third.value.replace(/,/g, "");
// Make it a number
value = parseInt(value, 10);
// Add one to it
++value;
// Turn it back into a string
value = String(value);
// Put it in the other text box, formatted with commas
fourth.value = numberWithCommas(value);
};
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
};
Made a JSFiddle http://jsfiddle.net/7r5SF/2/ - If you put a number in the first or third field, and then clear it, the second or fourth field will show up as NaN... It needs to say 0!
Any help would be great!
Replace
++value;
with
value = isNaN(value) ? 0 : value+1
JSFiddle
What I'm trying to achieve is a code checker. Only the first 4 numbers are important, the other numbers can be any number. The form will be used for users to put in productcodes.
The problem is that if the variable changes to say, 5 numbers the variable is false.
See below example:
http://jsfiddle.net/MZfxs/3/
If the user puts in the numbers 3541 the box changes color, but if the user put in the remaining numbers the value is set to false.
Additionally I'm trying to make the box only change color when 13 numbers are inserted AND the first 4 numbers are matching, in that order.
Solved!
Working Example:
http://jsfiddle.net/MZfxs/8/
If I understood correctly, you need a field value validation and the requirement is the value should start from 4 numbers like 7514 or 9268. Here you can use a regular expression to validate input value like:
// Will work for " 123433 " or "12345634 ", etc.
var value = $(this).val(),
re = /^\s*(\d{4})(\d+)\s*$/, // better to initialize only once somewhere in parent scope
matches = re.exec(value),
expectedCode = 3541,
expectedLength = 13;
if(!!matches) {
var code = matches[1]; // first group is exactly first 4 digits
// in matches[2] you'll find the rest numbers.
if(value.length == expectedLength && code == expectedCode) {
// Change the color...
}
}
Also if your requirement is strict to length of 13 than you can modify the regular epression to
var re = /^(\d{4})(\d{9})$/;
and retrieve first 4 numbers in first group and rest 9 in second group:
var matches = re.exec(value);
if(!!matches) {
var first4Digits = matches[1],
rest9Digits = matches[2];
// ...
// Also in this way you'll not need to check value.length to be 13.
}
You can break the string each time on key event fires. You can do this by calling js substring() method and take the first four characters and check it.
Try to use this:
<script>
$("input").keyup(function () {
var value = $(this).val();
$("p").text(value);
var value2 = $(this).val().substr(0,4);
if(value2 == 3541){
$(".square").css("background-color","#D6D6FF");
}else{
$(".square").css("background-color","yellow");
}
})
</script>