-
-
Save mairh/233f6b4ffdbaaed8ec75bb0bef087e8f to your computer and use it in GitHub Desktop.
// 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} /> | |
); | |
} | |
} |
@TrebuhD you need to hook up the onSubmit
method in a function call. For e.g in my case, I am passing calling a graphql
mutation hooked up to the onSubmit
method
class MyComponent extends React.Component {
onSubmit = values => {
const { someMethod } = this.props;
someMethod(values.selectExample, values.textInputExample, values.numberInputExample, values.emailInputExample);
}
render() {
return (
<div>
<MyForm onSubmit={this.onSubmit} />
</div>
);
}
}
export default compose(
graphql(MUTATION_NAME, {
props: ({ ownProps: { history }, mutate }) => ({
someMethod: async (selectExample, textInputExample, numberInputExample, emailInputExample) => {
await mutate({
variables: { input: { selectExample, textInputExample, numberInputExample, emailInputExample } },
optimisticResponse: {
someMethod: {
id: -1,
selectExample: selectExample,
textInputExample: textInputExample,
numberInputExample: numberInputExample,
emailInputExample: emailInputExample,
__typename: 'MyType',
},
}
});
return history.push('/');
}
})
})
)(MyComponent);
Thanks a lot! That was a big help.
@mairh I'm new to react can you add a working example, please
@mairh Thank you for your examples!
in semantic-ui-form.js, I keep getting meta error and warning undefined.. do you have any idea why?
Thanks.
Hello @mairh
Did you see that semanticFormField return <Form.Field>
and in your exemple you are using as={Form.Select}
which is a sugar for <Form.Field><Select /></Form.Field>
, so it renders a Form.Field inside a Form.Field ? Maybe i'm misunderstanding something.
Also, how to you make your semanticFormField works with checkboxes and radios ? I'm having a hard time trying to make it works
Thank you a lot for this gist !
Thank you! This helped me a lot.
This is very helpfull tanks for that
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.
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!
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 getvalue={['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
Is the return value here supposed to be an array or an Object?
It's partly working - it's dispatching actions correctly, but nothing is being saved in the store and the input box remains empty as I type.