Skip to content

Instantly share code, notes, and snippets.

@mairh
Last active August 12, 2021 23:03
Show Gist options
  • Save mairh/233f6b4ffdbaaed8ec75bb0bef087e8f to your computer and use it in GitHub Desktop.
Save mairh/233f6b4ffdbaaed8ec75bb0bef087e8f to your computer and use it in GitHub Desktop.
Semantic-UI-React form validation using redux-form example
// semantic-ui-form.js
import React from 'react';
import PropTypes from 'prop-types';
import { Form, Input } from 'semantic-ui-react';
export default function semanticFormField ({ input, type, label, placeholder, meta: { touched, error, warning }, as: As = Input, ...props }) {
function handleChange (e, { value }) {
return input.onChange(value);
}
return (
<Form.Field>
<As {...props} {...input} value={input.value} type={type} label={label} placeholder={placeholder} onChange={handleChange} />
{touched && ((error && <span><i>{error}</i></span>) || (warning && <span><i>{warning}</i></span>))}
</Form.Field>
);
}
semanticFormField.propTypes = {
as: PropTypes.any,
input: PropTypes.object,
type: PropTypes.string,
label: PropTypes.string,
placeholder: PropTypes.string,
meta: PropTypes.object
};
// validation.js
export const required = value => (value ? undefined : 'Required');
export const number = value => value && isNaN(Number(value)) ? 'Must be a number' : undefined;
export const email = value => {
value && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)
? 'Invalid email address'
: undefined;
};
// your-component.js
import React from 'react';
import PropTypes from 'prop-types';
import { compose } from 'redux';
import { Field, reduxForm } from 'redux-form';
import { Button, Form } from 'semantic-ui-react';
import semanticFormField from './semanticFormField';
import { required, number, minValue } from './validation';
const options = [
{ key: '0', text: 'Option 1', value: '0' },
{ key: '1', text: 'Option 2', value: '1' }
];
const ComponentForm = (props) => {
return (
<Form name="product" onSubmit={handleSubmit(onSubmit)}>
<Field name="selectExample" component={semanticFormField} as={Form.Select} options={options} label="Select label" placeholder="Select an option" validate={required} />
<Field name="textInputExample" component={semanticFormField} as={Form.Input} type="text" label="Input label" placeholder="Text Input" validate={required} />
<Field name="numberInputExample" component={semanticFormField} as={Form.Input} type="text" label="Number label" placeholder="Number Input" validate={number} />
<Field name="emailInputExample" component={semanticFormField} as={Form.Input} type="email" label="Email label" placeholder="Email Input" validate={[required, email]} />
<Button primary loading={submitting} disabled={pristine || submitting}>Submit</Button>
</Form>
);
};
ComponentForm.propTypes = {
handleSubmit: PropTypes.func,
reset: PropTypes.func,
onSubmit: PropTypes.func,
pristine: PropTypes.bool,
submitting: PropTypes.bool
};
export default compose(
reduxForm({
form: 'yourComponent',
enableReinitialize: true
})
)(ComponentForm);
// Use the above created form component anywhere else in the code base
import ComponentForm from './your-component';
class ComponentWhereFormIsUsed extends React.Component {
// Capturing redux form values from redux form store (pay attention to the name we defined in the previous component)
onSubmit = values => {(
values.selectExample,
values.textInputExample,
values.numberInputExample,
values.emailInputExample
)};
render() {
return (
<ComponentForm onSubmit={this.onSubmit} />
);
}
}
@adriandurran
Copy link

Great example and very helpful.....thank you for this.
Just to make it a bit funkier instead of the <span>......</span> for the errors and warnings I think <Message negative><Message.Header>etc.....</Message.Header></Message> adds that final touch.

@jace45
Copy link

jace45 commented Oct 1, 2019

Hey! Thanks for your example!

I am trying to have a <Field as={Form.Select} multiple selection.../> take in multiple values so that it can have default values appear on mount. The problem I am having is that I can't get value={['this', 'array', 'of_values']} to be in input of the semanticFormField (but name is)

<Field
                  component={semanticFormField}
                  name='fieldNames'
                  as={Form.Select}
                  multiple
                  selection
                  value={selectedFieldNamesInArray} //this is the problem here
                  options={fieldNameOptions}
                  label='Field'
                  width={8}
                  onChange={this.handleFieldNames}
                />

any help would be great!

@jace45
Copy link

jace45 commented Oct 3, 2019

Hey! Thanks for your example!

I am trying to have a <Field as={Form.Select} multiple selection.../> take in multiple values so that it can have default values appear on mount. The problem I am having is that I can't get value={['this', 'array', 'of_values']} to be in input of the semanticFormField (but name is)

<Field
                  component={semanticFormField}
                  name='fieldNames'
                  as={Form.Select}
                  multiple
                  selection
                  value={selectedFieldNamesInArray} //this is the problem here
                  options={fieldNameOptions}
                  label='Field'
                  width={8}
                  onChange={this.handleFieldNames}
                />

any help would be great!

Update:

I figured out the problem, you should add input to the props and any onChange or onBlur methods should be included as well

<Field
  component={semanticFormField}
  name='fieldNames'
  as={Form.Dropdown}
  multiple
  selection
  input={ { value: selectedFieldNamesInArray, onChange: this.handleFieldNames } }
/>

However, if trying to make a certain value appear upon initial mount, it's best to use the initialValues in mapStateToProps from reduxForm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment