All the TextFields in my app move the cursor to the end of the input on first edit. Subsequent edits work just fine.
If I replace the <TextField .../>
with an <input .../>
, the behavior stops.
There is a hacky fix to the problem I'm observing - Comment out this line https://github.com/callemall/material-ui/blob/master/src/TextField/TextField.js#L356
this.setState({hasValue: isValid(event.target.value), isClean: false});
Then the problem goes away, although I'm sure this isn't a correct fix.
@joewalker I just tried using the controlled example in the docs, and it's working fine.
Here's my hunch as to what's up:
My TextField is in a Dialog, and it looks like Dialog works by having a second render loop, which I think means that setState might become asynchronous? If that's true, then maybe the answer is in here?
Quick video of what's going wrong:
I press 'u' at the start of the TextField and the cursor jumps to the end.
Is there any documentation to what hasValue and isClean do?
I'm happy to work out a more correct fix
I'm afraid you may have to reverse engineer it to figure that out.
I'm experiencing the same issue with the same version. I'm observing that It's always jumps to the end if I do custom modification to the value each time a key is pressed. In my TextField I automatically add space between group of numbers to make it more readable. Do you have some kind of advice?
After some more research, It turn out my issue related to how react behave https://github.com/facebook/react/issues/955
@joewalker: I have replicated this issue in a dialog - it is a bit annoying!
This repros only for TextField in Dialog.
Use "defaultValue" instead of "value" with TextField will fix it.
Use "defaultValue" instead of "value" with TextField will fix it.
Right, except that this makes the TextField no longer be controlled, so it's not a fix to the problem.
It is controlled. Try it.
<Dialog
title="Add Item"
modal={false}
open={this.state.showDialog}
>
<TextField
id="text-field-controlled"
defaultValue={self.state.value}
onChange={(e)=>{
self.setState({
value: e.target.value
})
}}
/>
</Dialog>
onChange will be triggered.
I am also having the same issue in all TextInputs. The temporary fix doesnt work. Is there any other work around?
It seems there are 2 ways of doing dialogs - with a portal so the dialog renders in a separate render loop, and without so the rendering is as you would expect.
The portal method probably makes for better webcompat, but it makes it harder to test with things like enzyme and causes problems like this.
My intention when I next visit this problem is to look at Boron and Skylight to see if they fit. They seem to not use portals and I'm hoping that it will make it easier to write unit tests.
I think we can close this since it appears to be an issue with React itself (https://github.com/facebook/react/issues/955#issuecomment-33104589).
cc @oliviertassinari.
Look for these code in TextField.js and comment out the line
// _this.setState({ hasValue: isValid(event.target.value), isClean: false });
This fixed the issue for me. It has been a while ago, I don't remember how I figure it out. Just want to share the code.
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(TextField)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = {
isFocused: false,
errorText: undefined,
hasValue: false,
isClean: true
}, _this.handleInputBlur = function (event) {
_this.setState({ isFocused: false });
if (_this.props.onBlur) _this.props.onBlur(event);
}, _this.handleInputChange = function (event) {
// _this.setState({ hasValue: isValid(event.target.value), isClean: false });
if (_this.props.onChange) _this.props.onChange(event, event.target.value);
}, _this.handleInputFocus = function (event) {
if (_this.props.disabled) return;
_this.setState({ isFocused: true });
if (_this.props.onFocus) _this.props.onFocus(event);
}, _this.handleInputKeyDown = function (event) {
if ((0, _keycode2.default)(event) === 'enter' && _this.props.onEnterKeyDown) _this.props.onEnterKeyDown(event);
if (_this.props.onKeyDown) _this.props.onKeyDown(event);
}, _this.handleHeightChange = function (event, height) {
var newHeight = height + 24;
if (_this.props.floatingLabelText) {
newHeight += 24;
}
_reactDom2.default.findDOMNode(_this).style.height = newHeight + 'px';
}, _temp), _possibleConstructorReturn(_this, _ret);
}
@lucasbento Given the potential work-arounds in this thread and the linked React bug, I don't think it's a bug on their part. FWIW, the React team closed it as not a bug on their end. This seems very related to how a Dialog renders its children.
I haven't dove too deep, but I don't think the above solution is the right one. I'll post if I figure out anything more sustainable.
I'm having a slightly different problem that might be related to this. The cursor jumps to the end in a multiLine
TextField
on line break, only when the input is controlled and within a Dialog.
Multi-line TextField within Dialog (cursor jumps to the end):
Multi-line TextField (works fine):
My workaround was to make only this TextField uncontrolled for now.
My workaround was to not use a Dialog :(
This is still an issue
I'm also having the same issue on a controlled TextField.
It is not in a dialog. It's simply controls a phone input.
I'm using a workaround to fix the position manually on the next cycle. It's not the best fix, as the cursor blinks at the end and then returns to correct position.
setTimeout(fixCursorPosition, 0, event.currentTarget, formattedValue)
The workaround found in this comment fixed any instances of issues I was having. I'm not sure if it's safe enough to use within MUI's TextField
directly though.
Most helpful comment
This is still an issue