Adding onKeyPress to existing <a onClick={}></a> - javascript

I have been attempting to add several onKeyPress to existing onClick tags in my React.js project, more specifically, being able to press Enter to fire off an onClick after tabbing to a link. The onKeyPress in my code works properly when I insert a simple console.log() to test, however it fails when I insert the function. I left out irrelevant portions of code for brevity. Essentially I need click and Enter to do the same thing. Thanks!!!
class Link extends React.Component {
changeSection(e) {
// code to change section
}
render() {
return (
<div>
<a id="menu-item" tabIndex={this.props.tabIndex} onKeyPress={(e) => {(e.key === 'Enter' ? this.changeSection.bind(this) : null)}} onClick={this.changeSection.bind(this)}>
{this.props.linkText}
</a>
</div>
);
}
}

Another option would be to let the browser handle it for you, especially because you're already using an a tag. It might not be nice to add the href="#", but it's probably better than a function that is regenerated every render. Plus you don't have the overhead with the custom tabbing implementation.
Try it here:
class Link extends React.Component {
changeSection(e) {
e.preventDefault();
console.log('Fired!');
}
render() {
return (
<div>
<a
id="menu-item"
href="#"
onClick={this.changeSection.bind(this)}
>
{this.props.linkText}
</a>
</div>
);
}
}
ReactDOM.render(
<Link linkText="Test" />,
document.getElementById('root')
);
<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>

It looks like a syntax error. Does this work? If not, what error are you getting?
<a id="menu-item" tabIndex={this.props.tabIndex} onKeyPress={(e) => (e.key === 'Enter') ? this.changeSection.bind(this) : null} onClick={this.changeSection.bind(this)}>

You mixed 2 syntax together I think.
You can change this;
onKeyPress={(e) => {(e.key === 'Enter' ? this.changeSection.bind(this) : null)}}
With this;
onKeyPress={(e) => {
if(e.key === 'Enter') this.changeSection.bind(this);
else null
}}
or with this;
onKeyPress={(e) => (e.key === 'Enter' ? this.changeSection.bind(this) : null)}

onKeyPress={(e) => {(e.key === 'Enter' ? this.changeSection.bind(this) : null)}}
I think this is where you fail. Your code here just binds new context to a function but doesn't call it.

Related

how to access event as well as value passed to function in react

how do i access event and value passed to function at a time
here is what i have tried
<ul className="list" data-testid="lists">
{options.map((option, i) => (
<li
role="button"
tabIndex="0"
onClick={() => {
setSelected(option);
setOpen(false);
}}
className={state.cursor === i ? "activeList" : "list-item"}
onKeyDown={ handleEnter(option) }
>
{option}
</li>
))}
</ul>
const handleEnter = (option, e) => {
if (e.keyCode === 13) {
setSelected(option)
}
};
what i want to do is when enter pressed want to update the state with value of option
but not able to do so
what should i do
The event object is passed into the onXXX function.
If you want to pass it from the onKeyDown function to the handleEnter function then you must do so explicitly.
You also have to pass a function to onKeyDown in the first place, not undefined which is the return value of the function you are calling.
Use useCallback to stop the function being recreated on every render.
const onKeyDown = useCallback(
(event) => handleEnter(option, event),
[option, handleEnter]
);
and
onKeyDown={ onKeyDown }
Do note, however, that keyCode is deprecated and we have better alternatives for it now.
You can update the property like
onKeyDown={(e)=> handleEnter(option, e)}
it will bind your events in your handleEnter function.
I hope it will work for you. Thanks.

getElementById after conditionally rendering with setState

