368

I am new to Bootstrap and stuck with this problem. I have an input field and as soon as I enter just one digit, the function from onChange is called, but I want it to be called when I push 'Enter when the whole number has been entered. The same problem for the validation function - it calls too soon.

var inputProcent = React.CreateElement(bootstrap.Input, {type: "text",
  //bsStyle: this.validationInputFactor(),
  placeholder: this.initialFactor,
  className: "input-block-level",
  onChange: this.handleInput,
  block: true,
  addonBefore: '%',
  ref:'input',
  hasFeedback: true
});
Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
Bill Lumbert
  • 4,633
  • 3
  • 20
  • 30

12 Answers12

674

According to React Doc, you could listen to keyboard events, like onKeyPress or onKeyUp, not onChange.

var Input = React.createClass({
  render: function () {
    return <input type="text" onKeyDown={this._handleKeyDown} />;
  },
  _handleKeyDown: function(e) {
    if (e.key === 'Enter') {
      console.log('do validate');
    }
  }
});

Update: Use React.Component

Here is the code using React.Component which does the same thing

class Input extends React.Component {
  _handleKeyDown = (e) => {
    if (e.key === 'Enter') {
      console.log('do validate');
    }
  }

  render() {
    return <input type="text" onKeyDown={this._handleKeyDown} />
  }
}

Here is the jsfiddle.

Update 2: Use a functional component

const Input = () => {
  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      console.log('do validate')
    }
  }

  return <input type="text" onKeyDown={handleKeyDown} />
}
Bombe
  • 81,643
  • 20
  • 123
  • 127
wuct
  • 10,057
  • 2
  • 19
  • 22
  • 2
    And you would also like to bind the validation process to `onBlur` event. – wuct Jul 07 '15 at 15:48
  • +1 The great thing about this method is that the backspace key doesn't fire an event. Great for auto-complete. – backdesk Dec 17 '15 at 16:20
  • 9
    Same solution in a more compact way with reference to the input text: ` {(e.key === 'Enter' ? doSomething(this.refs.reference.value) : null)}} />` – musemind Jul 30 '16 at 16:31
  • 5
    @musemind Actually, you don't need to use `ref`. ` doSomething(e.target.value)}` is sufficient. – wuct Aug 02 '16 at 03:50
  • 9
    @musemind The point to use a class method instead of an inline function is to avoid creating a new function every time when `onKeyPress` is triggered. It is a subtle perf improvement. – wuct Aug 02 '16 at 03:52
  • 1
    attached fiddle is not working anymore, please check, anyways nice answer – Pardeep Jain Jul 04 '17 at 13:12
  • @wuct you said that according to the react docs one shouldn't listen to the onChange event. Where is this stated in the docs? couldn't find it... All of their examples with controlled components use the onChange event. – c-chavez Aug 31 '18 at 14:53
  • 1
    @PardeepJain Thanks for noticing. I've updated the link. – wuct Sep 05 '18 at 02:56
  • @c-chavez You are right. I should use "could" in that sentence. Updated! – wuct Sep 05 '18 at 03:11
  • @wuct - the function does not "get created" each time onKeyPressed is called – memical Apr 22 '20 at 07:23
  • @memical You are right. It should be created each time the component updated. I hope I can edit that comment. – wuct Jun 29 '20 at 11:48
  • 3
    I prefer `onKeyUp` since it only fires when the key is released. `onKeyDown`, on the other hand, will fire multiple times if for some reason the user presses and holds the key. – kawerewagaba Jan 04 '21 at 06:10
99

You can use onKeyPress directly on input field. onChange function changes state value on every input field change and after Enter is pressed it will call a function search().

<input
    type="text"
    placeholder="Search..."
    onChange={event => {this.setState({query: event.target.value})}}
    onKeyPress={event => {
                if (event.key === 'Enter') {
                  this.search()
                }
              }}
/>
Admir
  • 2,876
  • 1
  • 19
  • 19
51

Pressing Enter in a form control (input) normally triggers a submit (onSubmit) event on the form. Considering that you can handle it this way (having a submit button is optional if you have only one input):

const { useState } = React;

