Redux表单选择表单值

时间:2017-10-13 19:19:07

标签: forms reactjs redux redux-form

我需要验证月份和年份的生日。如果feb比生日不会大于28。如果月数比生日数不会超过30,如果奇数月,生日不会大于31,而在闰年生日不会超过29。已经为所有可能的条件设置了验证。现在我必须在选择月份时从redux商店获得价值。这是遗留代码和示例显示,从redux表单网站示例中选择值使我对此代码感到困惑。我需要在此代码中从redux存储中获取值,以便我可以将其置于条件中以在给定条件下验证生日。

import React, { PureComponent, PropTypes } from 'react';
import { connect } from 'react-redux';
// import { formValueSelector } from 'redux-form/immutable';
import moment from 'moment';
import { createStructuredSelector } from 'reselect';
import { FaVenus as FemaleIcon, FaMars as MaleIcon } from 'react-icons/lib/fa/';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { Field, reduxForm, actions } from 'redux-form/immutable';
import { TextInput, Select } from 'components/Fields';

import * as rules from 'utils/validationRules';
import * as DateValidator from 'utils/DateValidator';
import { DOB_RAW_FORMAT, PERSON_TYPE_CLIENT, PERSON_TYPE_PARTNER, HOUSEHOLD_SINGLE, birthMonth } from 'containers/constants';
import { selectDobOfClientAndPartner, selectPostalCodeLookup } from '../selectors';
import { doValidatePostalCode, clearPostalCodeLookup } from '../actions';

// const FORM_NAME = 'advisor-feeForm';

// const selector = formValueSelector(FORM_NAME);

export const SexOptions = [
  { value: 'female', label: 'Female', icon: <FemaleIcon /> },
  { value: 'male', label: 'Male', icon: <MaleIcon /> },
];

let dobValues = null;
let personType = '';
const AGE_OFFSET = 30;
let showPostalCodeInfo = false;
const CLIENT_FORM = 'clientForm';

const dobDiffValidator = (dobVals, householdType, dob) => {
  let diffDob = null;
  if (dobVals && dobVals.householdType !== HOUSEHOLD_SINGLE && (dobVals.partner || dobVals.client)) {
    if (householdType === PERSON_TYPE_CLIENT) {
      diffDob = dobVals.partner || dob;
    } else if (householdType === PERSON_TYPE_PARTNER) {
      diffDob = dobVals.client || dob;
    }
    return DateValidator.validateDobDiff(diffDob, dob, 'years', AGE_OFFSET, householdType);
  }
  return null;
};

const doValidateDob = (formProps) => {
  const date = moment.utc(formProps.toJS().DOB, DOB_RAW_FORMAT, true);
  const errors = {};
  if (dobValues && personType && date) {
    errors.DOB = dobDiffValidator(dobValues, personType, date);
  }
  return errors;
};

const normalizePostalCode = (value) => {
  const postalCode = value.toUpperCase().replace(/\s+/, '');
  showPostalCodeInfo = false;
  if (!postalCode || postalCode.length !== 6) return value;

  return postalCode.substring(0, 3).concat(' ', postalCode.substring(3));
};

const OptionStandalone = ({ label, icon, value, onSelect, namePrefix, disabled }) => {
  const cn = disabled ? 'client-form__button--disabled client-form__button' : 'client-form__button';
  return (
    <button id={`${value}button`} onClick={() => onSelect(value)} type="button" className={cn}>
      {label}
    </button>
  );
};

class MaleOrFemale extends PureComponent {
  onChangeCombined = (val) => {
    const { input } = this.props;
    input.onChange(val);
  };

  render() {
    return (
      <span>
        <OptionStandalone
          {...SexOptions[1]}
          onSelect={this.onChangeCombined}
          disabled={this.props.input.value !== 'male'}
        />
        <OptionStandalone
          {...SexOptions[0]}
          onSelect={this.onChangeCombined}
          disabled={this.props.input.value !== 'female'}
        />
      </span>
    );
  }
}