I have a trigger button that will open a dialog asking if a user would like to enable text to speech. Once the dialog is open, I want to focus on the yes button within the dialog by getting the button element by its ID.
When the trigger is pressed, the following function is called:
private openTTSDialog = () => {
if (this.state.ttsDialog === true) {
this.setState({ ttsDialog: false })
} else {
this.setState({ ttsDialog: true }, () => {
// search document once setState is finished
const yesButton = document.getElementById('tts-dialog-yes-button')
log('yesButton', yesButton)
if (yesButton) {
yesButton.focus()
}
})
}
}
And my dialog is conditionally rendered with a ternary expression like this:
{
this.state.ttsDialog ? (
<div className="tts-dialog-container">
<div className="tts-dialog-text-container">
{session.ttsEnabled ? (
<div>
{
strings.disableTTS
}
</div>
) : (
<div>
{
strings.enableTTS
}
</div>
)}
</div>
<div className="tts-dialog-button-container">
<button
aria-label={strings.yes}
tabIndex={0}
className="tts-dialog-button"
id="tts-dialog-yes-button" // this is the button I want to focus
onClick={this.toggleTTS}
>
{
strings.yes
}
</button>
<button
aria-label={strings.no}
tabIndex={0}
className="tts-dialog-cancelButton"
onClick={this.closeTTSDialog}
>
{
strings.no
}
</button>
</div>
</div>
) : null
}
My log for yesButton is undefined. I thought adding the callback function to setState would fix this because I would be searching the document after setState was finished, but I'm still missing something. Any idea what it is?
In the constructor of your class, you should add a ref to your button:
this.myRef = React.createRef();
Then in your button :
<button
ref={this.myRef}
aria-label={strings.yes}
tabIndex={0}
className="tts-dialog-button"
id="tts-dialog-yes-button" // this is the button I want to focus
onClick={this.toggleTTS}
>
Finally, instead of doing:
const yesButton = document.getElementById('tts-dialog-yes-button')
You should do :
const yesButton = = this.myRef.current;
Actually I would also think this should work since you use a callback on setState, so the new render should have completed and the element should already be mounted and accessible. Anyway I think the idiomatic React way for this would be to use a ref (https://reactjs.org/docs/refs-and-the-dom.html) and put it on the button like <button ref={this.yesButton} ...>...</button> and then call this.yesButton.focus(). Have you tried that already?

HandleKeyPress not recognising down arrow

I'm in the process of building a customised, accessible select input with React.js. I need to have the up and down arrow keys function as the tab key would within the scope of select input's options.
I have a handleKeyPress function on the elements that detects when other keys are pressed (for instance 'Enter' works fine).
Here is an example option:
<li
className="oc-select-field__item"
tabIndex="0"
onClick={handleClick}
onKeyPress={handleKeyPress}
>
...and here is the handleKeyPress function
handleKeyPress = event => {
if (event.key === 40) {
console.log('Down arrow key fired'); // does not fire
}
if (event.key === 'Enter') {
console.log('Enter key fired'); // does fire
}
};
What am I doing wrong that I am not successfully detecting when the down arrow is pressed?
event.which will give you the numeric value of the key.
event.key and event.code will give you a string value.
Try this tool: http://keycode.info
if (event.key === 'ArrowDown') {
console.log('Down arrow key fired');
}
As #devserkan mentioned you should use onKeyDown instead of onKeyPress.
The keydown event is fired when a key is pressed down. Unlike the keypress event, the keydown event is fired for keys that produce a character value and for keys that do not produce a character value.
For Arrow keys, I think you need onKeyDown instead of onKeyPress.
class App extends React.Component {
handleKeyPress = ( event ) => {
if ( event.key === "ArrowDown" ) {
console.log( "Down arrow key fired" ); // does not fire
}
if ( event.key === "Enter" ) {
console.log( "Enter key fired" ); // does fire
}
};
render() {
return (
<div>
<ul>
<li
tabIndex="0"
onClick={this.handleClick}
onKeyDown={this.handleKeyPress}
>Foo
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<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>

ReactJS OnKeyPress to trigger a button press

I'm very new to ReactJS and I'm just trying to do some small things to understand more.
I was wondering if the OnKeyPress can trigger a button press. I've seen a few similar questions but what the OnKeyPress triggered was just a console.log or an alert. So I wasn't sure how to trigger the button press.
This is what I have so far:
class Form extends React.Component {
onButtonPress = (e) => {
// this is just an example of what happens when the button is pressed.
this.setState({isClicked: true});
}
keyPress = (event) => {
if (event.key == 'Enter'){
// How would I trigger the button that is in the render? I have this so far.
this.onButtonPress();
}
}
render() {
return (
<div>
<div className="fieldForm">
<input
value={name}
type="name"
onKeyPress={this.keyPress}
/>
</div>
<Button onClick={this.onButtonPress}>Submit</Button>
</div>
)
}
}
Please note that I didn't include everything in here such as the constructor, props, or the state object attributes.
The purpose of this is to make it look like the button has been clicked. When the button is clicked, it'll show a small loading sign on the button. I want the same thing to happen if I were to press enter (with the loading sign on the button, that's why I want the button pressed).
Is this possible?
Programmatically triggering DOM events is not something you should do unless you have very specific needs.
Both onKeyPress and onClick are event handlers, you can do anything you want when an event happens. I would just call a function that sets the state you want from both handlers.
Here's an example:
class Form extends React.Component {
handleFormSubmit = () => {
this.setState({ isClicked: true });
};
handleButtonPress = () => {
this.handleFormSubmit();
};
handleKeyPress = event => {
if (event.key == 'Enter') {
this.handleFormSubmit();
}
};
render() {
return (
<div>
<div className="fieldForm">
<input value={name} type="name" onKeyPress={this.handleKeyPress} />
</div>
<Button onClick={this.handleButtonPress} loading={this.state.Load}>
Submit
</Button>
</div>
);
}
}
In case you have no other way and you should click on this element for some vague reason and the method that elas said didn't work for you. try this:
onButtonPress = (e) => {
console.log('hi hi')
}
handleKeyPress = (event) => {
if (event.key === 'Enter') {
this.refs.but.click()
}
}
render () {
return (
<Layout>
<div>
<div className="fieldForm">
<input
value={'name'}
type="name"
onKeyPress={(e) => this.handleKeyPress(e)}
/>
</div>
<Button onClick={this.onButtonPress} ref="but">Submit</Button>
</div>
</Layout>
)
}

React prevent form submission when enter is pressed inside input

React prevent form submission when enter is pressed
I have the following React Search Bar component where the parent container can call using
<SearchBar onInputChange={this.handleInputChange} />
Everytime the user changes the input, the parent container will be notified. This is why my search bar does not need any submit button.
However, I am finding that if I press enter inside my search bar, the whole page refreshes. And I dont want that.
I know if I have a button in the form, I could call event.preventDefault(). But in this case I have no button so I dont know what to do here
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({ value: e.target.value });
this.props.onInputChange(e.target.value);
}
render() {
return (
<div id="search-bar">
<form>
<FormGroup controlId="formBasicText">
<FormControl
type="text"
onChange={this.handleChange}
value={this.state.value}
placeholder="Enter Character Name"
/>
</FormGroup>
</form>
</div>
);
}
}
export default SearchBar
You need to create a form handler that would prevent the default form action.
The simplest implementation would be:
<form onSubmit={e => { e.preventDefault(); }}>
But ideally you create a dedicated handler for that:
<form onSubmit={this.submitHandler}>
with the following implementation
submitHandler(e) {
e.preventDefault();
}
In a React component with a Search input field, nested in a larger (non-React OR React) form, this worked best for me across browsers:
<MyInputWidget
label="Find"
placeholder="Search..."
onChange={this.search}
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }}
value={this.state.searchText} />
(e)=>{e.target.keyCode === 13} (#DavidKamer's answer) is incorrect: You don't want the event.target. That's the input field. You want the event itself. And in React (specifically 16.8, at the moment), you want event.key (e.key, whatever you want to call it).
I'm not sure if this works for every situation, as when you press enter in a form's input field you will still trigger the onSubmit method, although the default submit won't occur. This means that you will still trigger your pseudo submit action that you've designed for your form. A one liner with ES6 that solves the problem specifically and entirely:
<input onKeyPress={(e)=>{e.target.keyCode === 13 && e.preventDefault();}} />
This solution should have 0 side effects and solves the problem directly.
The best way to prevent the ENTER, as suggested also by Eon is to add the following to your input element:
onKeyPress={(e) => { e.key === 'Enter' && e.preventDefault(); }}
This works for me:
<Input
...
onKeyDown={(e) => { e.key === 'Enter' && e.preventDefault() }}
/>
prevent for Enter key for search input:
<input type="text" onKeyPress={e => {
if (e.key === 'Enter') e.preventDefault();
}} />

Categories