Lets say we have 3 variables and I want to check them empty or not without using multiple if else blocks.
let firstName = "adem"
let lastName = "corona"
let email = "adamcorons#gmai.com"
If(firstName === " " && lastName !== " " && email !== " "){
Console.log("first name empty")
} else if .......
What is the best way of solving this?
Thanks a lot
You can avoid chained if-else stataments by returning directly from an if statement. For example, you can have a function such as this one:
function isInputValid({ firstName, lastName, email }) {
if (firstName === '') {
return false;
}
if (lastName === '') {
return false;
}
if (email === '') {
return false;
}
return true;
}
console.log(isInputValid({ firstName: 'adem', lastName: 'corona', email: 'adamcorons#gmai.com' }));
console.log(isInputValid({ firstName: 'adem', lastName: '', email: 'adamcorons#gmai.com' }));
Instead of a boolean value, you could also return an object containing an error message, so you can point out which field is missing.
You could try looping over a required array of fields like this to make it short and flexible:
const validate = (values, required) = {
let errors = {}
required.map(field => {
if (values[field] == '') {
errors[field] = 'Required';
}
}
return errors;
}
const required = ['firstName', 'lastName', 'email'];
const values = {
firstName = '',
lastname = 'test',
email = ''
}
const errors = validate(values, required);
console.log(errors);
// errors = { firstName: 'Required', email: 'Required' }
Making the values an object instead of individual parameters makes it possible to access them dynamically in a loop. This might work depending on what your needs and requirements are.
Then to check if errors exist, just see if the size of the object is 0 by converting it to an array:
if (Object.keys(errors).length == 0) {
// No errors, continue as valid
} else {
// There are errors, handle them as needed.
}
Another great way is to use YUP. It is possible to provide validation anywhere. I always use it. Here is an example.
const schema = Yup.object({
last_name: Yup.string()
.when('first_name', {
is: true,
then: Yup.string().required().label("Last Name"),
}),
});
You can use a similar as following. It also has many other amenities. You can find all the information from the official website below.
https://github.com/jquense/yup
I guess you can try something like this
// declare vars where you should, and add the vars you want to test in an object
let result = [];
let toTest= {
firstName = "adem",
lastName = "corona",
email: "adamcorons#gmai.com",
}
// declare this function to test your values
function testValue(){
Object.keys(toTest).map(key => {
if(!toTest[key]){
result.push(key);
}
}
}
// where you need, call your function to test your strings
testValue();
// in your result array you will have the keys of all the empty vars in your object
Note: if its for field validation you have some plugins like Yup(if Formik) or validate.js that are great for it ! have a look ! https://validatejs.org/
EDIT: Changed the response to an array so you can have all the results. I recommande you to set result as an object {key: errorMessage, ...} so its easier for you to use him after (ex: call the error.nameOfInput in your form to display the error.
EDIT2:
With object result would look like this
// declare vars where you should, and add the vars you want to test in an object
let error= {};
let toTest= {
firstName = "adem",
lastName = "corona",
email: "adamcorons#gmai.com",
}
// declare this function to test your values
function testValue(){
Object.keys(toTest).map(key => {
if(!toTest[key]){
error[key]={`${key} cannot be empty`};
}
}
}
// where you need, call your function to test your strings
testValue();
// in your render
<input name="firstName" ...props />
{error.firstName && <div className='error'>{error.firstName} </div> }
I believe you can't achieve this with plain if like in your example. You would need to have a validation schema and function that you run to validate, like most libraries do it. So you would need have some kind of initial object that couples the field names, their rules and error messages. But then you would need to use object with properties instead of plain variables. With those you cannot avoid checking them without separate if statements.
For reference check how joi or yup works. Although I do understand that using one of those might be too much for you, so I'd just check each field separately.
Related
trying to find a way to condense this. wasnt sure of the best way to do it. basically if criteria is met i display an alert with a parameter that is the message. i was thinking of maybe trying it in function. this is part of a larger function react component. i was also thinking if i could find a way to condense the else if's i could use a ternary. thanks in advance for the assistance.
const handleUpdatePassword = () => {
const allFilled = !reject(passwords).length;
const passwordsMatch = newPassword === conPassword;
const isDifferent = curPassword !== newPassword;
const meetsPasswordRequirements = validatePassword();
const usesName = isUsingName();
const usesUserID = isPartOfUserID();
const isValidPassword = meetsPasswordRequirements && isDifferent;
if (allFilled) {
if (!isDifferent) {
Alert.alert(difPassWord);
} else if (!passwordsMatch) {
Alert.alert(noMatch);
} else if (!meetsPasswordRequirements) {
Alert.alert(pasReqs);
} else if (usesName || usesUserID) {
Alert.alert(pasName);
}
} else {
Alert.alert(fieldNotComplete);
}
if (isValidPassword) {
changePasswordPost(
{
userId,
curPassword,
newPassword
},
partyId
);
}
};
You can create an array of objects for your validation rules, each containing a function which returns a boolean indicating whether that validation passes, and a string with the error message to display.
Then loop over the rules array and alert the message for the first rule that returns false. If they all return true, do the post.
You can split each if statement into a function, then chain them. For example
// here we make a closure to validate, and return a Promise
// condition can be a function
const validate = (condition, error) => ()=> new Promise((res, rej)=>{
if(condition()){
res();
}else{
rej(error);
}
});
const handleUpdatePassword = () => {
const validateFieldsComplete = validate(
()=>!reject(passwords).length,
fieldNotComplete
);
const validateDifPassword = validate(
()=> curPassword !== newPassword,
difPassWord
);
// ...
validateFieldsComplete()
.then(validateDifPassword)
.then(...)
.catch(Alert.alert)
}
It would be much cleaner with pipe. You can take a look at ramda. Or if you are intrested in functional way, you might consider using Monad.
I'd recommend DRYing up the Alert.alert part since all branches have that in common, and just come up with an expression that evaluates to the alert message. Compactness isn't always everything, but if you want it, then nested conditional operators can fit the bill. I'm also rearranging your conditions so that it can be a flat chain of if/elses:
const message
= reject(passwords).length ? fieldNotComplete
: curPassword === newPassword ? difPassWord
: newPassword !== conPassword ? noMatch
: !validatePassword() ? pasReqs
: (isUsingName() || isPartOfUserID()) ? pasName
: null;
const isValid = !message;
if (!isValid) {
Alert.alert(message);
}
(feel free to use any other sort of code formatting pattern; nested conditionals always look awkward no matter which pattern you use, IMO.)
Edit:
Also inlined conditionals which will short-circuit evaluation and make it even more compact.
I'd setup a validations object that has the tests and error messages and then loop over it. If validation fails, it'll throw the last validation error message. Using this method, you only have to maintain your tests in one place and not mess with a block of conditional statements.
const handleUpdatePassword = () => {
const validations = {
allFilled: {
test() {
return newPass && oldPass
},
error: 'Must fill out all fields'
},
correct: {
test() {
return curPass === oldPass
},
error: 'Incorrect password'
},
[...]
}
const invalid = () => {
let flag = false
for (let validation in validations) {
if (!validations[validation].test()) {
flag = validations[validation].error
}
}
return flag
}
if (invalid()) {
Alert.alert(invalid())
} else {
changePasswordPost(
{
userId,
curPass,
newPass
},
partyId
)
}
}
hi everyone this was the method i used for a solution
const messages = [
{
alertMessage: difPassWord,
displayRule: different()
},
{
alertMessage: noMatch,
displayRule: match()
},
{
alertMessage: pasReqs,
displayRule: validatePassword()
},
{
alertMessage: pasName,
displayRule: !isUsingName() || !isPartOfUserID()
}
];
if (allFilled) {
const arrayLength = messages.length;
for (let i = 0; i < arrayLength; i++) {
if (messages[i].displayRule === false) {
Alert.alert(messages[i].alertMessage);
}
}
I'm building a javascript function that receives an input and checks it against stored objects in an array to see if it matches against any
The if else statement don't work
const accounts = []; //holds all user name and password
function getinput() {
let pass = document.getElementById("password").value;
let user = document.getElementById("username").value;
let newuser = {
username: user,
password: pass,
};
let match = (toMatch) => toMatch === newuser.username
if (accounts.some(match) === true) {
return alert("choose another `username");
}
accounts.push(newuser)
return alert("account created")
};
var clik = document.getElementById("login").addEventListener("click", getinput);
It should tell the user if a username is available or not
The direct answer to your question would be along the lines of:
function getInput() {
/* store the value of the input */
var current_userName = document.getElementById("username").value;
/* check if that value already exists in the accounts Array */
var matched = accounts.find(account => account.username === current_userName);
/* conditional for each of the two cases */
if (!matched) {
/* code if username is available */
} else {
/* code if username is NOT available */
}
};
document.getElementById("login").addEventListener("click" , getInput);
You have some mistakes in your code, which need fixing.
Also, look into Array.prototype.find() for more info.
Hope this will help you get started in the right direction. Best of luck!
Finally understood what I was doing wrong had to point toMatch of accounts to check for username contained within the array of object
const = [ ]; //holds all user name and password
function getinput() {
let pass = document.getElementById("password").value;
let user = document.getElementById("username").value;
let newuser = {
username: user,
password: pass,
};
//this was where I got it wrong I was doing toMatch === newuser.username which was wrong
let match = (toMatch) => toMatch.username === user
if (accounts.some(match) === true) {
return alert("choose another username");
}
accounts.push(newuser)
return alert("account created")
};
document.getElementById("login
I am doing some JavaScript front-end and I have a heavy load of forms, all of which need validation. As of now I am using this structure :
function validateForm() {
let form = document.forms["form-add-consumer"];
let id = form["input-id"].value;
let lastName = form["input-last-name"].value;
let firstName = form["input-first-name"].value;
...
let missing = false;
if (lastName.trim() === "") {
document.getElementById("input-last-name-error").className = "error";
missing = true;
}
if (firstName.trim() === "") {
document.getElementById("input-first-name-error").className = "error";
missing = true;
}
if(missing){
return false
} else {
return buildRequest(id, firstName, lastName, ...);
}
}
As you can see, for large forms the function will quickly grow. The code is a bit redundant for each field:
Declare form field
Check its value against a boolean condition
If boolean failed, display the error label and set the failed boolean to true to not send the request
How could I improve this code without complexyfing it too much (no library if possible) ?
Perhaps you could create an object that contians per-field validators, with selectors for respective fields, so that you can perform the nessisary validation in a more concise way like so:
function validateForm() {
let form = document.forms["form-add-consumer"];
let id = form["input-id"].value;
let lastName = form["input-last-name"].value;
let firstName = form["input-first-name"].value;
...
// Construct an object with selectors for the fields as keys, and
// per-field validation functions as values like so
const fieldsToValidate = {
'#input-id' : value => value.trim() !== '',
'#input-last-name' : value => value.trim() !== '',
'#input-first-name' : value => value.trim() !== '',
...,
'#number-field' : value => parseInt(value) > 0, // Different logic for number field
...
}
const invalidFields = Object.entries(fieldsToValidate)
.filter(entry => {
// Extract field selector and validator for this field
const fieldSelector = entry[0];
const fieldValueValidator = entry[1];
const field = form.querySelector(fieldSelector);
if(!fieldValueValidator(field.value)) {
// For invalid field, apply the error class
field.className = 'error'
return true;
}
return false;
});
// If invalid field length is greater than zero, this signifies
// a form state that failed validation
if(invalidFields.length > 0){
return false
} else {
return buildRequest(id, firstName, lastName, ...);
}
}
I was adding validation functions for my Node application, and want a custom message for the field I provide in that function. The issue is, some options need to have a default values, and others I can pass as parameters.
let field = 'email';
let options = {
'message': `${field} is required`
}
function validation(field, opt = options) {
console.log(opt.message);
}
validation('password');
validation('confirm', {message: 'Confirm password is required'})
But in this case, the output is
"email is required"
"Confirm password is required"
While I want the output to be
"password is required"
"Confirm password is required"
I also want to know how Javascript works for this code. How it is accessing all the stuff and how to get the required output.
Thanks
In your code you just create option object and you create it with message field = "email is required". And you never change it's value. As an alternative you may generate object each time you want it to be parametrized:
const field = 'email';
const getOptions = (field) => ({
'message': `${field} is required`
});
function validation(field, opt) {
opt = opt || getOptions(field);
console.log(opt.message);
}
let field = 'email';
let options = {
'message': `${field} is required`
}
This assigns options.message with the current value of field. Since you never changes its value, you get "email is required". The parameter named field in function validation(field, opt = options) is a different variable than the global one with the same name. And its value has no affect on the value of options.message because that assignment was already executed before the function was ever called.
Manipulating global objects is considered poor programming. Instead, you can create the object inside the function:
function validation(field) {
let opt = {
'message': `${field} is required`
}
console.log(opt.message);
}
message:`${field} is required`
Is the same as:
message: field + " is required"
which directly looks up field and results in:
message: "email is required"
To evaluate later you have to use a function that you pass the field name in which then returns the message:
const options = {
message: field => `${field} is required`,
}
function validation(field, opt = options) {
const msg = typeof opt.message === "function" ? opt.message(field) : opt.message;
console.log(msg);
}
validation('password');
validation('confirm', {message: 'Confirm password is required'})
As my app is growing, I'm finding more need for more effective form validation. I personally don't like the angular built in validation that evaluates on field change. And there are always things it won't account for like verifying that a youtube video id is valid. Currently I'm doing validation in each forms controller. I have a function that looks like this. Each field has a message and if there is an error the message will appear red using ng-class.
$scope.validate = function (callback) {
// reset default messages
setMessages();
// create shorter references
var item = $scope.item,
message = $scope.itemMessage;
// title exists
if (item.title === '') {
message.title.message = 'You must give your item a title.';
message.title.error = true;
message.errors += 1;
}
// extract and clear video id with youtube api
if ($scope.temp.video !== undefined && $scope.temp.video !== '') {
var id = '';
var url = $scope.temp.video.replace(/(>|<)/gi,'').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);
if(url[2] !== undefined) {
id = url[2].split(/[^0-9a-z_]/i);
id = id[0];
} else {
id = url;
}
$http.get("http://gdata.youtube.com/feeds/api/videos/" + id)
.then(function (res) {
$scope.item.video = id;
}, function (res) {
message.video.message = 'That is not a valid youtube video.';
message.video.error = true;
message.errors += 1;
$scope.item.video = '';
});
}
if (message.errors === 0) {
callback();
}
};
and then my actual form submission function calls $scope.validate(); passing it a function containing the $http.post(). The two major problems I see are that my callback isn't promise base so there's no guarantee it won't be called when an error exists and I've read again and again to keep large chunks of logic outside of your controller. I haven't found great examples of how this should be done but it must be a common problem.
You can still use Angular's built-in validation and have it not evaluate unless the form has been submitted:
http://scotch.io/tutorials/javascript/angularjs-form-validation#only-showing-errors-after-submitting-the-form
Essentially you set $scope.submitted = true when the form is submitted and set a conditional check so that error messages and classes are only shown when $scope.submitted is set.