1

I'm using Redux Form v.7.1.2 and am currently submitting the form when the user clicks the submit button. Inside of the function it is assigned to run, I perform an action. I only want that action to be performed if at least one value has been changed since the last submit. How can I do that?

Here is my code currently:

import { Field, reduxForm } from 'redux-form';

class SearchFilters extends Component {
  constructor(props) {
    super(props);
    this.onSubmit = this.onSubmit.bind(this);
  }

  onSubmit(values) {
    // Only perform this action if at least one value was changed since the last submit
    this.props.doSomething(values);
  }

  renderField(field) {
    return (
      <div className="search-parameter">
        <input type="text" {...field.input} />
      </div>
    );
  }

  render() {
    const { handleSubmit, pristine, submitting, invalid } = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit)} >
        <Field
          component={this.renderField}
          key="keyword"
          name="keyword"
        />
        <Field
          component={this.renderField}
          key="type"
          name="type"
        />
      </form>
    );
  }
}

export default reduxForm({
  validate,
  form: 'SearchFiltersForm',
})(connect(mapStateToProps, null)(SearchFilters));
zeckdude
  • 15,877
  • 43
  • 139
  • 187

4 Answers4

4
import { isDirty } from 'redux-form'

const mapStateToProps = state => ({
  ...
  isDirty: isDirty('myForm')(state),
})

and then inside render method you will have access to

this.props.isDirty

Kuzenko Lubko
  • 1,961
  • 1
  • 20
  • 26
2

I think storing the previously submitted values in the state could solve the issue:

import { Field, reduxForm } from 'redux-form';

class SearchFilters extends Component {
  constructor(props) {
    super(props);
    this.state = {
      values: ''
    };
    this.onSubmit = this.onSubmit.bind(this);
  }

  onSubmit(values) {
    // check if states are same, if not, setState and doSomething
    const valueString = JSON.stringify(values);
    if ( this.state.values !== valueString ) {
      this.setState({ values: valueString });
      this.props.doSomething(values);
    }
  }

  renderField(field) {
    return (
      <div className="search-parameter">
        <input type="text" {...field.input} />
      </div>
    );
  }

  render() {
    const { handleSubmit, pristine, submitting, invalid } = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit)} >
        <Field
          component={this.renderField}
          key="keyword"
          name="keyword"
        />
        <Field
          component={this.renderField}
          key="type"
          name="type"
        />
      </form>
    );
  }
}

export default reduxForm({
  validate,
  form: 'SearchFiltersForm',
})(connect(mapStateToProps, null)(SearchFilters));
Dane
  • 9,242
  • 5
  • 33
  • 56
  • Yup! Works perfectly! Thanks! – zeckdude Nov 02 '17 at 14:32
  • I tried your approach but instead of stringifying the `values` object and saving that string on the state, I am simply saving the entire `values` object to the state. Then when I compare the current values with the last submitted values, I just compare the two objects. Do you see any problem with that? Why did you choose to stringify the object? – zeckdude Nov 02 '17 at 14:55
  • comparing objects ? hmm... I dont think that will work.. see https://stackoverflow.com/questions/201183/how-to-determine-equality-for-two-javascript-objects and https://stackoverflow.com/questions/1068834/object-comparison-in-javascript – Dane Nov 03 '17 at 03:22
  • Is that why you're using stringify? Or why did you decide to stringify the object? – zeckdude Nov 03 '17 at 03:23
  • that's one method.. or using [Lodash `isEqual()`](https://lodash.com/docs/4.17.4#isEqual) – Dane Nov 03 '17 at 03:25
1

Also, you could update your initialValues with the submitted values, and that way pristine/dirty will let you know.

Erik R.
  • 7,152
  • 1
  • 29
  • 39
  • Hey, thanks for such an awesome component library! And great documentation! Your suggestion sounds appealing but I’m not sure how to implement that. Can you please provide a code sample? – zeckdude Nov 03 '17 at 12:25
1

Thanks to Erik R's suggestion, I managed to figure out how to update the initialValues whenever the form is submitted. Then redux-form can compare the current values to the last set initialValues to determine if the form is pristine/dirty.

import { Field, reduxForm } from 'redux-form';

class SearchFilters extends Component {
  constructor(props) {
    super(props);
    this.onSubmit = this.onSubmit.bind(this);
  }

  onSubmit(values) {
    // Check if the form values have changed since the last submit
    // The dirty boolean (signifies if the form has changed from its initial values) is established by redux-form by comparing the currently entered values to the initial form values
    // After we identify the form as having been changed, we will send the new form values to replace the original initial form values so redux-form is always comparing the current form values against the last submitted form values
    if (this.props.dirty) {
      // Set the initial values for the form on the redux store (This is used by redux form to compare the current values to the initial values so we can determine if there are new values since the last submit)
      this.props.initialize(values);
    }
  }

  renderField(field) {
    return (
      <div className="search-parameter">
        <input type="text" {...field.input} />
      </div>
    );
  }

  render() {
    const { handleSubmit, submitting, invalid } = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit)} >
        <Field
          component={this.renderField}
          key="keyword"
          name="keyword"
        />
        <Field
          component={this.renderField}
          key="type"
          name="type"
        />
        <button
          type="submit"
          disabled={submitting || pristine || invalid}
        >
          Search
        </button>
      </form>
    );
  }
}

export default reduxForm({
  validate,
  form: 'SearchFiltersForm',
})(connect(mapStateToProps, null)(SearchFilters));
zeckdude
  • 15,877
  • 43
  • 139
  • 187