3

When the user presses a certain key, a component shows. I have four such components. When the user is typing or editing, I want to disable the hotkeys.

I have this code in each of the four components

componentDidMount(){
    document.body.addEventListener("keypress", (e) => {
        if (e.key === "t") { // "n" "w" "," for the others
            this.setState({opened: !this.state.opened});
        }
    });
}

I only want to disable hotkeys when the user is typing or editing. Is there a way to know if any input is in focus? Or the other way, can we add the event listeners only if all the inputs are 'on blur'?

César García Tapia
  • 3,326
  • 4
  • 27
  • 51
lmathl
  • 199
  • 2
  • 12

2 Answers2

4

So we need to know if any of the inputs on the page are in focus and if any of them is focused then we just will not do anything to show or hide components.

Let's assume that our component has in the state some property which indicates that some input on the page is focused, let's call it isFocus.

So, we need to collect all inputs on the page, iterate over them all and assign to each input the focus and the blur event handlers, so we will be able to know when to change the isFocus property in the state.

First of all, we need to collect all of the inputs on the page, we do it with:

const inputs = document.getElementsByTagName('input').

Iterate over them all and assign the focus and blur event handlers:

for (let input of inputs) {
    input.addEventListener('focus', () => this.setState({isFocus: true}));
    input.addEventListener('blur', () => this.setState({isFocus: false}));
}

And finally, let's change the condition for the keypress event:

document.addEventListener('keypress', e => {
    if (!this.state.isFocus && e.key === "t") {
        this.setState({opened: !this.state.opened});
    }
});

Everything together will look like this:

componentDidMount() {
    const inputs = document.getElementsByTagName('input');
    for (let input of inputs) {
        input.addEventListener('focus', () => this.setState({isFocus: true}));
        input.addEventListener('blur', () => this.setState({isFocus: false}));
    }

    document.addEventListener('keypress', e => {
        if (!this.state.isFocus && e.key === "t") {
            this.setState({opened: !this.state.opened});
        }
    });
  }

Hope this helps. Good luck.

1

You could move the current open component state to the most upward component, like the following:

state: {
    openComponent: null
}

your hotkey function would look like this:

hotkey(e){
    const componentKeyHandlers = {
       "n": {openComponent: "componentN"},
       "m": {openComponent: "componentM"}
    }
    if (e.keyCode === 27) { //ESC
        this.setState({openComponent: null});
    } else if (!this.state.openComponent) {
        this.setState(componentKeyHandlers[e.key]);
    }
}

I'm assuming you could only have ONE open component each time. Also, you could close them by hitting ESC. For each component, its visibility would be controlled by comparing props.openComponent to its name, given that the current state component is passed down to each one via props.

This way you don't need to unregister the hotkey function. When you start typing with an open component, the setState is going to be ignored due to the if (!this.state.openComponent) condition.

diogenesgg
  • 2,601
  • 2
  • 20
  • 29
  • Thanks, but this is not what I want and I can't modify it to make it work. When the component is open and I'm not editing, I still want to be able to press a key and then the component closes. – lmathl Jun 03 '18 at 07:59
  • 1
    You could create a new state `editing` and evaluate it on `hotkey` function prior calling `setState`. Also set editing to false on component close. – diogenesgg Jun 03 '18 at 12:30