Samira Arabgol
Samira Arabgol

Reputation: 389

How to disable a button when the state or the input value gets changed in React JS?

I have a form which has a large number of inputs and update button. I am looking for the best way to disable the button unless one of the states or inputs get changed. I know about the way that having Boolean state variable to hold the button's disable/enable state. Then on change of the input field set value to the state variable name accordingly.

since i have a large number of states. I need to write a code which loop trough the nested object and compare.

I would appreciate your help

Upvotes: 1

Views: 3022

Answers (2)

rghossi
rghossi

Reputation: 598

I don't see why the boolean approach would be bad.

Anyways, you could compare your previous model object with your current state using lodash _.isEqual function to check whether data has changed or not.

UPDATE (snippet):

class App extends React.Component {
  state = {
    foo: '',
    bar: ''
  }
  
  componentDidMount() {
    const { foo, bar } = this.props;
    this.setState({ foo, bar });
  }
  
  hasChangedSinceInitialState = () => {
    const { foo, bar } = this.props;
        
    // here you could use lodash ._isEqual if you have an bigger object
    return (foo === this.state.foo && bar === this.state.bar);
  }
  
  handleInputChange = (event) => {
    this.setState({ [event.target.name]: event.target.value });
  }
  
  render() {
    return (<div>
      <div>Foo: <input type='text' name='foo' value={this.state.foo} onChange={this.handleInputChange} /></div>
      <div>Bar: <input type='text' name='bar' value={this.state.bar} onChange={this.handleInputChange} /></div>
      <button disabled={this.hasChangedSinceInitialState()}>Submit</button>
    </div>);
  }
}

ReactDOM.render(<App foo='oldFoo' bar='oldBar' />, document.getElementById('root'));
<script src="https://cdn.jsdelivr.net/npm/[email protected]/isEqual.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

Upvotes: 1

Dacre Denny
Dacre Denny

Reputation: 30390

If I understand your situation and code correctly, then you are only interested in validating on certian variables in your component state.

You could achieve the desired validation behaviour by adding the following method to your component:

getCustomValidation() {

  // Extract a list for validation on only the state fields that are 
  // relevance to the form validation
  const fieldsToValidate = [
    "ppvLimit",
    "securityCode",
    "primaryPhone",
    "secondaryPhone",
    "email",
    "billingAddressLine1",
    "billingAddressLine2",
    "billingAddressCity",
    "billingAddressTerritoryCode",
    "billingAddressPostalCode",
    "contactAddressLine1",
    "contactAddressLine2",
    "contactAddressCity",
    "contactAddressTerritoryCode",
    "contactAddressPostalCode",
    "authorizedUser1",
    "authorizedUser2",
    "authorizedUser3",
    "authorizedUser4"
  ];

  // Iterate each field to check to determine if field is valid
  for(const fieldToValidate of fieldsToValidate) {

    // Extract value for current field
    const value = this.state[ fieldToValidate ]

    // If value is "truthy" then return valid (true)
    if( !!value ) {
      return true
    }
  }

  // If none of the validation fields are valid, return false
  return false;
}

To make use of this, you could update the Submit component in your render method as follows:

<Button primary disabled={ !this.getCustomValidation() } type="submit">
{ loading ? <div><LoadingIcon size="lg" /> Saving...</div> : "Update" }
</Button>

Upvotes: 0

Related Questions