Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation using Formik with Yup and React-select

I'm working with a react form validation using Yup along with Formik. There is a react-select element in the form which needs to be validated as well. For validation i'm making use of validationSchema of Formik to validate form on value change. I need only value of the select field as a string so cant take the complete object (key-value). The select field is working fine how ever the validation error message is not cleared. The question is how can I validate the select field with existing approach?

Below is the minimal code sample.

import ReactDOM from "react-dom";
import React, { useState } from "react";
import { Grid, TextField, Button } from "@material-ui/core";
import { Formik } from "formik";
import * as Yup from "yup";
import Select from "react-select";
import "./styles.css";

function App() {
  const [selectedYear, setSelectedYear] = useState("");

  const testSchema = Yup.object().shape({
    name: Yup.string().required("Enter Name"),
    year: Yup.string().required("Select Year")
  });

  const initialValues = {
    name: "",
    year: ""
  };

  const handleYearChange = (selectedYear, values) => {
    values.year = selectedYear.value;
    console.log(selectedYear);
    setSelectedYear(selectedYear);
  };

  const yearOptions = [
    { value: "1960", label: "1960" },
    { value: "1961", label: "1961" },
    { value: "1962", label: "1962" },
    { value: "1963", label: "1963" },
    { value: "1964", label: "1964" },
    { value: "1965", label: "1965" }
  ];

  return (
    <Formik validationSchema={testSchema} initialValues={initialValues}>
      {({
        handleChange,
        handleBlur,
        values,
        errors,
        touched,
        handleSubmit,
        setFieldTouched
      }) => {
        return (
          <>
            <Grid container spacing={2}>
              <Grid item md={12} xs={12}>
                <TextField
                  label="Name"
                  name="name"
                  margin="normal"
                  variant="outlined"
                  onChange={handleChange("name")}
                  style={{ width: "100%", zIndex: 0 }}
                  value={values.name}
                  onBlur={() => {
                    console.log("name");
                  }}
                />
                {errors.name}
              </Grid>

              <Grid item md={6} xs={12}>
                <Select
                  placeholder="Year"
                  value={selectedYear}
                  onChange={selectedOption => {
                    handleYearChange(selectedOption);
                    // handleYearChange(selectedOption, values);
                    // values.year = selectedOption.value;
                    console.log("values", values.year);
                    handleChange("year");
                  }}
                  isSearchable={true}
                  options={yearOptions}
                  name="year"
                  isLoading={false}
                  loadingMessage={() => "Fetching year"}
                  noOptionsMessage={() => "Year appears here"}
                />
                {errors.year}
              </Grid>
              <Grid
                item
                md={4}
                style={{ marginTop: "24px", marginBottom: "10px" }}
                xs={12}
              >
                <Button onClick={handleSubmit}>Save</Button>
              </Grid>
            </Grid>
          </>
        );
      }}
    </Formik>
  );
}

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

Here is the codesandbox :

Edit throbbing-shadow-6f6yw

PS: I'm new to Reactjs.

like image 412
Nik Avatar asked Aug 21 '19 14:08

Nik


2 Answers

Change

handleChange("year")

To

handleChange("year")(selectedOption.value);

Currently the year field in the Formik value isn't updated. The handleChange() function returns a new function that can be called with a value to update the Formik state.

Easiest way to spot these things is by outputting the Formik props with the following code:

<pre>{JSON.stringify(props, null, 2)}</pre>

See this sandbox for an example. In the sandbox I have completely removed the need for the custom year state. I'd recommend using only the Formik state to manipulate the values. Using only Formik state you will probably have to extract only the year part when saving, because react-select uses the complete object by default.

like image 71
Jap Mul Avatar answered Sep 21 '22 14:09

Jap Mul


easy solution :: it works,,,,, even for any other input type of input field like react-color,, or datepicker or anything... By Using this logic.. You need to fool formik that it will consider this as an event,,,Example is given below,,,,, here - handleChange is from formik

validationSchema = yup.object({
     year_value :yup.object().required('*year value is required.')
})

<Select 
    className="  "
    name="year_value"
    id="year_value"
    placeholder='Choose year value'
    value={values.year_value}
    onBlur={handleBlur}
    onChange={selectedOption => {
        let event = { target : { name:'year_value',value: selectedOption}}
        handleChange(event)
    }}
    onBlur={()=>{
      handleBlur({ target: {name:'year_value'} });
    }}
    options={yearOptions}
/>

like image 33
Manthan Patel Avatar answered Sep 20 '22 14:09

Manthan Patel