1
votes

I created a simple form with React, Formik and Yup. It contains a list of numbers. I want to validate that the order of the list is ascending:

  • 1,2,3 is valid
  • 1,5,100 is valid
  • 3,1,2 is invalid
  • 100,99,98 is invalid

I checked the Yup documentation but there was nothing for ascending or descending. What would be the best way to go here?

import React, { useState, Fragment } from "react";
import ReactDOM from "react-dom";
import { Formik, FieldArray, Form, Field } from "formik";
import * as Yup from "yup";

function App() {
  const [values] = useState({
    someNumbers: [1, 2, 3]
  });

  const validationSchema = Yup.object().shape({
    // how can I check for the correct order here?
    someNumbers: Yup.array()
  });

  return (
    <div className="App">
      <Formik
        initialValues={values}
        onSubmit={values =>
          setTimeout(() => {
            alert(JSON.stringify(values, null, 2));
          }, 500)
        }
        validationSchema={validationSchema}
      >
        {formikProps => (
          <Form>
            <FieldArray
              name="listOfDates"
              render={({ move, swap, push, insert, unshift, pop }) => (
                <Fragment>
                  {formikProps.values.someNumbers.map((d, index) => (
                    <Field type="number" name={`someNumbers.${index}`} />
                  ))}
                </Fragment>
              )}
            />
            <div>
              <button type="submit">Submit</button>
            </div>
            <pre>{JSON.stringify(formikProps.errors, null, 2)}</pre>
            <pre>{JSON.stringify(formikProps.values, null, 2)}</pre>
          </Form>
        )}
      </Formik>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Here is the code as codesandbox.

1

1 Answers

1
votes

I guess I'm a little bit late. But this could help you:

// Custom Validation
Yup.addMethod(Yup.array, 'sorted', function (message, parser = a => a) {
  return this.test('sorted', message, function (list) {
      return Boolean(
        list
          .map(parser)
          .reduce((valid, item) => valid && item >= valid && item)
      );
  });
});

Then you could do something like:

const arr1 = [1,2,3];
const validationSchema1 = Yup.array().sorted('Shame!');

const arr2 = [{id:1},{id:2},{id:3}];
const validationSchema2 = Yup.array().sorted('Shame!', a => a.id);

Here it is an example: https://codesandbox.io/s/nameless-dust-fjxon