dispatch a custom action on redux-form when onchange select - react-redux

Given a custom component:
export const RenderDropDown = (props) => {
const {values, input, label, type, meta: {touched, error, active}} = props;
var options = function (value, index) {
return <Option key={index}
value={value} />
};
return(
<div>
<select {...input}>
<option value="">--- Select a nationality ---</option>
{values.map(options)}
</select>
</div>
)
}
Wrapped in a Redux-form Field component
<Field name="nationality" component={RenderDropDown} values={props.nationalities}/>
I want that when select fires "onChange" event, a custom action is dispatched besides the Redux-form action (AKA ##redux-form/change)
How I can achieve this?
I tried to pass by props the function to call and set an onChange handler on <select> tag but this overrides the redux-form onChange.
Any help appreciated!

You need to call the redux-form onChange manually in your own custom onChange to update the redux-form value. Like so:
const { onChange, ... } = props;
...
<select onChange={(e) => {
const val = e.target.value
// whatever stuff you want to do
onChange(val)
}} />

Related

React formik form onsubmit event callings many times?

import { Formik, Form, Field } from "formik";
import { Button } from "antd";
const AddUser = () => {
const initialValues = {
name: "",
};
return (
<>
<Formik
initialValues={initialValues}
onSubmit=(values) => {
alert("hi");//calling mamy times
Here added api call (post method)
}}
>
{({ isValid, submitForm, isSubmitting, values }) => {
return (
<Form>
<Field
name="name"
label="Name"
placeholder="Dataset Name"
/>
<Button
type="primar"
htmltype="submit"
loading=(props.addingdata) // this is my reducer state intial was false after post call request became true and success state value false
>
Add Dataset
</Button>
</Form>
);
}}
</Formik>
</div>
</>
);
};
export default AddUser;
I have simple formik form antd button I have used when click submit button post api calling twice and thrice even If I added loading property in button why its happening like this?

Sync validation to throw form level error (rather then field level)

In sync validation per - https://redux-form.com/7.1.2/examples/syncvalidation/ - I was trying to throw a form level error. Just like when we do throw new SubmissionError({ _error:'form level error from on submit' }), however I am not able to figure it out. I tried using the special _error key and even just error key like so:
reduxForm({
validate: values => ({ error:'form level??', _error:'form level alt??' })
})
However it is not setting FormProps error value. Does anyone know if this is supported or how to achieve this?
To pass form-level error to form after validation you should add _error property to object returned by redux-form config validate function.
The error will be passed as error prop to your form component.
For example:
import React from 'react';
import { Field, reduxForm } from 'redux-form';
const ExampleForm = (props) => {
const { handleSubmit, pristine, submitting, error } = props;
return (
<form onSubmit={handleSubmit}>
<div>
<label>Name</label>
<div>
<Field
name="name"
component="input"
type="text"
placeholder="Name"
/>
</div>
</div>
<div>Error: {error}</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
</div>
</form>
);
};
const validate = (values) => ({
_error: `form level error for firstName = '${values.name || ''}'!`,
});
export default reduxForm({
form: 'exampleForm',
validate,
})(ExampleForm);

Form-level validation does not behave as expected

Using redux-form 7.0.3, I'm unable to get the Field validate API to do anything.
First, I created a basic, minimal example templated off of the docs.
import React from 'react'
import { Field, reduxForm } from 'redux-form'
// removed validation fns
const required = value => {
console.log('Test of validation fn')
return (value ? undefined : 'Required')
}
// unchanged
const renderField = ({
input,
label,
type,
meta: { touched, error, warning }
}) =>
<div>
<label>
{label}
</label>
<div>
<input {...input} placeholder={label} type={type} />
{touched &&
((error &&
<span>
{error}
</span>) ||
(warning &&
<span>
{warning}
</span>))}
</div>
</div>
// removed fields & made into React Component
class FieldLevelValidations extends Component {
render(){
const { handleSubmit } = this.props
return (
<form onSubmit={handleSubmit}>
<Field
name="test"
type="text"
component={renderField}
label="Test Component"
validate={required}
/>
<div>
<button type="submit">
Submit
</button>
</div>
</form>
)
}
}
export default reduxForm({
form: 'fieldLevelValidation'
})(FieldLevelValidations)
From this I would assume that the forms reducer processes an action that sets a prop that can be accessed in renderField, but it does not. Both error and warning are undefined, and required is never called. Additionally, there is no isValid or the like property set in the store. I don't know if this is a bug or if I'm missing some critical piece, but I would expect more to be happening here. Also, some greater detail in the docs would be nice.

redux-form and react-select with options appearing as user types

I have a redux-form with a react-select. The expected behaviour is that, as I type in the select field, I call the redux action (by using OnInputChange). But I don't know how to call the action. The line that calls the action is commented in the snippet below, because it fails (this.props.getArtistSearch(value)). Any ideas of how to properly call the action as user types in?
class FormApplication extends React.Component {
submit(values) {
this.props.submitForm(values)
}
getArtist(value){
//this.props.getArtistSearch(value) --> props is undefined
console.log(value)
}
render() {
const { handleSubmit } = this.props
return (
<form className='content text padding-top-0' onSubmit={handleSubmit(this.submit.bind(this))}>
<div className='row adjust-form-row'>
<div className='col-md-6 last-lineup'>
<div className='row adjust-form-row'>
<div className='col-md-6'>
<div className='form-group'>
<Field
name='dl_artistname'
options={this.props.gap.artistSearch}
component={props => (
<Select
{...props}
name={props.name}
onInputChange={this.getArtist}
onChange={(value) => {
this.props.requestArtistInstance({id: value.dl_artistid })
return props.input.onChange(value != null ? value.dl_artistid : null)}
}
onBlur={() => props.input.onBlur(props.input.value)}
options={props.options}
//loadOptions={getOptions}
clearable={false}
cache={false}
backspaceRemoves={false}
valueKey='dl_artistid'
labelKey='dl_name'
value={props.input.value || ''}
isLoading={false}
disabled={false}
/>
)}
/>
</div>
</div>
</div>
</div>
</div>
</form>
)
}
}
const mapDispatchToProps = dispatch => ({
getArtistSearch: (text) => {
dispatch(getArtistSearch(text))
},
submitForm: (values) => {
dispatch(submitForm(values))
}
})
Going through your code, I noticed that the custom method you defined, getArtist was not bound to your React context so props will be undefined. Two possible approaches for this are:
1) bind it in the constructor method
constructor(){
super();
this.getArtist = this.getArtist.bind(this);
}
2) Alternatively, bind it in the Select component(Not ideal tho')
onInputChange={this.getArtist.bind(this)}

How to hijack submit to add values?

I have a form that can have different state based on which button was used for submission; one does a simple submit while the other one adds a flag then submit.
I found a working solution that is, imo, quite ugly, so I'd like to know how else to do it ?
class MyForm extends Component {
// Hijack submit to add published flag
handlePublish = (e) => {
e.preventDefault();
const { handleSubmit, onSubmit } = this.props;
handleSubmit((values) => {
onSubmit({
...values,
isPublished: true,
});
})();
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field
name="foo"
component="input"
/>
<button
type="submit"
onClick={this.handlePublish}
>
Publish
</button>
<button type="submit">
Save
</button>
</form>
);
}
}
✅ This is the idiomatic way. Alternatively, you could provide any number of values as initialValues that don't actually have a Field on the form, but will be submitted.

Resources