const SexSelector = ({ onChange, active, namePrefix, captions }) => {
  const selector = (
    <Field
      name={`${namePrefix}sex`}
      component={MaleOrFemale}
      directOnChange={onChange}
      active={active}
      className="2"
      validate={[rules.required]}
    />
  );

  return (
    <div className="client-form__input">
      <div className="client-form__input-label" id="labelSex">
        <FormattedMessage {...captions.sexLabel} />
      </div>
      {selector}
    </div>
  );
};

**const BirhdayValidator = (validateAllDoB) => {
  if (birthMonth !== '2') {
    validateAllDoB = rules.birthDay;
  } else {
    validateAllDoB = rules.febBirthday;
  }
  return (
    <Field
      name={'birth_day'}
      type="tel" placeholder={'day'}
      component={TextInput}
      validate={[rules.required, validateAllDoB]}
    />
  );
};**

/* eslint react/no-multi-comp: 0 */
class ClientForm extends PureComponent {
  constructor(props) {
    super(props);
    const { initialValues } = props;

    this.state = {
      sex: initialValues.get('sex'),
      fNameFilled: false,
      lNameFilled: false,
    };
  }

  componentDidMount() {
    const formName = this.props.form;
    dobValues = this.props.dobValues;
    personType = formName.substring(0, formName.indexOf('Form'));
  }

  componentWillUnmount() {
    this.props.clearPostalCode();
  }

  handleFirstNameBlur = (e) => {
    const value = e.target.value;
    const isFilled = value.length > 0;
    this.setState({ fNameFilled: isFilled });
  };

  handleLastNameBlur = (e) => {
    const value = e.target.value;
    const isFilled = value.length > 0;
    this.setState({ lNameFilled: isFilled });
  };

  handleSexChange = (value) => {
    this.setState({ sex: value });
  };

  handlePostalCodeOnBlur = (e) => {
    showPostalCodeInfo = false;
    const postalCode = String(e.target.value);
    if (postalCode) {
      const isInvalid = rules.postalCode(postalCode);
      if (!isInvalid) {
        showPostalCodeInfo = true;
        this.props.clearPostalCode();
        this.props.validatePostalCode(postalCode);
      }
    } else {
      // error...
    }
  };

  handleLastNameKeyPress = (e) => {
    if (e.key === 'Enter') {
      this.handleLastNameBlur(e);
    }
  };

  incFieldsCount() {
    if (this.state.fieldsCount + 1 <= this.maxFieldsCount) {
      return { fieldsCount: this.state.fieldsCount + 1 };
    }
    return { fieldsCount: this.state.fieldsCount };
  }

