Author avatar

Raphael Alampay

Binding Functions and Enable/Disable State in HTML Buttons with React.js

Raphael Alampay

  • Sep 21, 2020
  • 7 Min read
  • 120 Views
  • Sep 21, 2020
  • 7 Min read
  • 120 Views
Web Development
Front End Web Development
Client-side Frameworks
React

Introduction

React.js's state management approach allows systematic implementation of a wide variety of user experiences. One such user experience technique is telling the user that something is happening or is loading in the background when a button is clicked. To achieve this, we'd like to have a boolean state value that governs the visibility of user interface components. That is, if the state value is true then the components are disabled. Otherwise, the components are disabled. That same value can also be used to determine if a section of the app will display a loading message or any visual component for that matter.

Defining the State Value

Supposed you're creating a SearchComponent that contains two major input elements:

  • A text input where users can type in a search query
  • A submit button that is a call to action to start searching

You'll then control the disabled attribute of these two elements with an isDisabled boolean state.

Establishing State

In your component's constructor, go ahead and define the isDisabled state with an initial value of false. This tells the user that they are free to input stuff in the text input and click the submit button.

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';

export default class SearchComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      isDisabled: false
    }
  }
}
javascript

Binding State to UI

Create your component's render() method that returns the form itself with the two UI elements. Copy the following function and paste it within the SearchComponent. In practice, it's usually found as the last method of a React.js component.

1
2
3
4
5
6
7
8
9
10
render() {
  return (
    <div>
      <input type="text" disabled={this.state.isDisabled} />
      <button disabled={this.state.isDisabled}>
        Submit Query
      </button>
    </div>
  );
}
javascript

Embed the value of this.state.isDisabled as a value of the disabled attribute via JSX as wrapped by {}. Since its initial value is false, users can then proceed to input text in it.

1
<input type="text" disabled={this.state.isDisabled} />
jsx

The same goes for the button for submitting a query.

1
2
3
<button disabled={this.state.isDisabled}>
  Submit Query
</button>
jsx

Disabling the Interface

The next thing you have to do is to bind a function that will update the state value of a component by calling this.setState(), where this is a reference to the instance of the React.js component. Remember that in React.js, a call to this.setState() will force a re-render of the component with the newly updated values. The function will look like the following:

1
2
3
4
5
handleSubmitClicked() {
  this.setState({
    isDisabled: true
  });
}
javascript

Binding to an Event

Given your event handler, you'll bind the function to your button's onClick attribute:

1
2
3
4
5
6
<button 
  disabled={this.state.isDisabled}
  onClick={this.handleSubmitClicked.bind(this)}
>
  Submit Query
</button>
jsx

Invoke the .bind(this) function in order to retain the value for this, which is a reference to the instance of the component. This way (pun not intended), the this inside the logic of handleSubmitClicked() will always retain the value of the component's instance, thus allowing the setState() to be called from it.

Cascading Effect

Since handlSubmitClicked() updates the state of isDisabled to true, it will force a call to the render() method of the component, causing the input elements' disabled attribute to have a value of true. As a result, this will create an effect that tells the user that something is happening after the button was clicked.

Re-enabling the Interface

Once the process is finished, you can tell the user that they're free to input or modify the current text field. Do this by creating another event handler function that does the opposite—that is, it enables the UI components:

1
2
3
4
5
enableComponents() {
  this.setState({
    isDisabled: false
  });
}
javascript

Simulating a Process

To simulate that "something is happening," add code in the handleSubmitClicked() that waits three seconds before firing a function which in turn will call enableComponents().

1
2
3
4
5
6
7
8
9
10
11
12
handleSubmitClicked() {
  this.setState({
    isDisabled: true
  });

  setTimeout(
    function() {
      this.enableComponents()
    }.bind(this),
    3000
  );
}
javascript

Notice that you'll call .bind(this) once again against the function that is the first argument to setTimeout(). This will allow this to retain its value as the reference to the instance of this component, allowing a call to be made to enableComponents(). Normally, this timeout code will be replaced by actual processing of the user input, which will eventually call enableComponents() once done.

Overall Code

Your final component form will look like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import React from 'react';

export default class SearchComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      isDisabled: false
    }
  }

  handleSubmitClicked() {
    this.setState({
      isDisabled: true
    });

    setTimeout(
      function() {
        this.enableComponents()
      }.bind(this),
      3000
    );
  }

  enableComponents() {
    this.setState({
      isDisabled: false
    });
  }

  render() {
    return (
      <div>
        <input type="text" disabled={this.state.isDisabled} />
        <button 
          disabled={this.state.isDisabled}
          onClick={this.handleSubmitClicked.bind(this)}
        >
          Submit Query
        </button>
      </div>
    );
  }
}
javascript

Try this component out and notice that upon clicking Submit Query, both the input and button elements will disable, and after three seconds will be enabled again.

Conclusion

This guide demonstrated a simple way to communicate to a user that something is happening after clicking a button by maintaining a boolean state variable that serves as a value for the visibility of the UI. Try to see if you can incorporate this technique to your own stateful React component by having a single state variable govern the accessibility of your interface. Some suggestions are:

  1. Using the state variable to make a loading text or visualization appear if the value is true. Otherwise, hide the text or visualization.
  2. Invoking enableComponents() after a successful AJAX call within handleSubmitClicked()

0