DEV Community

Cover image for More control over controlled forms
aryaziai
aryaziai

Posted on

More control over controlled forms

I'm currently working on a React app that's intended for a customizable news experience. The user will create a new topic and fill out the appropriate input fields. The input values are saved to state, and this data is interpolated into different fetch requests to the respective API's. Here is a rough draft of what the Create New Topic form will look like.

Each topic will serve a similar purpose to twitter hashtags. It's important that the "spacebar" and number keys are prevented in these different input fields. The first step is to see whether I can prevent these key inputs via the html input attributes. I found the following input attributes available on W3Schools:

autocomplete         height and width            formnovalidate       step 
autofocus            list                        formtarget
form                 formaction                  multiple
formenctype          formmethod                  min and max
pattern (regexp)     placeholder                 required

Although the min and max attributes will come in handy, I need to create a function that takes care of this for me. The pattern (regex) attribute could potentially help me achieve my goal, however, writing a function sounds a lot more fun. Here is a code snippet for the "#TopicName" field on my Create New Topic form:

       handleChange = (e) => {
       this.setState ({
        [e.target.name]: e.target.value
       })
      }


<Form onSubmit={(e) => {this.props.handleSubmitTopic(e, this.state) }}>
<Form.Control type='text' name="topic_title" placeholder="TopicName"

onChange={(e) => this.handleChange(e)} value={this.state.topic_title}/> /* synthetic event */

</Form>

As you can see, I'm using the "onChange" synthetic event to maintain a controlled form. My first attempt was adding a conditional statement to handleChange(e), the conditional statement would prevent typing if e.target.value === " " .

      handleChange = (e) => {
        if (e.target.value === " ") {
          console.log("space was typed")
          e.preventDefault()
        }
        else {
         this.setState ({
         [e.target.name]: e.target.value
       })
      }} 

The results were a little surprising. I was able to prevent the spacebar only if it's the first key pressed. In the gif below, you can see me successfully hitting the "if" statement, however, once I start typing letters and THEN press the spacebar, the "if" statement is no longer being accessed.

After some research, I learned that the onKeyDown synthetic event can help me achieve my goal. I created a new function called avoidSpace(e) and calling it via onKeyDown

avoidSpace = (e) => {
 if (e.key === " " {
  console.log("spacebar:", e.key)
  e.preventDefault();
 }
}

<Form onSubmit={(e) => {this.props.handleSubmitTopic(e, this.state) }}>
<Form.Control type='text' name="topic_title" placeholder="TopicName" 

onKeyPress={(e) => this.avoidSpace(e)} onChange={(e) => this.handleChange(e)} 
value={this.state.topic_title}/>  /* two synthetic events */

</Form>

I was successful in preventing the spacebar from being clicked:

Now that I know that the keyDown event works, I just need to modify the if statement to include numbers as well:

if (e.key === " " || e.key >= 0 || e.key < 10 ) {
  e.preventDefault()
}

The End

Top comments (0)