as said on title, validating the prompt if is null (inpname variable) inside the func/while/try wont work. output = {}
meanwhile the testing i did outside works fine.
check the code below please. what did i do wrong?
//works
let test = prompt("testing","aasdasd");
if (test === null) {
console.log("cancel");
}
else {
console.log("ok");
}
let inpname;
//do not work
let func = () => {
while (true) {
try {
inpname = prompt("name ", "name here");
if (inpname.length > 10 || inpname.length <= 3) {
throw "Your name must be at least 10 characters long, but not less than 4";
}
else if ( inpname != inpname.match(/^[a-zA-Z]+$/)) {
throw "A-Z characters accepted only!";
}
//problem here!
else if (inpname === null) {
throw "cant cancel";
}
else {
console.log("success");
break
}
}
catch (err) {
console.log(err);
break
}
}
}
func();
The console outputting {} instead of the exception seems to be a bug in Stack-snippets. You would get more correct output using console.error.
That being said, the issue you're seeing is in part caused because you're not checking that impname is null before you attempt to dereference it.
Changing the ordering of your error checking would solve the problem (Although stack-snippets is still not going to report exceptions as they happen, which is not the behavior you get in a browser)
let func = () => {
while(true) {
var inpname = prompt("name ", "name here");
try {
if (inpname === null) {
throw "cant cancel";
}
if (inpname.length > 10 || inpname.length <= 3) {
throw "Your name must be at least 10 characters long, but not less than 4";
}
if (inpname != inpname.match(/^[a-zA-Z]+$/)) {
throw "A-Z characters accepted only!";
}
return inpname;
} catch(err) {
console.error(err);
}
}
}
func();
Note that you might want to avoid disallowing use of the "cancel" button. If the user doesn't want to provide the requested info, simply exit the app with an appropriate message
Related
/* I want to check for the age of the user, if 18 or above, grant access. If not proceed to the next block where they are asked if they are given permission by their parents. If (yes || Yes || YES) grant access. If (no || No || NO) deny access. If anything apart from the (yes(s) and no(s)) return (Wrong input!). If (!yes(s) and !no(s) "ie, the user cancels,") return (Try Next time!) */
let age = prompt('How old are you?', [18]);
function ageChecker(age) {
if (age >= 18) {
return 'Access Granted!';
}
else if (!age) {
return 'Sorry Enter Your Age!';
}
else {
let confirmation = prompt('Do you have permission from your parents?', ['Yes']);
let posResult1 = 'yes';
let posResult2 = 'Yes';
let posResult3 = 'YES';
let negResult1 = 'no';
let negResult2 = 'No';
let negResult3 = 'NO';
if (confirmation) {
if (posResult1 || posResult2 || posResult3) {
return 'Access Granted!';
}
else if (negResult1 || negResult2 || negResult3) {
return 'Access Denied!';
}
}
else {
return 'Wrong Input Sucker!';
}
return confirmation;
}
}
alert( ageChecker(age) );
The confirmation variable's output should not be compared with the multiple variables, instead of just use the toLowerCase() function
let age = prompt('How old are you?', [18]);
function ageChecker(age) {
if (age >= 18) {
return 'Access Granted!';
}
else if (!age) {
return 'Sorry Enter Your Age!';
}
else {
let confirmation = prompt('Do you have permission from your parents?', ['Yes']);
if ('yes' == confirmation.toLowerCase()) {
return 'Access Granted!';
}else if('no' == confirmation.toLowerCase()){
return 'Access Denied!';
}else if(!confirmation){
return 'Try next time';
}
else {
return 'Wrong Input Sucker!';
}
return confirmation;
}
}
alert( ageChecker(age) );
A couple of things to note:
The result you get back from a prompt is of type string, so if you use age >= 18 it won't be doing a proper comparison. Therefore if you're expecting the user to enter a number, you should convert the result using parseInt().
The answer to a prompt is stored in the variable you assign the prompt function to, so if you do const foo = prompt("What is your name");, the answer will be stored in variable foo. Therefore, your if statements need to check the confirmation variable.
If you are not reassigning a variable, make it a habit to use constants (i.e. const foo = ... instead of let foo = ...).
Lastly, you can use toLowerCase() so you only have to compare the confirmation answers to "yes" and/or "no".
This is a way in which you could write the function instead:
const age = parseInt( prompt('How old are you?', [18]), 10 );
function ageChecker(age) {
if (!age) {
return 'Sorry Enter Your Age!';
}
if (age >= 18) {
return 'Access Granted!';
}
else {
const confirmation = prompt('Do you have permission from your parents?', ['Yes']);
if (!confirmation) {
return 'Wrong Input Sucker!';
}
if (confirmation.toLowerCase() === 'yes') {
return 'Access Granted!';
}
else if (confirmation.toLowerCase() === 'no') {
return 'Access Denied!';
}
return 'Wrong Input Sucker!';
}
}
alert( ageChecker(age) );
Another neat thing you can do when checking the confirmation is using a switch statement instead of an if statement:
const age = parseInt( prompt('How old are you?', [18]), 10 );
function ageChecker(age) {
if (!age) {
return 'Sorry Enter Your Age!';
}
if (age >= 18) {
return 'Access Granted!';
}
else {
const confirmation = prompt('Do you have permission from your parents?', ['Yes']);
if (!confirmation) {
return 'Wrong Input Sucker!';
}
switch (confirmation.toLowerCase()) {
case 'yes':
return 'Access Granted!';
case 'no':
return 'Access Denied!';
default:
return 'Wrong Input Sucker!';
}
}
}
alert( ageChecker(age) );
Depending on the use, switch statements can be a much neater way of checking variables than using a bunch of if statements.
I will expand on Yannik's answer with some advice for what I think is best practice in javascript code.
Use variables to describe conditions in if statements. It's easier to read for other developers, especially if there are several conditions, like hasValidAge, locatedInEurope, and isAdmin.
If the method returns something, return it at the end of the method. That not only makes the code more clear of what it will do, but you are also given a chance to explain - through the variable name - what is returned.
Refactor code. Right now, you have ageChecker with a long if statement, which makes it hard to read. But not only that, you also have a method that makes two things. It's not only checks age, it also asks for the parent's permission. A method should, in best scenario, only do one thing.
I marked the code below to highlight my points.
[EDIT] clarifications based on questions in the comment:
a) The prompt could return undefined if the user removes all text. That will make the code crash later on with confirmation.toLowerCase().
const confirmation = prompt('Do you have permission from your parents?', ['Yes']) // can return undefined
b) I didn't want to sway away too much from your code in my refactor example. If I would have done the refactor properly, I would have used three methods:
function ageCheckerAlert() {
let messageStr = promptAge();
const invalidAge = messageStr == 'Invalid Age';
if (invalidAge) {
messageStr = promptParentsPermission();
}
alert(messageStr);
}
function promptAge() {
let messageStr = 'Invalid Age';
const age = parseInt( prompt('How old are you?', [18]), 10 );
// if statements that changes messageStr, if either valid age or empty input.
return messageStr;
}
function promptParentsPermission() {
// same code as in parentsPermissionChecker() in the snippet below
}
By separating the functionality, you get the added benefit of being able to call promptAge() or promptParentsPermission() alone if you ever would need to do that.
const age = parseInt( prompt('How old are you?', [18]), 10 );
function ageChecker(age) {
let messageStr;
const hasValidAge = age >= 18; // 1
if (!age) {
messageStr = 'Sorry Enter Your Age!';
}
else if (hasValidAge) { // 1
messageStr = 'Access Granted!';
}
else {
messageStr = parentsPermissionChecker(); // 3
}
return messageStr; // 2
}
function parentsPermissionChecker() { // 3
const confirmation = prompt('Do you have permission from your parents?', ['Yes']) || ''; // added a default string.
let messageStr = 'Wrong Input Sucker!';
const typedYes = confirmation.toLowerCase() === 'yes';
const typedNo = confirmation.toLowerCase() === 'no';
if (typedYes) {
messageStr = 'Access Granted!';
}
else if (typedNo) {
messageStr = 'Access Denied!';
}
return messageStr; // 2
}
alert( ageChecker(age) );
how to write simple if take the first expression. Example bellow, my code is looks like to much.
i mean first condition email.val() and second !validateEmail(email.val()) with or expression. my big question is how to detect that first or second condition is executed ?
if(email.val() == "" || !validateEmail(email.val())){
//call the condition again
if(email.val() ==""){
$("#error").html("<p>Email Cant be empty</p>");
$("#error").show();
setTimeout(function(){$("#error").fadeOut();}, 2000)
}else{
$("#error").html("<p>Wrong email format</p>");
$("#error").show();
setTimeout(function(){$("#error").fadeOut();}, 2000)
}
email.focus();
}
so I don't need to call this if again
if(email.val() == ""){
$("#error").html("<p>Email Cant be empty</p>");
$("#error").show();
setTimeout(function(){$("#error").fadeOut();}, 2000)
}else{
$("#error").html("<p>Wrong email format</p>");
$("#error").show();
setTimeout(function(){$("#error").fadeOut();}, 2000)
}
Personally I do that way.
It allow in future to add other errors message or easy change them if needed.
// separate messages values to avoid long texts in the nested if part
// and prevent them from being searched for in parts of code
// where they can be scattered in several places, and possibly repeated
const errorMessage =
{ email_empty : '<p>Email Cant be empty</p>'
, email_wrong : '<p>Wrong email format</p>'
}
var messageError = ''
if(email.val()==='') { messageError = errorMessage.email_empty }
else if ( !validateEmail(email.val())) { messageError = errorMessage.email_wrong }
if (messageError) {
$("#error").html(messageError)
$("#error").show()
setTimeout(function(){$("#error").fadeOut();}, 2000)
email.focus()
}
You have roughly
if (condition1 || condition2) {
if (condition1) {
foo();
} else {
bar();
}
moo();
}
The else can only trigger when condition1==false and condition2==true, hence you can write the same as
if (condition1) {
foo();
moo();
} else if (condition2) {
bar();
moo();
}
So, as I see you're validating an email, there are two options you can look to avoid the nested if-else block or basically repeating your code again.
User Regex Expression: You can validate email, and check if it's empty as well.
if(!regexPat1.test(email)) {
// Do something
}
if(!regexPat2.test(email)) {
// Do something
}
Use nest condition : With this you can avoid rewriting same condition again.
if(email.val().trim() !=="") {
if(!validateEmail(email.val().trim()) {
//Throw invalid email error
}else {
// Do something
}
}else {
// Trow empty value error
}
There can be better solutions as well but I think this solves your doubt.
Simple rearrangement of your existing code.
if(email.val() == "") {
$("#error").html("<p>Email Cant be empty</p>");
$("#error").show();
setTimeout(function(){$("#error").fadeOut();}, 2000);
email.focus();
} else if (!validateEmail(email.val()) {
$("#error").html("<p>Wrong email format</p>");
$("#error").show();
setTimeout(function(){$("#error").fadeOut();}, 2000);
email.focus();
}
Anytime I try using the throw statement in a try/catch command.
It gives me an output of undefined undefined.
Please how can I make it work.
Here is the code I used
try {
let a = prompt("Answer");
if (a == 10) {
throw "right";
} else {
throw "wrong"
}
} catch (i) {
alert(i.message);
}
You have multiple errors:
You have to convert the result to a number before the comparison, you can use the Number function.
You have to show the error and not only its message property since you are throwing a string and not an object.
try {
const a = Number(prompt('Answer'));
if (a === 10) {
throw 'right';
} else {
throw 'wrong';
}
} catch (e) {
alert(e);
}
I'm getting an array of Strings, and if the array has items I want to do one thing and if not I want to do the other. I'm not sure how to check if the array is empty of not. Also when stepping through my code in chrome debugger even if the array has items in it the length is still 0 so I can't use formErrors.length > 0.
Here's my code for getting the errors. This works fine and returns an array of error strings or an empty array:
var formErrors = validateFormData(formData);
function validateFormData(data) {
var errors = [];
if (data["title"].length == 0) {
errors["title"] = "Project title required";
}
if (data["client"].length == 0) {
errors["client"] = "Client name required";
}
if (data["date"].length == 0) {
errors["date"] = "Date required";
} else if (!isValidDateFormat(data["date"])) {
errors["date"] = "Date format invalid - Format: dd/mm/yyyy";
}
if (data["status"] == "") {
errors["status"] = "Please select current status for this project";
}
if (data["type"] == "") {
errors["type"] = "Please select a project type";
}
if (data["extras"].length == 0) {
errors["extras"] = "You must select at least one extra for this project";
}
return errors;
}
Then I want to do one thing if there's no errors and another if there is. But this is the bit that won't work for me.
if (formErrors !== {}) {
displayFormErrors(formErrors);
event.preventDefault();
}
else {
clearForm();
}
I've tried multiple ways and nothing has worked so far. Any help is appreciated, thank you!
EDIT
I can't use the .length on the array cause the length is 0 even when it has data.
Screenshot of chrome debugger
I'm slightly confused about what people are asking sorry, i'm not an expert here is my full code to get a better understanding of what i'm trying to do.
$(document).ready(function () {
$('#submit').on("click", onSubmitForm);
function onSubmitForm(event) {
clearErrorMessages();
var formData = getFormData();
var formErrors = validateFormData(formData);
if (formErrors) {
displayFormErrors(formErrors);
event.preventDefault();
}
else {
clearForm();
// Do other stuff
}
}
function clearForm() {
$('#title').val("");
$('#client').val("");
$('#date').val("");
$('#status').val("planning");
$('#description').val("");
$('.type').prop('checked', false);
$('.extra').prop('checked', false);
$('#title').focus();
}
function clearErrorMessages() {
$(".uk-text-danger").html("");
}
function getFormData () {
var data = [];
data["title"] = $('#title').val();
data["client"] = $('#client').val();
data["date"] = $('#date').val();
data["status"] = $('select#status option:selected').val();
data["description"] = $('#description').val();
if ($("input[name='type']:checked").length > 0) {
data["type"] = $("input[name='type']:checked").val();
}
else {
data["type"] = "";
}
data["extras"] = [];
$.each($("input[name='extras[]']:checked"), function(index, radio) {
data["extras"].push(radio.value);
});
return data;
}
function validateFormData(data) {
var errors = [];
if (data["title"].length == 0) {
errors["title"] = "Project title required";
}
if (data["client"].length == 0) {
errors["client"] = "Client name required";
}
if (data["date"].length == 0) {
errors["date"] = "Date required";
} else if (!isValidDateFormat(data["date"])) {
errors["date"] = "Date format invalid - Format: dd/mm/yyyy";
}
if (data["status"] == "") {
errors["status"] = "Please select current status for this project";
}
if (data["type"] == "") {
errors["type"] = "Please select a project type";
}
if (data["extras"].length == 0) {
errors["extras"] = "You must select at least one extra for this project";
}
return errors;
}
function displayFormErrors(errors) {
for (var field in errors) {
var errorElementId = field + "Error";
$('#' + errorElementId).html(errors[field]);
}
} });
Sorry if this is too much i'm not sure what else to do.
An empty array, string or object is "falsy" in JavaScript.
That is, you can pass the array, string or object directly into the if conditional and it will run depending on if something is in there or not.
if ([]) {
// this will never run
}
if ('') {
// this won't run either
}
if ({}) {
// nor will this
}
var errors = {}; inside the validateFormData function.
And then compare the the object like this.
if (JSON.stringify( formErrors ) !== '{}') { //do something}else { //do something}
Where are you verifying if the formErrors is empty? This verification (the if-else) should be inside the function which submits the form.
Also try using:
if (formErrors.length > 0)
instead of:
if (formErrors !== {})
This is my code (Javascript):
function getNumbers(){
var numberString = document.getElementById("numbers").value;
var actualNumbers = [];
var flowIndex = 0;
for(let i = 0; i < numberString.length; i++){
if(numberString.charAt(i) != " " && numberString.charAt(i) != "\," && numberString.charAt(i) != "\t"){
actualNumbers[flowIndex] = parseInt(numberString.charAt(i));
flowIndex++;
}
else continue;
}
return actualNumbers;
}
function division(){
try{
var answer = getNumbers()[0] / getNumbers()[1];
if(getNumbers()[1] == 0)
throw "bad";
}
catch(error){
throw error.description + "Division by zero error";
}
finally{
return answer;
}
}
I have a function getNumbers() which returns an array, with array[0] = 1 and array[1] = 0. Now, I want to throw an exception "bad" when array[1] == 0. But, neither the try exception nor the catch exception is being thrown, but the finally clause is working. What is the problem?
NOTE: On division by zero, no exception is being thrown, instead answer is coming out to be Infinity. getNumbers() is working properly.
The exception is getting thrown, but then you're suppressing the exception by doing this:
finally {
return answer;
}
The finally clause gets final say. If you return from it, that suppresses the exception and makes the function complete normally.
One way to fix it is to remove the finally clause and put the return answer; inside your try.
Just FWIW, some other notes as comments:
function getNumbers(){
var numberString = document.getElementById("numbers").value;
var actualNumbers = [];
var flowIndex = 0;
// You might consider splitting the string into an array of one-character strings so you
// aren't constantly calling a method (`charAt`), like this:
// `var chars = numberString.split("");`
// Then index into `chars`
// N.B. `let` is an ES2015 (ES6) feature not all JavaScript engines have as it's new;
// the rest of your code is using the older `var`
// --v
for (let i = 0; i < numberString.length; i++){
// No need to escape the comma --------------------------------v
if(numberString.charAt(i) != " " && numberString.charAt(i) != "\," && numberString.charAt(i) != "\t"){
actualNumbers[flowIndex] = parseInt(numberString.charAt(i));
flowIndex++;
}
// No need for the `else continue;` at all
else continue;
// In the above, you regularly call `charAt` four times when once would have been sufficient.
// You might also consider a `switch`
}
return actualNumbers;
}
function division(){
try{
// Rather than calling `getNumbers` three separate times, call it once and remember its return value
// doing the calculation should be AFTER checking [1] for 0, not before
var answer = getNumbers()[0] / getNumbers()[1];
if(getNumbers()[1] == 0)
throw "bad"; // Recommend using Error, e.g.: `throw new Error("bad")`
// Move the `return answer;` here
}
catch(error){
// You've thrown a string, it doesn't have a `description` property
// Separately: Why throw something above, just to catch it here and throw something else?
throw error.description + "Division by zero error";
}
// Remove the finally
finally{
return answer;
}
}
Again just FWIW, I'd probably put responsibility for getting the value from the input in division (or even in the thing calling division) rather than in getNumbers, and use /\d/.test(...) to test if a character is a digit, since there are lots of non-digits that aren't " ", ",", or "\t". And once we know they're digits, we can use +ch instead of parseInt to convert them (but with this input, it's just a style choice [well, there's a performance implication, but 99.99% of the time, that doesn't matter]).
So perhaps:
function getNumbers(str) {
var numbers = [];
str.split("").forEach(function(ch) {
if (/\d/.test(ch)) {
numbers.push(+ch);
}
});
return numbers;
}
function division() {
var numbers = getNumbers(document.getElementById("numbers").value);
if (numbers[1] == 0) {
throw new Error("Division by zero error");
}
return numbers[0] / numbers[1];
}
Or with an alternate getNumbers that is more concise, but makes more loops through the input (which usually doesn't matter):
function getNumbers(str) {
return str.split("")
.filter(function(ch) { return /\d/.test(ch); })
.map(function(ch) { return +ch; });
}
function division() {
var numbers = getNumbers(document.getElementById("numbers").value);
if (numbers[1] == 0) {
throw new Error("Division by zero error");
}
return numbers[0] / numbers[1];
}