Сборщики даты и времени Ant не передают значение через Formik (реагирует) - PullRequest
0 голосов
/ 17 ноября 2018

В настоящее время я работаю над формой бронирования, которая находится в React с использованием Formik. Я также включил «Выбор даты» и «Выбор времени» Ant Design для даты и времени бронирования соответственно, но у меня возникают трудности с возвратом значений в компонент.

Вот как я настроил его в компоненте формы (я пропустил другие несвязанные поля):

const { booking, handleSubmit, mode } = this.props;

...

<Formik
    initialValues={booking}
    onSubmit={handleSubmit}
    render={({errors, touched, isSubmitting}) => (
        <Form>
        ...
<div className="form-group col-sm-4 col-md-6 col-lg-4">
    <label htmlFor="booking_date">
        Booking Date <span className="required">*</span>
    </label>
    <DatePicker onChange={ (date, dateString) => setFieldValue('booking_date', dateString)} defaultValue={this.state.bookingDate}
        className="form-control" format={this.state.dateFormat} />
</div>
<div className="form-group col-sm-4 col-md-6 col-lg-4">
    <label htmlFor="start_time">
        Start Time <span className="required">*</span>
    </label>
    <TimePicker
        defaultValue={this.state.startTime}
        format={this.state.timeFormat}
        className="form-control"
        onChange={this.handleStartTimeChange}
        minuteStep={5}
        id="start_time"
        name="start_time"
    />
</div>

Это функция, которая обрабатывает изменение времени (только набор состояний):

handleStartTimeChange(time) {
    this.setState({
        startTime: time
    });
}

А затем на родительском элементе компонент настроен так:

<BookingForm
    show={true}
    booking={null}
    handleSubmit={this.saveBooking.bind(this)}
    mode="add"
/>

А функция saveBooking просто консоль записывает параметры. Тем не менее, он только отключает другие поля, такие как firstname, surname и email. Даты полностью игнорируются, и я не знаю, как заставить форму распознавать их - я даже пытался создать скрытое поле Formik для репликации значения даты при отправке, но оно все равно игнорируется. Имя и идентификатор поля являются правильными и соотносятся с базой данных, как и все остальные - поэтому я не понимаю, почему они не будут читать эти данные?

Ответы [ 2 ]

0 голосов
/ 18 ноября 2018

Я не понимаю, почему он не читает эти данные?

Formik передает значения как values prop, они обновляются с использованием setFieldValue. Когда вы храните значения в состоянии, Formik ничего об этом не знает .

Конечно, нет ничего плохого в сохранении значений в состояние (при условии, что оно работает), но Вы должны определить внутренний обработчик отправки, чтобы присоединить эти значения к другим .Простым вызовом реквизита:

onSubmit={handleSubmit}

у вас нет шансов сделать это.Будут переданы только обработанные значения Formik .Вам необходимо определить внутренний обработчик отправки, например:

const handleSubmit = values => {
  // init with other Formik fields
  let preparedValues = { ...values }; 

  // values from state
  const { startTime, startDate } = this.state; 

  // attach directly or format with moment
  preparedValues["startTime"] = startTime;
  preparedValues["startDate"] = startDate;

  // of course w/o formatting it can be done shorter
  // let preparedValues = { ...values, ...this.state }; 

  console.log(preparedValues);

  // call external handler with all values
  this.prop.handleSubmit( preparedValues );
}
0 голосов
/ 18 ноября 2018

Проще говоря, вам нужно использовать Ant 100 Form.Item внутри пропеллера Formik Field * component.

Вы сможете добавлять и другие элементы формы Antd, однако есть несколько причуд.Поэтому я бы рекомендовал использовать только один или другой (не оба).

Рабочий пример : https://codesandbox.io/s/4x47oznvvx

component / AntFields.js (причина создания двух разных onChange функций заключается в том, что один из компонентов муравья передает обратно event (event.target.value), а другой возвращает обратно value - к сожалению, причуду при использовании Formik с Antd)

import map from "lodash/map";
import React from "react";
import { DatePicker, Form, Input, TimePicker, Select } from "antd";

const FormItem = Form.Item;
const { Option } = Select;

const CreateAntField = Component => ({
  field,
  form,
  hasFeedback,
  label,
  selectOptions,
  submitCount,
  type,
  ...props
}) => {
  const touched = form.touched[field.name];
  const submitted = submitCount > 0;
  const hasError = form.errors[field.name];
  const submittedError = hasError && submitted;
  const touchedError = hasError && touched;
  const onInputChange = ({ target: { value } }) =>
    form.setFieldValue(field.name, value);
  const onChange = value => form.setFieldValue(field.name, value);
  const onBlur = () => form.setFieldTouched(field.name, true);
  return (
    <div className="field-container">
      <FormItem
        label={label}
        hasFeedback={
          (hasFeedback && submitted) || (hasFeedback && touched) ? true : false
        }
        help={submittedError || touchedError ? hasError : false}
        validateStatus={submittedError || touchedError ? "error" : "success"}
      >
        <Component
          {...field}
          {...props}
          onBlur={onBlur}
          onChange={type ? onInputChange : onChange}
        >
          {selectOptions &&
            map(selectOptions, name => <Option key={name}>{name}</Option>)}
        </Component>
      </FormItem>
    </div>
  );
};

export const AntSelect = CreateAntField(Select);
export const AntDatePicker = CreateAntField(DatePicker);
export const AntInput = CreateAntField(Input);
export const AntTimePicker = CreateAntField(TimePicker);

компонентов / FieldFormats.js

export const dateFormat = "MM-DD-YYYY";
export const timeFormat = "HH:mm";

компонентов / ValidateFields.js

import moment from "moment";
import { dateFormat } from "./FieldFormats";

export const validateDate = value => {
  let errors;

  if (!value) {
    errors = "Required!";
  } else if (
    moment(value).format(dateFormat) < moment(Date.now()).format(dateFormat)
  ) {
    errors = "Invalid date!";
  }

  return errors;
};

export const validateEmail = value => {
  let errors;

  if (!value) {
    errors = "Required!";
  } else if (!/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(value)) {
    errors = "Invalid email address!";
  }

  return errors;
};

export const isRequired = value => (!value ? "Required!" : "");

компонентов / RenderBookingForm.js

import React from "react";
import { Form, Field } from "formik";
import { AntDatePicker, AntInput, AntSelect, AntTimePicker } from "./AntFields";
import { dateFormat, timeFormat } from "./FieldFormats";
import { validateDate, validateEmail, isRequired } from "./ValidateFields";

export default ({ handleSubmit, values, submitCount }) => (
  <Form className="form-container" onSubmit={handleSubmit}>
    <Field
      component={AntInput}
      name="email"
      type="email"
      label="Email"
      validate={validateEmail}
      submitCount={submitCount}
      hasFeedback
    />
    <Field
      component={AntDatePicker}
      name="bookingDate"
      label="Booking Date"
      defaultValue={values.bookingDate}
      format={dateFormat}
      validate={validateDate}
      submitCount={submitCount}
      hasFeedback
    />
    <Field
      component={AntTimePicker}
      name="bookingTime"
      label="Booking Time"
      defaultValue={values.bookingTime}
      format={timeFormat}
      hourStep={1}
      minuteStep={5}
      validate={isRequired}
      submitCount={submitCount}
      hasFeedback
    />
    <Field
      component={AntSelect}
      name="bookingClient"
      label="Client"
      defaultValue={values.bookingClient}
      selectOptions={values.selectOptions}
      validate={isRequired}
      submitCount={submitCount}
      tokenSeparators={[","]}
      style={{ width: 200 }}
      hasFeedback
    />
    <div className="submit-container">
      <button className="ant-btn ant-btn-primary" type="submit">
        Submit
      </button>
    </div>
  </Form>
);

компонентов / BookingForm.js

import React, { PureComponent } from "react";
import { Formik } from "formik";
import RenderBookingForm from "./RenderBookingForm";
import { dateFormat, timeFormat } from "./FieldFormats";
import moment from "moment";

const initialValues = {
  bookingClient: "",
  bookingDate: moment(Date.now()),
  bookingTime: moment(Date.now()),
  selectOptions: ["Mark", "Bob", "Anthony"]
};

const handleSubmit = formProps => {
  const { bookingClient, bookingDate, bookingTime, email } = formProps;
  const selectedDate = moment(bookingDate).format(dateFormat);
  const selectedTime = moment(bookingTime).format(timeFormat);
  alert(
    `Email: ${email} \nSelected Date: ${selectedDate} \nSelected Time: ${selectedTime}\nSelected Client: ${bookingClient}`
  );
};

export default () => (
  <Formik
    initialValues={initialValues}
    onSubmit={handleSubmit}
    render={RenderBookingForm}
  />
);
...