Sungho Yahng
Sungho Yahng

Reputation: 91

I have a question about the Focus event and the Blur event

I'm sorry for the ambiguous title. It was difficult to explain the problem with a single sentence.

First, my code structure looks like this (with JSX)

<Parent>
    <EditableText1 />
    <EditableText2 />
</Parent>

Here's how I want it to work:

Here's how I tried:

1)

<Parent 
onFocus={() => { this.setState({ visible: 'flex' }) }} 
onBlur={() => { this.setState({ visible: 'none' }) }>
    <EditableText1 />
    <EditableText2 className={css`
display: ${this.state.visible};
`/>
</Parent>

The problem here is this:

enter image description here

When ET1 becomes 'focus', ET2 appears. However, if I try to select ET2, ET1 becomes 'blur', So 'display' of ET2 becomes 'none'. So I can not select ET2!

2) So I tried to prevent bubbling when ET1 is blurred:

<Parent 
onFocus={() => { this.setState({ visible: 'flex' }) }} 
onBlur={() => { this.setState({ visible: 'none' }) }>
    <EditableText1 
onBlur={(e) => { e.stopPropagation() }}
/>
    <EditableText2 className={css`
display: ${this.state.visible};
`/>
</Parent>

The problem with this case is this:

enter image description here

It is now possible to select ET2 after ET1 has been focused. But, If I blur from ET1 to outside of Parent, 'display' of ET2 does not change to 'none'.

enter image description here

If I blur outside Parent from ET2, 'display' changes to 'none' (the way I want it to work).

I do not know what to do anymore. It seems to be because of my lack of knowledge. Can anyone give me a way or give me a hint?

Upvotes: 2

Views: 185

Answers (2)

Sungho Yahng
Sungho Yahng

Reputation: 91

I eventually decided to use this method.

<div class="Parent">
  <input type="text" id="ET1" />
  <br />
  <input type="text" id="ET2" />
</div>

.Parent:focus-within #ET2 {
  display: flex;
}

#ET2 {
  display: none;
}

I asked a question at devpal.io and got this answer and got help. Thank you, Andy.

Hey there! Ok, so their response works, but I'd probably take a CSS approach using :focus-within: https://www.scottohara.me/blog/2017/05/14/focus-within.html It's got really good browser support: https://caniuse.com/#feat=css-focus-within I think you'll get a lot more resilience approaching it with that. Hopefully that helps

Upvotes: 1

J.Lindebro
J.Lindebro

Reputation: 223

Here is a possible solution. Its not the prettiest but i works. The main idea is to store which element has focus in the state. And when the blur event occurs on ET1 element you need to check if ET2 has focus or not. To do that you need to create a delay because the blur event will fire before the focus event. And without that delay the state telling which element has focus, will not have been updated yet.

import React from "react";

export default class myClass extends React.Component {
  constructor() {
    super();
    this.beforeBlur = this.beforeBlur.bind(this);
    this.update = this.update.bind(this);
    this.state = {
      whoHasFocus: "none",
      visible: "none"
    };
    this.delay = null;
  }

  beforeBlur(obj) {
    const that = this;
    this.delay = setInterval(() => {
      if (this.state.whoHasFocus !== "ET2") {
        this.update(obj);
      }
      clearInterval(that.delay);
    }, 10);
  }
  update(obj) {
    this.setState(obj);
  }
  render() {
    return (
      <div>
        <input
          type="text"
          onBlur={() => {
            this.beforeBlur({
              visible: "none",
              whoHasFocus: "none"
            });
          }}
          onFocus={() => {
            this.update({
              visible: "flex",
              whoHasFocus: "ET1"
            });
          }}
        />
        <input
          type="text"
          style={{ display: `${this.state.visible}` }}
          onFocus={() => {
            this.update({ whoHasFocus: "ET2" });
          }}
          onBlur={e => {
            this.update({
              visible: "none",
              whoHasFocus: "none"
            })
          }}
        />
      </div>
    )
  }
}

I hope this could be to any help for you.

Upvotes: 1

Related Questions