Express Validator - How to handle conditional Validation

18.3k Views Asked by At

I have a form where if a person's shipping address is different from their Billing address they will select a radio button saying "no".

I need to be able to check what the value of this is, and if it is "no" check the form that unfolds. if it is "yes" I skip on to the next validations below. The "yes section is working, but the "no" section always returns invalidated. is there a way to nest validations in a conditional like this with this library?

Here is a screenshot of the form:

Test Form Image

Here is the validation code i have for this scenario:

    router.post('/testData2/', [
      body('billingSameAsShipping', "Please Fill All Fields Of Your Billing Address").custom((value) => {
        if (value === 'no') {
          [
            body('billingFirstName', "Please Enter Your First Name").isLength({
              min: 1
            }),
            body('billingLastName', "Please Enter Your Last Name").isLength({
              min: 1
            }),
            body('billingAddress1', "Please Enter Your Billing Address").isLength({
              min: 1
            }),
            body('billingZip', "Please Enter Your Billing ZipCode").isLength({
              min: 1
            }),
            body('billingCity', "Please Enter Your Billing City").isLength({
              min: 1
            }),
            body('billingState', "Please Enter Your Billing State").isLength({
              min: 1
            })
          ]
        } else {

          return Promise.resolve();
        }

      }),
    body('creditCardNumber', 'Please Enter A Vaild Credit Card Number').isCreditCard(),
    body('expmonth', 'Exp Month Empty').isLength({
      min: 1
    }),
    body('expyear', 'Exp Year Empty').isLength({
      min: 1
    }),
    body('CVV', 'CVV Empty').isLength({
      min: 3
    })
  ],
  (req, res) => {...

Here is the request object we are checking against

{
  billingSameAsShipping: 'no',
  billingFirstName: 'First',
  billingLastName: 'Last',
  billingAddress1: '450 Test Ave',
  billingZip: '12345',
  billingCity: 'San Diego',
  billingState: 'CA',
}
3

There are 3 best solutions below

3
On BEST ANSWER

I got it, Express Validator has a conditional check built-in

I used oneOf([]) to check if the value of the radio buttons was "yes" or check that the billing address fields were filled in.

router.post('/testData2/', [
    oneOf([
      [
        body('billingFirstName', "Please Enter Your First Name").isLength({
          min: 1
        }),
        body('billingLastName', "Please Enter Your Last Name").isLength({
          min: 1
        }),
        body('billingAddress1', "Please Enter Your Billing Address").isLength({
          min: 1
        }),
        body('billingZip', "Please Enter Your Billing ZipCode").isLength({
          min: 1
        }),
        body('billingCity', "Please Enter Your Billing City").isLength({
          min: 1
        }),
        body('billingState', "Please Enter Your Billing State").isLength({
          min: 1
        })
      ],
      body('billingSameAsShipping').equals('yes')
    ], "Please Fill Out All Fields Of Your Billing Address"),
    body('creditCardNumber', 'Please Enter A Vaild Credit Card Number').isCreditCard(),
    body('expmonth', 'Exp Month Empty').isLength({
      min: 1
    }),
    body('expyear', 'Exp Year Empty').isLength({
      min: 1
    }),
    body('CVV', 'CVV Empty').isLength({
      min: 3
    })
  ],
  (req, res) => {...

That seems to be working correctly now.

Anyone have any other solutions to this one, or see anything wrong with my solution above?

1
On

There is an easier way to turn validators conditional. The condition is a boolean, so you can simply use the && logical operator to decide whether to add a validator to the array or not.

router.post('/testData2/', [

   req.body.billingSameAsShipping && body('billingFirstName')
      .isLength({ min: 1 }),

   req.body.billingSameAsShipping && body('billingLastName')
      .isLength({ min: 1 })

   ].filter(x => !!x)
)

The filter at the end is needed because if the condition evaluates to false, it will add false to the array. That would cause a runtime error, so it has to be removed. This is the most concise way to add validators conditionally.

0
On

You can also use this conditional which allows to do stuff like:

body('billingFirstName').if(body('billingSameAsShipping').equals('yes')).notEmpty(),

and the sort