fifer4prez
fifer4prez

Reputation: 31

condense if, else JS with similar condition rules

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
  );
}

};

Upvotes: 3

Views: 136

Answers (5)

fifer4prez
fifer4prez

Reputation: 31

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);
    }
  }

Upvotes: 0

selfagency
selfagency

Reputation: 1578

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
    )
  }
}

Upvotes: 0

Jacob
Jacob

Reputation: 78840

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.

Upvotes: 1

Pooya Haratian
Pooya Haratian

Reputation: 785

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.

Upvotes: 1

Jonas H&#248;gh
Jonas H&#248;gh

Reputation: 10874

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.

Upvotes: 1

Related Questions