Reputation: 91
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:
In the default state, 'display' of ET2 (EditableText2) is 'none'
When 'Parent' is 'Focus' ET2's 'display' value becomes 'flex'
When 'Parent' is 'Blur', ET2's 'display' value becomes 'none' again
In other words, if ET1 is selected(ET1 is visible), ET2 becomes visible, and ET2 can be edited in that state.
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:
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:
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'.
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
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
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