I'm working on a calculator with vanilla JavaScript. I'm trying to make an if statement to find out whether the current result displayed has only one number left in the string. If this is true I want to make sure when the user clicks the delete button the current display returns to the default display instead of having no numbers in the string. I hope I explained this properly. How would I go about making this check.
const deleteNumber = () => {
let newDisplayedResult = currentResult[0].innerHTML.slice(0, -1);
if (firstNumber !== "" && currentOperator !== "") {
secondNumber = newDisplayedResult;
currentResult[0].innerHTML = newDisplayedResult;
} else {
firstNumber = newDisplayedResult;
currentResult[0].innerHTML = newDisplayedResult;
}
};
let re = new RegExp('^[0-9]$');
re.test(str)
or:
str.length === 1 && "0123456789".split("").includes(str)
Related
I have a code where the user enters multiple strings and I store them in an array, then I want to check if all the inputs are valid.
An input valid is a number with the same character repeated 3 times.
For example : '333', '999', '222', ...
What I have tried :
let valid = true;
inputs.forEach((input) => {
if (input.length !== 3 || isNaN(input)) {
valid = false;
} else {
const first = input[0];
for (let i = 1; i < 3; i++) {
console.log(first,input[i])
if (input[i] !== first) {
valid = false;
}
}
}
});
console.log(valid);
this code is working and I want to know if can I do better it seems like I used too much code for this simple task and I want to know if there is a simpler code when I searched in the interned they suggest rejex but this is so complicated for me thank you for helping me
First of all for a beginner your solution is good and correct congrats however you can optimize it and make it simpler
you can use every instead of forEach there is no need to check all the inputs once you find an invalid one
instead of loop through the input you can check if it is not divisible by 111 ;)
if(parseInt(input) % 111 !== 0) valid = false;
You could use Array#every.
let valid = inputs.every(s => s.length === 3 && !isNaN(s)
&& [...s].every(c => c === s[0]));
This could be shortened with a regular expression:
let valid = inputs.every(s => /^(\d)\1{2}$/.test(s));
First things first here is the code pen of the project;
https://codepen.io/furkancodes-the-typescripter/pen/jOyGJvx
I have tried searching for "." through contains() also with a condition to make it disabled but it does not work as I want it to.
decimal.addEventListener('click', (e) => {
decimal = e.target.value;
if (display.innerHTML === '') {
result = display.innerHTML = display.innerHTML.concat('0.');
} else if (display.innerHTML === output && display.innerHTML.indexOf(".") < 0) {
display.innerHTML = display.innerHTML.concat('.');
}
});
Also tried to come up with a solution like above but I am sure I am failing to grasp something here. Can anyone let me know what is wrong and lead me to the correct path to "prevent my calculator allowing more than one decimal" and any other improvements I can make.
Sample input:
4...4
Expected output:
4.4 ( not more than one decimal into the calculator display)
In order to stop the user from entering more than one decimal point for a single input, you can implement a counter.
let decimalCount = 0;
For the click handler for .number buttons add the following check.
// For the decimal increment decimal counter
if (number.id === ".") {
decimalCount++;
}
// For more than one decimal don't do anything. Return
if (number.id === "." && decimalCount > 1) {
return;
}
When the user enters another input (.operator click handler) reset the decimal counter to decimalCount = 0;.
Link: https://codesandbox.io/s/calculator-no-multiple-decimals-2fjnm
The write method to use for string is includes.
Using it solves the problem
decimal.addEventListener('click', function(){
if(display.innerHTML.includes('.') || firstNumber.innerHTML.includes('.')){
decimal.disabled = true;
} else {
decimal.disabled = false;
}
})
My code is supposed to detect currency symbols, and execute code based on the result, but the code will not detect the '£' under any circumstances. Here is the relevant code:
let requirements = [ "£", "$" ];
let mcontent = "$£50";
let y = 0;
for (let p = 0; p < requirements.length; ++p) {
if (mcontent.includes(requirements[p])) {
++y;
}
}
if (y == 1) {
//this is considered success, only ONE currency symbol was detected. If mcontent = '$50' or '£50', we should be here.
} else {
//this is considered failure, TWO or ZERO currency symbols were detected. In this scenario, I want the code to fail.
}
I'm aware this may not be the best way to code a function to accomplish what I'm trying to accomplish, so I'm open for better ideas/fixes for what I already have.
The most concise way to do this is to check with RegExp like this:
if (mcontent.match(/£|\$/g)?.length == 1) { // the question mark is so we don't encounter an error if no matches were found
// success
} else {
// failure
}
Here's a live example:
const mcontent1 = '$£50';
const mcontent2 = '£50';
const mcontent3 = '$50';
const regex = /£|\$/g; // slash to escape $ because it has special meaning in regex
console.log(mcontent1.match(regex).length == 1); // false
console.log(mcontent2.match(regex).length == 1); // true
console.log(mcontent3.match(regex).length == 1); // true
If you don't want to use regex, just check if the string includes a symbol, increment a counter, and return whether or not there was exactly 1 match:
let testA = "$£50",
testB = "£50",
testC = "$50";
function checkString(str) {
const symbols = ["£", "$"];
let matches = 0;
for (const symbol of symbols)
if (str.includes(symbol)) matches++;
return matches == 1;
}
console.log(
checkString(testA),
checkString(testB),
checkString(testC)
);
Use RegExp it will return true or flase based on value entred
this example will give you an idea of how to use it
const elementTwo = document.getElementById('elementTwo');
elementTwo.addEventListener("input", function(event) {
pattern = /^[£|$]{1}(\d+)/
if (pattern.test(this.value)) {
console.log("found")
} else console.log("not found")
});
<p>Enter value</p>
<input id="elementTwo" type="text" />
I'm using the typeof command to make sure that only 1 of the 2 input fields of this temperature (Celsius to/from Fahrenheit) calculator is populated with data and it has to be a number. If the input is not a valid number or both fields are populated, the app will throw an error message.
The problem: nothing satisfies this condition - the errorMessage is always shown, even if I type in a valid number.
Is typeof the right solution to this problem? If it is, why is this code not working?
document.getElementById('temperature-form').addEventListener('submit', calculateResult);
function calculateResult(e) {
e.preventDefault();
const celsiusInput = document.getElementById('celsius');
const fahrenheitInput = document.getElementById('fahrenheit');
let resultOutput = document.getElementById('result');
// validate input data type and calculate result
if ((typeof celsiusInput === 'number') && (fahrenheitInput === null)) {
resultOutput.value = (celsiusInput.value * 1.8 + 32) + ' Fahrenheit';
} else if ((celsiusInput === null) && (typeof fahrenheitInput === 'number')) {
resultOutput.value = ((fahrenheitInput.value - 32)/1.8) + ' Celsius';
} else {
errorMessage('Please add a number in one of these fields');
}
}
Many thanks!
You could check the value properties of each input to see if they are numbers using the isNaN() function like so:
function calculateResult(e) {
e.preventDefault();
//Get the value of each input box
const celsiusValue = document.getElementById('celsius').value;
const fahrenheitValue = document.getElementById('fahrenheit').value;
//Get the result element
let resultOutput = document.getElementById('result');
// validate input data type and calculate result
if(!isNaN(celsiusValue) && (fahrenheitValue === null || fahrenheitValue === "")){
//Only celsiusValue has a valid number
resultOutput.value = (celsiusValue * 1.8 + 32) + ' Fahrenheit';
}else if(!isNaN(fahrenheitValue ) && (celsiusValue === null || celsiusValue === "")){
//Only fahrenheitValue has a valid number
resultOutput.value = ((fahrenheitValue - 32)/1.8) + ' Celsius';
}else if(!isNan(celsiusValue) && !isNan(fahrenheitValue )){
//Both contain a valid number
//Figure this one out as you didn't account for it
}else{
//Neither is a valid number
errorMessage('Please add a number in one of these fields');
}
}
Documentation of isNaN():
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN
When doing const celsiusInput = document.getElementById('celsius') you're getting the DOM Element, not the value.
In order to obtain de value you'd have to check for the property value.
So you'd end up with something like this:
const celsiusInput = document.getElementById("celsius")
const celsiusValue = celsiusInput.value
Now if we do typeof celsiusValue we'll always get string, because text/number inputs always accept text (check input's type property for more info).
The proper way to check if there are numbers or letters is using Regular Expressions.
I'll leave a simple example to act as a starting point for you:
const celsiusInput = document.getElementById("celsius")
const celsiusValue = celsiusInput.value
if(/\D/.test(celsiusValue)) {
alert("There is something that's not a number in the Celsius input!")
}
First of by doing a comparison like this fahrenheitInput === null you're comparing a DOM element against the value null.
That will only evaluate to true if the DOM Element never existed.
Secondly the typeof method will always evaluate to a String on DOM element types, so again this will always be false.
To really get what you want you have to do a proper check
To check if both input fields are supplied, simply checking the length of the values will surface:
if(fahrenheitInput.length > 0 && celsiusInput.length > 0) //fail
If fahrenheitInput only is given:
if(!isNaN(Number(fahrenheitInput)) //convert
if celsiusInput only is given:
if(!isNaN(Number(celsiusInput)) //convert
Finally if all checks above don't check our, fail
In this jsfiddle example, I have created a text-entry field that responds to the characters entered and appends a class to the parent <div> element for visual feedback based on whether the entry is expected, partial, or has an error.
In this case, the text field is for serial number entry; the field contents will eventually be sent to a dynamic table for building out an order. Because of this, the serial number must have an absolute value in the prefix (i.e: ABCDE in the example) and contain exactly 14 characters... I'm having difficulty coming up with a working code that will turn the text box green if the prefix is correct and remain green regardless of the remaining 9 characters (although they do need to be strictly numeric and end in a letter).
Additionally, I have a feeling there is a shorter and more elegant way to implement the script for the prefix check. Currently, I'm using:
if (el.value == "abcde" || el.value == "ABCDE") {
document.getElementById('serial').className = 'serial-entry success';
} else if (el.value == "a" || el.value == "ab" || el.value == "abc" || el.value == "abcd" || el.value == "A" || el.value == "AB" || el.value == "ABC" || el.value == "ABCD") {
document.getElementById('serial').className = 'serial-entry warning';
... where I know there's got to be a better way to write the expected ascending prefix values other than (el.value == "a" || el.value == "ab" ||... and so on. Using my current method, I would need to write half-a-billion variants of the el.value in order to satisfy all combinations.
Please be aware that I am not versed in JS; everything I know I've picked up from this site. It's the equivalent of moving to a foreign country and learning the language solely by eavesdropping on conversation - my grammar, syntax, and vocabulary are sparse, at best. In other words: feel free to humiliate me with sage-like wisdom.
--- EDIT: Answered! ---
Thanks to Felix Kling for the solution. I should have been more clear on where the state changes would occur, so I'll do so now and then include the code.
Rules:
1.) As the user enters the first letters of the prefix in correct order ("abcde"), the class of the text box should change to let the user know that they're on the right track, but not quite finished (partial).
2.) If the prefix is entered exact and we're agnostic of the following numbers ("123456789"), but they eventually do enter the correct prefix and a total of 14 characters, then the state (class) of the text box should toggle showing a success indicator.
3.) All other entries into the text box should be considered as erroneous, and an error class should be appended respectively.
4.) Lastly, if the user clears the text box of any string they entered, then the box should revert its class to the original state and not persist with any of the above classes.
Here is Felix's revised jfiddle.
And purely the JS:
function checkSerial(el) {
var value = el.value.toLowerCase();
var prefix = 'abcde';
var className = 'error'; // assume no match
if (!value) {
className = '';
}
else if (value.length === 14 &&
value.indexOf(prefix) === 0) { // match
className = 'success';
}
else if ((value.length >= prefix.length &&
value.indexOf(prefix) === 0) || // match
prefix.indexOf(value) === 0) { // partial match
className = 'warning';
}
document.getElementById('serial').className = 'serial-entry ' + className;
}
You could just use .indexOf and test that the string starts with the prefix:
document.getElementById('serial').className =
el.value.toLowerCase().indexOf('abcde') === 0 ?
'serial-entry success' :
'serial-entry warning';
For the three case, match, partial match, no match, you can check whether the input string is shorter than the prefix and apply the same logic, but vice versa:
var value = el.value.toLowerCase();
var prefix = 'abcde';
var className = 'error'; // assume no match
if (value.length >= prefix.length) {
if (value.indexOf(prefix) === 0) { // match
className = 'success';
}
}
else if (prefix.indexOf(value) === 0) { // partial match
className = 'warning'
}
document.getElementById('serial').className = 'serial-entry ' + className;
DEMO
suggesting to use RegEx to match the prefix as follows:
var val = el.value;
if(val.match(/\bABCDE/g)!=null) {
document.getElementById('serial').className = "serial-entry success";
} else {
document.getElementById('serial').className = "serial-entry error";
}
this way you can easily validate if the input is starting exactly with 'ABCDE'.
You can change the RegEx to suite your requirements.
Try this:
if(el.value.toLowerCase().indexOf('abcde') == 0 && el.value.length == 14)
document.getElementById('serial').className = "serial-entry success";
else
document.getElementById('serial').className = "serial-entry warning";