Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross Field Validations #475

Closed
daniel-sc opened this issue Oct 30, 2020 · 6 comments
Closed

Cross Field Validations #475

daniel-sc opened this issue Oct 30, 2020 · 6 comments

Comments

@daniel-sc
Copy link

Are cross field validations possible? Eg "either email or phone must be set".

@ealush
Copy link
Owner

ealush commented Oct 31, 2020

Hey @daniel-sc, thanks for reaching out. Yes, cross field validation is possible and quite simple. There are multiple ways of achieving this, depending on your specific validation strategy.

I am adding a few example. I recommend you open the live demos as they add a few more details.

Option 1: use the any utility

Your specific example can be handled with the any utility function. The any utility function takes a series of functions or expressions, and as long as at least one evaluates to true, it will mark your validation as passing.

There are two possible ways to use any:

Use any to run one of multiple tests

the any utility will run each function until a passing test is found. This means that once one of the tests passes, the others won't run at all, saving you some performance.

Live Demo: https://codesandbox.io/s/demo-forked-tdj92?file=/src/validate.js

import vest, { test, enforce } from "vest";
import any from "vest/any";

export default vest.create("form_name", (data = {}) => {
  any(
    () =>
      test("email", "Email or phone must be set", () => {
        enforce(data.email).isNotEmpty();
      }),
    () =>
      test("phone", "Email or phone must be set", () => {
        enforce(data.phone).isNotEmpty();
      })
  );
});

Use any to run use different conditions in the same test

You could also use any within your test, if you have a joined test for both scenarios. This means that you have to return a boolean from your tests.

Demo: https://codesandbox.io/s/demo-forked-ltn8l?file=/src/validate.js

import vest, { test, enforce } from "vest";
import any from "vest/any";

export default vest.create("form_name", (data = {}) => {
  test("email_or_phone", "Email or phone must be set", () =>
    any(
      () => {
        enforce(data.email).isNotEmpty();
        return true;
      },
      () => {
        enforce(data.phone).isNotEmpty();
        return true;
      }
    )
  );
});

Option 2: use if/else

If your field depends on a different field's existence or a different simple condition, you could use a basic if/else statement.
In the following example I only validate confirm if password is not empty:

DEMO: https://codesandbox.io/s/demo-forked-z2ur9?file=/src/validate.js

import vest, { test, enforce } from "vest";

export default vest.create("user_form", (data = {}) => {
  test("password", "Password is required", () => {
    enforce(data.password).isNotEmpty();
  });

  if (data.password) {
    test("confirm", "Passwords do not match", () => {
      enforce(data.confirm).equals(data.password);
    });
  }
});

Option 2.5 if/else based on a different field

Sometimes you might want to run a certain validation based on the validation result of a previously run test, for example - only test for password strength if password DOESN'T have Errors. You could access the intermediate validation result and use it mid-run.

This requires using the function created from vest.create():

import vest, { test, enforce } from "vest";

const v = vest.create("user_form", (data = {}) => {
  test("password", "Password is required", () => {
    enforce(data.password).isNotEmpty();
  });

  if (!v.hasErrors('password')) {
    test("password", "Password is weak", () => {
      enforce(data.password).longerThan(8);
    });
  }
});
export default v;

@daniel-sc
Copy link
Author

@ealush thanks for the info!
Like it!

@ealush
Copy link
Owner

ealush commented Nov 1, 2020

Should probably add this as a docs section. Thanks for the good question!

@daniel-sc
Copy link
Author

@ealush The live demo seems to be wrong:
image

@ealush
Copy link
Owner

ealush commented Nov 1, 2020

@daniel-sc, you are right. I tested email twice but never phone, so the example "worked" correctly, but I had a bug 😅
Updated the link, and here it is again: https://codesandbox.io/s/demo-forked-ltn8l?file=/src/validate.js

@ealush
Copy link
Owner

ealush commented Nov 1, 2020

Also, added another example (2.5). Could be very useful.

@ealush ealush closed this as completed Nov 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants