I have a form with blur-events bound to the required fields. Then there is a "Cancel" Button which simply calls an URL (button is an image with click-event).
When leaving one of the required fields a warning is written to the page saying that field xy is required. -> this causes a layout shift, meaning all the fields and the buttons are moved down a little bit because of the text inserted above.
The tricky thing is this: when the focus is in an empty but required field and you click the cancel button, the required-warning is written to the screen but the click-event on the cancel button doesn't fire.
I think this is due to the layout shift. The mouse cursor doesn't hover over the button anymore, because the button scrolled down.
Has anyone a good idea how i could solve this?
You could attempt to display the warning before the change/blur events by polling a setInterval function, so that by the time you get to the ‘Cancel’ button the reflow has already occurred.
Or, you could catch onmousedown on the button instead of onclick as it will occur before blur. (Makes the button behave not-quite-as-expected though.)
But I'd probably simply try to make the warning not cause a reflow when it appears if possible, by leaving a blank space otherwise.
Related
I introduced a bug at some point (live version doesn't have this issue) but haven't been able to figure out what caused it.
I have a button in React (it's just a div with an onClick).
The button has an onClick and a :hover CSS effect.
The button is loaded by clicking on another div (which works on the first click).
After loading the button (and its wrapper content), the button doesn't do anything on the first click. Without doing anything else, clicking again let's it work fine.
Currently I have a debug message in my onClick, so it looks something like this
onClick={(e) => {
console.log("ONclicked! " + this.props.alt);
// e.stopPropagation();
// various callbacks
}}>
I also have similar console.log debug messages on all of the button's parents, all the way up to the root React element (i.e. clicking anywhere on the page shoots out a message, except when clicking on this particular button the first time). Even the root element does not register anything on the first click..
None of these messages appear on the first click.
Again, without doing anything else, just clicking one more time in the same spot fires the onClick as expected.
Other questions about "first click not working" I've seen are all about the state not updating on the first click. In my case I'm not even trying to update the state, I don't seem to be getting the onClick called at all.
I've looked through all the commits for this version and still haven't been able to figure out the problem. Any ideas on what can cause this behavior? The weirdest part to me is that the second click works, while the first doesn't seem to do anything. But nothing about the state/DOM is changing between the first and second click (since the first click doesn't seem to be registered at all). I think this rules out things like a misconfigured pointer-events CSS rule?
Edit:
Upon further exploration, it seems that the first click actually triggers onMouseEnter, which seems totally nuts lol... But I added a console.log to onMouseEnter and it's definitely triggering exactly when I make the first click, and NOT on subsequent clicks.
Edit 2:
But this mouseEnter thing only happens in Firefox, not Chrome. But the first click not working bug is in both browsers.
Edit 3:
onMouseDown is firing properly, but onClick still only happens on the second time the button is clicked (at which point onMouseDown has fired twice).
Also, double checked and confirmed that I don't use stopPropagation anywhere which seems to be a common source of this problem.
Figured it out!
In another adjacent div, I had an onBlur handler. In that handler, I called setState() on the component (hiding another div when that div is unfocused).
To show the button that was having issues, I clicked in something in the div with the onBlur. This gave it focus. When I did a first click outside on the button that appeared, it triggered blur.
Apparently, the setState() call interfered with the click in some way, including causing the weird behavior I described with mouseEnter being retriggered. Perhaps the setState caused a redraw, which then caused mouseEnter to be fired again? Maybe the quick redraw also stops the onClick from going through, even though mouseDown is fired? (something to do with event ordering?) I'm still not sure why exactly that happens.
But after removing the setState() call, the first click on the button works as expected.
And thus ends a couple hours of painful debugging.
I had the same problem, in your onClick function you have to persist your event.
onClick={(e) => {
e.persist();
console.log("ONclicked! " + this.props.alt);
// e.stopPropagation();
// various callbacks
}}>
see this link for more explanation on the subject: https://deepscan.io/docs/rules/react-missing-event-persist
If you are using Intellij or WebStorm this happens when running javascript debug mode.
I feel like I understand focus():
When trying to focus on a form element, like input, it "just works", so long as the document is ready.
When trying to focus on a non-form element, like div, you must add a tabindex attribute.
tabindex adds the ability to tab to an element in precedence order (higher number the better), 0 and up. However, there's a special value, -1, that explicitly removes the element from the tab order.
When calling focus programmatically, do so within a setTimeout.
Be sure to make a setTimeout value large enough that it waits for display animations to finish, but not so late that the user has time to do other things, like click or type elsewhere.
Pretty simple, really, right? But no. It just doesn't work for me.
My specific use-case is that I have a key-nav-enabled widget that, if you hit the right key, opens a pop-over modal widget. It works great. But I can't get that modal widget to take focus. That modal widget that has no form inputs (just some text and a close link). I've added keydown/up/press events to the modal widget, I've added tabindex to various nodes and tried to focus them, but the original widget still gets the keyboard events.
DOM-wise, the modal widget, despite being new'd up within the keynav widget, is attached to the DOM at the body level, so it's not like the keyboard events are bubbling up through my modal dialog and should be stopPropagation'd, it's never getting those events.
What this means is that if you hit another key before you click in the modal widget, it opens a different modal dialog underneath the first modal dialog!
I really hope I'm missing something about focusing divs, because I have several pieces of functionality I'd like to implement that just aren't working due to (I believe) focus requests simply being ignored.
Help! What am I missing?
In the specific case I was sleuthing out, I effectively had a typo.
I was doing this, which wasn't working:
setTimeout(lang.hitch(this, this.domNode.focus), 100);
But this worked:
setTimeout(function() { this.domNode.focus() }, 100);
That said, I've had a number of issues with focus that regularly make me dread ever having to use it programmatically.
Hopefully though, the list of tips in the question will be helpful to someone.
I have divs, which are made to textinput fields by a plugin. Also those divs are draggable.
Right now, I have reached, that if you drag the div, it gets dragged, and if you just click on it, it gets a ".focus()".
The problem is now, that if I click it once, i get a focus on it. But the cursor jumps to the beginning of the line.
What I want, is the cursor on the place, I clicked.
How can I do this with jquery? Thanks
EDIT (My JS Code):
$('.mydiv').click(function(){
//actually, it does not focus on "$(this)" but on a div inside ".mydiv" which
//is generated by the plugin
$(this).focus();
})
You could consider listening for mouseup and mousedown instead of click, which would help you distinguish between which event the user is performing. Like, if there is a mouse down event, and the user moves the mouse before a mouseup event, then you're in "drag" mode. If there's a mouseup event, and the user is not in "drag" mode, then the user has clicked, and you can fire a focus event.
That's the approach I would take without knowing more about what you're doing.
The truth is that you have a considerably more complex interface requirement than most, meaning you're going to have to give the computer more instructions to determine what to do :)
How do I force blurring, but without calling onBlur event in JavaScript/jQuery?
I'll try to describe you what I need it for:
when onBlur is called, I call a PHP script via jQuery and validating input. If there's something wrong, it returns a message and then I display it back in jQuery script.
if a blurred field isn't filled, script should focus user back to that field.
And the problem is that if you press TAB to change field, and your first field is not filled, script will focus you back, but then is called onBlur from second field that is also not filled, and then it causes an infinite loop.
So, i want to blur a field and focus to another without calling onBlur event.
It's not an answer as spec'ed in your question, but what I'd suggest you do (in a somewhat UX sort of perspective) is to scrap the auto-refocus on invalid input, and instead mark the invalid field (may I suggest red, for example?). Now, you can go and deal with the (arguably) simpler problem of preventing a form submit on invalid data, instead of the problem of preventing a natural browser behavior type of an event.
Additionally, I'd dare to say that auto-refocusing is irritating for the user. Imagine tabbing to the second field, start typing, then suddenly yoink! You get dragged to the first field.
Why not just use on "change" and "keyup" instead of on blur?
I agree with Richard above, there's nothing more annoying than losing focus in the middle of typing, but if you do need to do this (Due to a customer requirement etc) - in the code that auto-focuses the field, disable the onBlur function temporarily until you've focused the field, then re-enable it.
How do I make for this onFocus to occur just 1 time (not as now that is blocking the windows with dialogs)?
<html>
<form name="myForm">
<input type="button"
value="Big Button"
name="myButton"
onFocus="alert('Focus event occured')">
</form>
</html>
update:
sorry, when I say "a single time" I mean a single time each time it receive focus. Currently with a single focus it shows infinite dialogs.
This is problematic. When the input field gets focus the focus event is fired, you handle that event by putting up an alert box which takes focus away (a "blur" event) from the input field. When the alert is dismissed the input field gets focus again, firing the focus even another time, and leading to an endless loop of gain/lose/gain focus. You are getting the focus even more than once because you are changing the focus.
You do not want to do something in a focus handler that changes the focus like this, unless it's something along the lines of "when this control gets focus, send focus to that other control instead".
If you do something that doesn't cause a focus change (which an alert does), such as adding text to a div when you get focus, you'll see that the event will only occur once.
If you describe what you're actually trying to accomplish you may get better advice. I assume the alert is just a test.