  render() {
    const { captions, intl, namePrefix, postalCodeLookup, form } = this.props;
    const state = this.state;
    return (
      <div className="client-form-container">
        <h2>
          <FormattedMessage {...captions.header} />
        </h2>
        <form className="client-form">
          <div>
            <div className="client-form__input">
              <div className="client-form__input-label" id="labelClientFirstName">
                <FormattedMessage {...captions.nameLabel} />
              </div>
              <div className="client-form__input-field client-form__input-field__first-name">
                <Field
                  name={`${namePrefix}firstName`}
                  type="text"
                  component={TextInput}
                  placeholder={intl.formatMessage(captions.firstNamePlaceholder)}
                  validate={[rules.required]}
                  onBlur={this.handleFirstNameBlur}
                  ariaLabel={intl.formatMessage(captions.firstNamePlaceholder)}
                />
              </div>
              <div className="client-form__input-label" id="labelClientLastName" />
              <div className="client-form__input-field client-form__input-field__last-name">
                <Field
                  name={`${namePrefix}lastName`}
                  type="text"
                  component={TextInput}
                  placeholder={intl.formatMessage(captions.lastNamePlaceholder)}
                  validate={[rules.required]}
                  onBlur={this.handleLastNameBlur}
                  onKeyPress={this.handleLastNameKeyPress}
                  ariaLabel={intl.formatMessage(captions.lastNamePlaceholder)}
                />
              </div>
            </div>
            <SexSelector
              onChange={this.handleSexChange}
              value={state.sex}
              namePrefix={namePrefix}
              captions={captions}
            />
            <div className="client-form__input">
              <div className="client-form__input-label" id="labelDOB">
                <FormattedMessage {...captions.birthdayLabel} values={{ GENDER: state.sex || '' }} />
              </div>

              <div className="client-form__input-field client-form__input-field__birth-month">
                <Field
                  name={`${namePrefix}birth_month`}
                  label="month"
                  component={Select}
                  placeholder="Month"
                  validate={[rules.required]}
                  options={birthMonth}
                />
              </div>
              <div className="client-form__input-label" />
              <div className="client-form__input-field client-form__input-field__birth-day">
                {BirhdayValidator()}
              </div>

              <div className="client-form__input-label" />
              <div className="client-form__input-field client-form__input-field__birth-year">
                <Field
                  name={`${namePrefix}birth_year`}
                  type="tel" placeholder={'year'}
                  component={TextInput}
                  validate={[rules.required, rules.birthYear]}
                />
              </div>
            </div>
            {form === CLIENT_FORM && (
              <div className="client-form__input">
                <div className="client-form__input-label" id="labelPostalCode">
                  <FormattedMessage {...captions.postalCodeLabel} />
                </div>
                <div className="client-form__input-field">
                  <Field
                    name={`${namePrefix}postalCode`}
                    type="text"
                    component={TextInput}
                    placeholder="e.g. M1M 1M1"
                    normalize={normalizePostalCode}
                    validate={[rules.required, rules.postalCode]}
                    onBlur={this.handlePostalCodeOnBlur}
                    width="7em"
                  />
                </div>
              </div>
            )}
          </div>
          {postalCodeLookup.isPostalCodeFound === false &&
          showPostalCodeInfo &&
          form === CLIENT_FORM && (
            <div>
              <div className="client-form__warning-label" name="label_postalCodeInfo">
                <FormattedMessage {...captions.postalCodeAllCanada} />
              </div>
            </div>
          )}
        </form>
      </div>
    );
  }
}


ClientForm.propTypes = {
  initialValues: PropTypes.object,
  captions: PropTypes.object.isRequired,
  intl: intlShape,
  namePrefix: PropTypes.string,
  form: PropTypes.string,
  dobValues: PropTypes.object,
  clearPostalCode: PropTypes.func.isRequired,
  validatePostalCode: PropTypes.func.isRequired,
  postalCodeLookup: PropTypes.object,
};

ClientForm.defaultProps = {
  namePrefix: '',
};
const mapStateToProps = createStructuredSelector({
  dobValues: selectDobOfClientAndPartner(),
  postalCodeLookup: selectPostalCodeLookup(),
});

function mapDispatchToProps(dispatch) {
  return {
    updateErrors: (formName, field, err, touched) => {
      if (touched) {
        dispatch(actions.blur(formName, field, '', touched));
      }
      return dispatch(actions.updateSyncErrors(formName, { [field]: err }));
    },
    validatePostalCode: (postalCode) => dispatch(doValidatePostalCode(postalCode)),
    clearPostalCode: () => dispatch(clearPostalCodeLookup()),
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(
  reduxForm({ validate: doValidateDob })(injectIntl(ClientForm))
);

1 个答案:

答案 0 :(得分:0)

要验证某些字段,这取决于其他字段,您可以使用验证功能中传递的allValues参数。

因此,您可以为该字段编写特定规则:

const validateDoB = (value, allValues) => {
  // For example allValues.birth_year is accessible here
}

然后编写Field组件:

<Field
  name={'birth_day'}
  type="tel" placeholder={'day'}
  component={TextInput}
  validate={[rules.required, validateDoB]}
/>