I have this code to ask for a number to show in a td. But its not working properly.
The user should only be able to enter a value between the min and max passed in the func1. And the number must be a valid number.
If these conditions are met the td should should show the number entered by the user, otherwise it should appear again the prompt for the user enter a valid number.
The code is working if the user enter a valid number at first, for example in this case the min is 1 and the max is 10, if the user enter a number betwene these two values it works, the number entered by the user appears on the td. However if the user enters for example the number 0, it appears the message "The value 0 is not valid" and it appears again the prompt, and this is correct. However then if the user enter a valid number like 1 it appears undefined instead of 1 in the td.
Do you know why?
HTML
<tr>
<td>Number</td>
<td id="tdNumber"></td>
<td>
<button onclick="func1()">Add</button>
</td>
</tr>
JS
let config = {
numberX: NUMBER_X
}
function showConfig() {
document.getElementById(TD_NUMBER).innerHTML = config.numberX;
}
function func1() {
config.numberX = func2(1, 10, P_CONSTANT);
showConfig();
}
function func2(min, max, p = P_CONSTANT) {
var number = parseInt(prompt("Enter a number between " + min + "and " + max));
if (!Number.isInteger(number)) {
alert("The number " + number + " is not valid.");
func1();
} else if (number > max || number < min) {
alert("The number " + number + " is not valid");
func1();
} else {
return number;
}
}
The way you've written your func1 and func2, they can call each other an unlimited number of times. So imagine this case:
func1() is called (call this func1_A)
func1_A calls func2() to get the number (this is func2_B)
user enters invalid number, func2_B starts another call of func1 (func1_C)
this new invocation func1_C calls func2() to get a new number (func2_D)
user enters valid number, func2_D returns it, func1_C assigns it to numberX
func1_C returns, execution returns to func2_B which has been waiting, func2_B has nothing left to do so it returns undefined
func1_A gets undefined from func2_B and assigns it to numberX
Basically, the fact that you have these functions calling each other will keep adding new invocations to the stack which the old ones have to wait on before they can return. And importantly, the old ones will resume - this means the last thing to happen will always be func1 assigning the most recent return value of func2, which if the user ever entered an invalid number, will be undefined.
Pointy is right: this is a very poor format and is prone to a lot of issues. It isn't an approach you should pursue. At minimum your code shouldn't be needlessly prone to stack overflow errors by having unnecessary recursive function calls.
You can simplify this a lot with a while loop. I'm also a fan of meaningful names, and func1/func2 are as far away from meaningful as you can get, so I've renamed the functions.
const NUMBER_X = 10;
const P_CONSTANT = "???";
const TD_NUMBER = "tdNumber";
let config = {
numberX: NUMBER_X
};
function showConfig() {
console.log(document.getElementById(TD_NUMBER));
document.getElementById(TD_NUMBER).innerHTML = config.numberX;
}
function setNumber() {
config.numberX = getValidNumber(1, 10, P_CONSTANT);
showConfig();
}
function getValidNumber(min, max, p = P_CONSTANT) {
var isValid = false;
var number;
do {
number = parseInt(prompt("Enter a number between " + min + " and " + max));
if(!Number.isInteger(number)) {
alert("The number " + number + " is not valid.");
} else if(number > max || number < min) {
alert("The number " + number + " is not valid");
} else {
isValid = true;
}
} while(!isValid);
return number;
}
<table>
<tr>
<td>Number</td>
<td id="tdNumber"></td>
<td><button onclick="setNumber()">Add</button></td>
</tr>
</table>
The structure of your program is the real problem. It could probably be made to work, but it's simply not the way to do it. Instead, have func2() return some value that indicates an invalid number, and do the iteration inside func1():
const INVALID = {};
function func1() {
let p;
for (p = func2(1, 10); p === INVALID; p = func2(1, 10)) {
alert("Invalid value");
}
config.numberX = p;
showConfig();
}
function func2(min, max, p = P_CONSTANT) {
var number = parseInt(prompt("Enter a number between " + min + "and " + max));
if(!Number.isInteger(number)){
return INVALID;
}
if(number > max || number < min){
return INVALID;
}
return number;
}
when func1 calls func2,
func1 waits for a response.
If the entry is wrong func1 never gets its answer because func2 calls func1 again...
In total this makes 2 func1 functions which both await a response,
and if the new entry is wrong this will make it a third;
Only the last one on this stack will get a return,
while all the others func1 will continue to wait in vain
the correct way to code this is:
const tdNumber = document.getElementById('td-number')
, NUMBER_X = 10
, minVal = 1
, maxVal = 10
, config = { numberX: NUMBER_X }
;
function setNumber()
{
let numberStr = ''
, numberIn = 0
, badEntry = true
;
do
{
numberStr = prompt( "Enter a number between " + minVal + "and " + maxVal )
numberIn = parseFloat( numberStr )
badEntry = ( !Number.isInteger( numberIn ))
|| numberIn < minVal
|| numberIn > maxVal
;
if ( badEntry )
{ alert("The number " + numberStr + " is not valid") }
}
while ( badEntry )
tdNumber.textContent = config.numberX = numberIn
}
table {
border-collapse: collapse;
margin: 1em;
}
td {
border: solid grey 1px;
padding: 1em;
text-align : center;
}
#td-number {
width : 4em
}
<table>
<tr>
<td>Number</td>
<td id="td-number"></td>
<td><button onclick="setNumber()">Add</button></td>
</tr>
</table>
Related
I'm a student currently learning JavaScript. As practice, I wanted to make a cute reading randomizer for a friend with a simple form and a if else input validation process.
Both of my first two cases function as I expect them two, but the third, the one that actually does the calculation, does not send the result of the calculation to be displayed, but rather the formula. I'm not sure where I went wrong.
function pickfic() {
// Get the value of the input fields
let minNumChosen = document.getElementById('minNum').value;
let maxNumChosen = document.getElementById('maxNum').value;
// If input Not a Number or min bigger than max
let reply;
if (isNaN(minNumChosen) || isNaN(maxNumChosen) || minNumChosen > maxNumChosen ) {
reply = "I think you pissed off my sandwich. Also, those numbers make no sense to me.";
}
// If min is zero
else if (minNumChosen == 0) {
reply = "Really, dude? You have an Excel line for 'zero'?? Witch.";
}
else {
// if range is correct, randomize number
const generateRandomNumber = (minNumChosen, maxNumChosen) => {
return Math.floor(Math.random() * (max - min) + min);
};
reply = "Today, you should read fic number " + generateRandomNumber + "!";
}
document.getElementById("result").innerHTML = reply;
}
For the last case, the page displays : "Today, you should read fic number (minNumChosen, maxNumChosen) => { return Math.floor(Math.random() * (max - min) + min); }!"
You can find the codepen here.
EDIT: Turns out I found another bug, which is probably logic based. It seems that for my function, 2 is greater than 10. So it must be judging by the first digit...
function pickfic() {
// Get the value of the input fields
let minNumChosen = document.getElementById('minNum').value;
let maxNumChosen = document.getElementById('maxNum').value;
// If input Not a Number or min bigger than max
let reply;
if (isNaN(minNumChosen) || isNaN(maxNumChosen) || minNumChosen > maxNumChosen ) {
reply = "I think you pissed off my sandwich. Also, those numbers make no sense to me.";
}
// If min is zero
else if (minNumChosen == 0) {
reply = "Really, dude? You have an Excel line for 'zero'?? Witch.";
}
else {
// if range is correct, randomize number
const generateRandomNumber = (min, max) => {
return Math.floor(Math.random() * (max - min) + min);
};
reply = "Today, you should read fic number " + generateRandomNumber(parseInt(minNumChosen), parseInt(maxNumChosen)) + "!";
}
document.getElementById("result").innerHTML = reply;
}
<input id="minNum" placeholder="min">
<input id="maxNum" placeholder="max">
<div id="result"></div>
<button onclick=pickfic()>Click</button>
You had to add parenthesis to generateRandomNumber()
And also make the minNumChosen and maxNumChosen into integers with parseInt().
There was also another mistake where you didn't name the parameters of your generateRandomNumber function (min, max).
function pickfic() {
// Get the value of the input fields
let minNumChosen = document.getElementById('minNum').value;
let maxNumChosen = document.getElementById('maxNum').value;
// If input Not a Number or min bigger than max
let reply;
if (isNaN(minNumChosen) || isNaN(maxNumChosen) || minNumChosen > maxNumChosen ) {
reply = "I think you pissed off my sandwich. Also, those numbers make no sense to me.";
}
// If min is zero
else if (minNumChosen == 0) {
reply = "Really, dude? You have an Excel line for 'zero'?? Witch.";
}
else {
// if range is correct, randomize number
const generateRandomNumber = Math.floor(Math.random() * (maxNumChosen - minNumChosen) + minNumChosen);
reply = "Today, you should read fic number " + generateRandomNumber + "!";
}
document.getElementById("result").innerHTML = reply;
OR
You created a function which takes in values but you didn't provide the min and max value while calling the generateRandomNumber function
function pickfic() {
// Get the value of the input fields
let minNumChosen = document.getElementById('minNum').value;
let maxNumChosen = document.getElementById('maxNum').value;
// If input Not a Number or min bigger than max
let reply;
if (isNaN(minNumChosen) || isNaN(maxNumChosen) || minNumChosen > maxNumChosen ) {
reply = "I think you pissed off my sandwich. Also, those numbers make no sense to me.";
}
// If min is zero
else if (minNumChosen == 0) {
reply = "Really, dude? You have an Excel line for 'zero'?? Witch.";
}
else {
// if range is correct, randomize number
const generateRandomNumber = (min,max) => {
return Math.floor(Math.random() * (max - min) + min);
};
reply = "Today, you should read fic number " + generateRandomNumber(minNumChosen, maxNumChosen) + "!";
}
document.getElementById("result").innerHTML = reply;
}
I figured out the last bug thanks to #SchokokuchenBäcker's input on the first issue.
My conditional was comparing strings, which is why 20 was smaller than 5 !
Writing the first conditional like this:
if (isNaN(minNumChosen) || isNaN(maxNumChosen) || parseInt(minNumChosen) >= parseInt(maxNumChosen) )
makes it functional!
so I was given the task to make a unique code by adding numbers after the code.
and I have tried and succeeded but there is one thing that blocks what if the number has reached its limit? 9999 value
how to reset it to 00001. Lift digit increased by 1
here's my snippet code
function getNewCode(value, callback){
let newCode = _.upperCase(value) + "-";
let lastCode = newCode + "0001"
Transaction.findOne({tr_number: new RegExp(newCode, 'i')}, (err, doc) => {
if(err) callback(err)
if (!_.isNil(doc)){
let arr = doc.tr_number.split("-");
// in this part, i want got some conditional to set a new value
//when it got max length = 9999 for an example
let inc = parseInt(arr[1]) + 1;
lastCode = newCode + ("0000"+inc).slice(-4);
console.log('lastCode', ciduk, lastCode);
return callback(lastCode);
}else{
return callback(lastCode);
}
}).sort({tr_number: -1})
};
sorry for my bad language :) grats.
You can get number size by converting it toString() and get it length.
function getNext(prevStr) {
let padSize = prevStr.length;
let next = parseInt(prevStr, 10) + 1;
if (next >= 10 ** padSize) {
padSize++;
next = 1;
}
return next.toString().padStart(padSize, '0');
}
console.log(getNext('0099')); // '0100'
console.log(getNext('9999')); // '00001'
I'm completing a JavaScript Codecademy course and am having trouble with one of the independent projects that requires you to design a number guessing game. For some reason, when "0" is involved, it returns incorrectly.
JavaScript and I aren't best friends as is, but I had a hard time with what's a relatively simple project and decided to try out one of the "challenge yourself" sections and I just can't make it work at all, or work out what's going wrong.
function generateTarget() {
return Math.floor(Math.random() * 10);
};
function compareGuesses(userGuess, computerGuess, targetNumber) {
function getAbsoluteDistance() {
const uGuess = Math.abs(generateTarget() - userGuess);
const cGuess = Math.abs(generateTarget() - computerGuess);
return uGuess - cGuess
};
if (getAbsoluteDistance() <= 0) {
return true
} else {
return false
};
};
// 'human' is input when return is true; 'computer' when return is false
function updateScore(winner) {
if (winner === 'human') {
humanScore ++;
} else if (winner === 'computer') {
computerScore ++;
};
};
function advanceRound() {
currentRoundNumber +=1;
};
It's essentially a game where the computer generates a random "target" number, you enter a guess number and the computer generates a guess number. Depending on which guess number is closer, you or the computer wins. If you guess the same number, or your guesses are equidistant, the human is meant to win.
This is (just about) working now, except in cases when:
the "target" number is 0. (The computer always wins)
you and the computer guess the same number. (The computer always wins)
you and the computer guess different but equidistant numbers from the target number (The computer always wins)
I'd like to try and get my head around some basic JavaScript so I can move on to something else for a bit, but can't work out what's wrong at all or how to fix it. The only thing that I can identify that these cases have in common is the fact that there's always a "0" somewhere in the absolute distance calculation.
Any help would be massively appreciated!
Kind of made it interactive. From what you say the user wins in the event of a tie or when you guess the same number (a tie). I think the comments indicated why it was failing initially, or at least what is what I see. You were comparing to two different targets, and you can see that in a Fiddle because the results were not consistent.
const userinput = document.getElementById("user");
const computerinput = document.getElementById("computer");
const targetvalue = document.getElementById("target");
const roundcount = document.getElementById("round");
var humanScore = 0;
var computerScore = 0;
var rounds = 0;
document.getElementById("generate").addEventListener("click", function(e) {
targetvalue.value = generateTarget();
});
document.getElementById("calc").addEventListener("click", function(e) {
let result = compareGuesses(userinput.value, computerinput.value, targetvalue.value);
if(result) humanScore++
else computerScore++
rounds++
roundcount.innerHTML = rounds;
alert("Score: Human: " + humanScore + ", Computer: " + computerScore );
});
function generateTarget() {
return Math.floor(Math.random() * 10);
}
function compareGuesses(userGuess, computerGuess, targetNumber) {
const uGuess = Math.abs(targetNumber - userGuess);
const cGuess = Math.abs(targetNumber - computerGuess);
if (uGuess - cGuess <= 0) {
return true
} else {
return false
}
}
<input id = "user" value="" placeholder ="user">
<input id = "computer" value="" placeholder ="computer"><br>
<input id = "target" value="" placeholder ="target">
<button id ="calc" type = "submit">
Submit
</button>
<button id ="generate" type = "submit">
Generate Number
</button><br>
Round: <span id = "round"></span>
The Snippet should allow testing easily. Did not add a thing to generate the computer guess, but that would be similar to generating a target.
I would do like:
function NumGuessGame(){
this.computerScore = this.score = 0;
this.guess = function(num){
if(num === Math.floor(Math.random()*10)){
this.score++;
}
else{
this.computerScore++;
}
return this;
}
}
var gg = new NumGuessGame;
gg.guess(9).guess(11).guess(7).guess(7);
if(gg.computerScore >= gg.score){
console.log('Computer Wins');
}
else{
console.log('You Win');
}
Of course, you should notice that the computer will almost always win under this scenario. You should notice the odds go up here:
function NumGuessGame(){
this.computerScore = this.score = 0;
this.guess = function(num){
if(num === Math.floor(Math.random()*10)){
this.score++;
}
else{
this.computerScore++;
}
return this;
}
}
var gg = new NumGuessGame;
gg.guess(4);
if(gg.computerScore >= gg.score){
console.log('Computer Wins');
}
else{
console.log('You Win');
}
Note that the examples above expect a 0-9 guess or you lose no matter what.
I am building a tip calculator and I couldn't make the if statement in my function work it just skips to calculating.
function calculate() {
var bill = parseInt(document.getElementById("bill").value);
var tip = parseInt(document.getElementById("tip").value) * .01;
var persons = parseInt(document.getElementById("persons").value);
if (bill == "" || tip == "") {
alert("Please enter value");
return;
};
if (persons == "" || persons <= 1) {
persons = 1;
document.getElementById("perPerson").style.display = "none";
} else {
}
let totalTipPer = (bill * tip) / persons;
let totalPer = (bill + (tip * 100)) / persons;
let totalTip = bill * tip;
let total = bill + (tip * 100);
totalTipPer = totalTipPer.toFixed(2);
totalPer = totalPer.toFixed(2);
total = total.toFixed(2);
totalTip = totalTip.toFixed(2);
document.getElementById("total-tip/person").innerHTML = totalTipPer;
document.getElementById("total-price/person").innerHTML = totalPer;
document.getElementById("total-tip").innerHTML = totalTip;
document.getElementById("total-price").innerHTML = total;
}
document.getElementById("calculate").onclick = function () {
calculate();
document.getElementById('results').style.display = 'block';
}
I expect the div encapsulating Tip Amount per person and total per person and to not appear when the input value of persons is empty.
Function parseInt returns 'An integer number parsed from the given string. If the first character cannot be converted to a number, NaN is returned.'
if you rpovide an empty value ('') it will return
NaN which is not equal to anything, even itself.
there are several ways to fix this:
check if it is a NaN with Number.isNaN(var)
use an intermediate value like var personsValue and check if it is equal to empty string ''.
use Hybrid suggested solution and assign a 0
value for falsy value('', undefined, n
ull etc...)
The issue is that persons becomes NaN, since if the value is left blank, "" becomes NaN when it is run through parseInt().
The way to fix this is by defaulting it to 0 if the field is left blank.
var persons = parseInt(document.getElementById("persons").value || 0);
as others pointed out parseInt is returning NaN if the field is blank, but this will also happen if the user inputs $5.00 for example.
Here's one way to make sure the value can be converted to a number before doing so.
// This function determines if a JavaScript String can be converted into a number
function is_numeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function calculate() {
// first put the input values into separate variables
billValue = document.getElementById("bill").value;
tipValue = document.getElementById("tip").value;
personsValue = document.getElementById("persons").value;
// use the is_numeric() function above to check if the values can be converted to numeric
if (!is_numeric(billValue) || !is_numeric(tipValue)) {
alert("Please enter values for bill and tip");
return;
}
// the rest of your code here
}
Hope this helps.
function mathProb() {
var x = parseInt(prompt("Enter first integer", ""));
var y = parseInt(prompt("Enter the second integer", ""));
var operand = prompt("Enter type of operation", "");
if (operand == "+" || "add") {
var sum = x + y;
document.write("Your sum is " + sum);
} else if (operand == "-") {
var difference = x - y;
document.write("Your difference is " + difference);
} else if (operand == "*") {
var product = x * y;
document.write("Your product is " + product);
} else if (operand == "/") {
var quotient = x / y;
document.write("Your quotient is " + quotient);
} else {
document.write("Oops something went wrong");
}
}
Well to start I am reading a book on JavaScript and have been doing pretty well, I am now on functions and was getting those until parameters were introduced can someone explain what a parameter is in a clear simple way?
Why does this function work when named function mathProb() and function mathProb(x,y,operand)?
And a third question off of the previous one is why when I call the function in html
(<input type="button" value="Calculator" onclick="mathProb()"/>)
I have to use mathProb() even if its named mathProb(x,y,operand). If I call it using that name it wont work. Please help?
First, the line:
if(operand=="+"||"add")
Will always be true, as the expression "add" will always return a true-ish value. You probably mean to use:
if(operand=="+" || operand=="add")
Your question about parameters is probably a pretty broad topic. Basically, a parameter is a variable given to a function so that the function can be generalized to work with any data. For example, if you wanted to write a function that can add two numbers, the function must know which two numbers to add. These numbers would be supplied as parameters:
function add(x, y)
{
return x + y; // x and y are variables known within this function
}
You'd then call your function as so:
var oneplusone = add(1, 1); // Adds 1 and 1
Using this knowledge, you could rewrite your code as this:
function mathProb(x, y, operand)
{
// No need for var x, etc as these can now be passed in..
}
Then call your function:
mathProb(
parseInt(prompt("Enter first integer","")), // This is x
parseInt(prompt("Enter the second integer","")), // This is y
prompt("Enter type of operation","") // This is operand
);
Keep in mind you could still call your function mathProb without the parameters:
mathProb();
...if you really wanted to. JavaScript does allow this (unlike many other languages). However, within your function, the variables x, y and operand will be undefined which might cause unexpected results if you don't account for that.
You need call and pass function like mathProb(1,2,'+')
HTML:
<input type="button" value="Calculator" onclick="mathProb(1,2,'+')"/>
Javacript:
function mathProb(x,y,operand)
{
//var x = parseInt(prompt("Enter first integer",""));
//var y = parseInt(prompt("Enter the second integer",""));
//var operand = prompt("Enter type of operation","");
if(operand=="+"|| operand=="add")
{
var sum = x+y;
document.write("Your sum is " +sum);
}
else if(operand=="-")
{
var difference = x-y;
document.write("Your difference is " +difference);
}
else if(operand=="*")
{
var product = x*y;
document.write("Your product is " +product);
}
else if(operand=="/")
{
var quotient = x/y;
document.write("Your quotient is " +quotient);
}
else
{
document.write("Oops something went wrong");
}
}