function App() {
  const [text, setText] = useState("");
  const [submitted, setSubmitted] = useState('');

  function handleChange(e) {
    setText(e.target.value);
  }

  function handleSubmit(e) {
    e.preventDefault();
    setSubmitted(text);
    setText("");
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" value={text} onChange={handleChange} />
        <input type="submit" value="add" />
      </form>
      submitted: {submitted}
    </div>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>
<div id="root"></div>

Implicit form submission (submit event on Enter) is performed when:

  • there's a submit button
  • there're no submit buttons, but there's only one input

More on it here.

Alternatively you could bind your handler to the blur (onBlur) event on the input which happens when the focus is removed (e.g. tabbing to the next element that can get focus).

x-yuri
  • 16,722
  • 15
  • 114
  • 161
Luca
  • 9,259
  • 5
  • 46
  • 59
  • 4
    This is far more clean than using `onKeyPress`. – Blackus Apr 06 '16 at 13:25
  • 2
    Thought since the target is different, `event.target.value` isn't available – Izkata Nov 08 '16 at 21:42
  • @Izkata what you say is absolutely correct; my answer might require a different way of handling things in the controller `handleInput` method. Doing as per my answer would cover you both when the user presses enter while focused on the input and when activating a `submit` button/input. – Luca Nov 16 '16 at 12:15
  • 4
    In **most** situations in web apps there are no forms, just inputs, so this answer is not relevant to the majority of use-cases, IMHO – vsync Oct 16 '19 at 09:42
  • 1
    @vsync it might not be relevant to the majority, but still valid for a portion - and definitely not incorrect, I don't think it's worth a downvote? – Luca Oct 22 '19 at 15:46
  • 2
    @vsync you should have a form element for accessibility. Just as you should not make everything a div. – Maxim Mazurok Oct 02 '20 at 04:02
  • Note that submitting on a form will refresh the entire page, as a default behavior of form itself. Don't forget to include `event.preventDefault()` on the onSubmit event to prevent the default behavior of reloading the page. – Devwulf Nov 28 '20 at 16:23
13

You can use event.key

function Input({onKeyPress}) {
  return (
    <div>
      <h2>Input</h2>
      <input type="text" onKeyPress={onKeyPress}/>
    </div>
  )
}

class Form extends React.Component {
  state = {value:""}

  handleKeyPress = (e) => {
    if (e.key === 'Enter') {
      this.setState({value:e.target.value})
    }
  }

  render() {
    return (
      <section>
        <Input onKeyPress={this.handleKeyPress}/>
        <br/>
        <output>{this.state.value}</output>
      </section>
    );
  }
}

ReactDOM.render(
  <Form />,
  document.getElementById("react")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
vsync
  • 118,978
  • 58
  • 307
  • 400
onmyway133
  • 45,645
  • 31
  • 257
  • 263
10

I prefer onKeyUp since it only fires when the key is released. onKeyDown, on the other hand, will fire multiple times if for some reason the user presses and holds the key. For example, when listening for "pressing" the Enter key to make a network request, you don't want that to fire multiple times since it can be expensive.

// handler could be passed as a prop
<input type="text" onKeyUp={handleKeyPress} />

handleKeyPress(e) {
  if (e.key === 'Enter') {
    // do whatever
  }
}

Also, stay away from keyCode since it will be deprecated some time.

Robin Daugherty
  • 7,115
  • 4
  • 45
  • 59
kawerewagaba
  • 1,107
  • 2
  • 15
  • 21
9

React users, here's an answer for completeness.

React version 16.4.2

You either want to update for every keystroke, or get the value only at submit. Adding the key events to the component works, but there are alternatives as recommended in the official docs.

Controlled vs Uncontrolled components

Controlled

From the Docs - Forms and Controlled components:

In HTML, form elements such as input, textarea, and select typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().

We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.

If you use a controlled component you will have to keep the state updated for every change to the value. For this to happen, you bind an event handler to the component. In the docs' examples, usually the onChange event.

Example:

1) Bind event handler in constructor (value kept in state)

constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
}

2) Create handler function

handleChange(event) {
    this.setState({value: event.target.value});
}

3) Create form submit function (value is taken from the state)

handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
}

4) Render

<form onSubmit={this.handleSubmit}>
    <label>
      Name:
      <input type="text" value={this.state.value} onChange={this.handleChange} />
    </label>
    <input type="submit" value="Submit" />
</form>

If you use controlled components, your handleChange function will always be fired, in order to update and keep the proper state. The state will always have the updated value, and when the form is submitted, the value will be taken from the state. This might be a con if your form is very long, because you will have to create a function for every component, or write a simple one that handles every component's change of value.

Uncontrolled

From the Docs - Uncontrolled component

In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.

To write an uncontrolled component, instead of writing an event handler for every state update, you can use a ref to get form values from the DOM.

The main difference here is that you don't use the onChange function, but rather the onSubmit of the form to get the values, and validate if neccessary.

Example:

1) Bind event handler and create ref to input in constructor (no value kept in state)

constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
}

2) Create form submit function (value is taken from the DOM component)

handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
}

3) Render

<form onSubmit={this.handleSubmit}>
    <label>
      Name:
      <input type="text" ref={this.input} />
    </label>
    <input type="submit" value="Submit" />
</form>

If you use uncontrolled components, there is no need to bind a handleChange function. When the form is submitted, the value will be taken from the DOM and the neccessary validations can happen at this point. No need to create any handler functions for any of the input components as well.

Your issue

Now, for your issue:

... I want it to be called when I push 'Enter when the whole number has been entered

If you want to achieve this, use an uncontrolled component. Don't create the onChange handlers if it is not necessary. The enter key will submit the form and the handleSubmit function will be fired.

Changes you need to do:

Remove the onChange call in your element

var inputProcent = React.CreateElement(bootstrap.Input, {type: "text",
    //    bsStyle: this.validationInputFactor(),
    placeholder: this.initialFactor,
    className: "input-block-level",
    // onChange: this.handleInput,
    block: true,
    addonBefore: '%',
    ref:'input',
    hasFeedback: true
});

Handle the form submit and validate your input. You need to get the value from your element in the form submit function and then validate. Make sure you create the reference to your element in the constructor.

  handleSubmit(event) {
      // Get value of input field
      let value = this.input.current.value;
      event.preventDefault();
      // Validate 'value' and submit using your own api or something
  }

Example use of an uncontrolled component:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    // bind submit function
    this.handleSubmit = this.handleSubmit.bind(this);
    // create reference to input field
    this.input = React.createRef();
  }

  handleSubmit(event) {
    // Get value of input field
    let value = this.input.current.value;
    console.log('value in input field: ' + value );
    event.preventDefault();
    // Validate 'value' and submit using your own api or something
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

ReactDOM.render(
  <NameForm />,
  document.getElementById('root')
);
c-chavez
  • 7,237
  • 5
  • 35
  • 49
7

You can also write a little wrapper function like this

const onEnter = (event, callback) => event.key === 'Enter' && callback()

Then consume it on your inputs

<input 
    type="text" 
    placeholder="Title of todo" 
    onChange={e => setName(e.target.value)}
    onKeyPress={e => onEnter(e, addItem)}/>
David Alsh
  • 6,747
  • 6
  • 34
  • 60
7

Example of preventing Enter from submitting a form on an input, in my case it was a google maps location autocomplete input

<input
  ref={addressInputRef}
  type="text"
  name="event[location]"
  className="w-full"
  defaultValue={location}
  onChange={(value) => setLocation(value)}
  onKeyDown={(e) => {
    if (e.code === "Enter") {
      e.preventDefault()
    }
  }}
/>
Dorian
  • 7,749
  • 4
  • 38
  • 57
1

This one works better than all others solutions given:

<!-- html -->
<input type="text" onkeydown='handleKeyPress(this)'>

...

// js
function handleKeyPress(e)
{
    if (event.key === 'Enter') 
    {
        // call your method here
    }
}
Alexandre Mazel
  • 2,462
  • 20
  • 26
0

Here is a common use case using class-based components: The parent component provides a callback function, the child component renders the input box, and when the user presses Enter, we pass the user's input to the parent.

class ParentComponent extends React.Component {
  processInput(value) {
    alert('Parent got the input: '+value);
  }

  render() {
    return (
      <div>
        <ChildComponent handleInput={(value) => this.processInput(value)} />
      </div>
    )
  }
}

class ChildComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handleKeyDown = this.handleKeyDown.bind(this);
  }

  handleKeyDown(e) {
    if (e.key === 'Enter') {
      this.props.handleInput(e.target.value);
    }
  }

  render() {
    return (
      <div>
        <input onKeyDown={this.handleKeyDown} />
      </div>
    )
  }      
}
krubo
  • 5,969
  • 4
  • 37
  • 46
0
const [value, setValue] = useState("");

const handleOnChange = (e) => {
    setValue(e.target.value);
};

const handleSubmit = (e) => {
    e.preventDefault();
    addTodoItem(value.trim());
    setValue("");
};

return (
    <form onSubmit={handleSubmit}>
        <input value={value} onChange={handleOnChange}></input>
    </form>
);
señor SR
  • 9
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 01 '22 at 14:16
-1
//You can use onkeyup directly on input field

    const inputField = document.querySelector("input");
        inputField.addEventListener("keyup", e => {
         
            if (e.key == "Enter") {
                 console.log("hello");
            }
        });
Omar Saade
  • 320
  • 2
  • 8