preact icon indicating copy to clipboard operation
preact copied to clipboard

Can't implement masked input

Open just-boris opened this issue 5 years ago • 10 comments

I am trying to use Rifm.js library to create masked input. The library works with React, but fails to work with Preact/compat.

The demo is here: https://9x6wv.csb.app Source code: https://codesandbox.io/s/9x6wv

just-boris avatar Dec 21 '19 19:12 just-boris

Hey @just-boris, thanks for opening this issue! I just opened the linked CodeSandbox and the masked inputs seemed to be working fine, maybe? Can you give it another try and let us know?

Thank you!

cristianbote avatar Jan 28 '20 20:01 cristianbote

Hi @just-boris I can reproduce your issue in the codesandbox and I think it is another issue caused by preact not really supporting controlled inputs.

Ping @JoviDeCroock as I remember you were digging into this issue too.

If I'm really right and this is caused by not really supporting controlled components we need to take action on this. Either we should warn when someone is using controlled components (i.e. using the value attribute) or properly support controlled components (if that is even possible without a custom event system)

sventschui avatar Jan 28 '20 21:01 sventschui

I haven't looked into this case specifically (yet, I'll try to make some time for this in the near future) but yes.

Let me describe the issue for future reference, what we do in Preact is we let the native behavior occur, this is our input command will alter the dom-node's value attribute. However when we re-render we double check this attribute, whether or not this was changed by a passive event or not. If it was and it doesn't correspond to the value we have in virtual dom we change it to be correct. Now for the case where this becomes erroneous imagine this:

const Input = () => {
  const [text, setText] = useState('');
  cosnt onChange = (e) => {
    if (e.target.value.length <= 3) {
      setText(e.target.value)
    }
  }
}

When we input "Foo" our state represents "Foo" and so does our input tag, when we type an extra "o" this condition will be false and the state will be Foo but our text in our input will be "Fooo". Linear happens if we'd setState with the currentValue because for instance instead of an if-check we only grab the first 3 characters.

I hope this is a clear description of where this currently fails. This could be solved by monkey-patching onInput in /compat for these scenario's

JoviDeCroock avatar Jan 28 '20 21:01 JoviDeCroock

I just opened the linked CodeSandbox and the masked inputs seemed to be working fine, maybe? Can you give it another try and let us know?

@cristianbote the cursor always remains at the start of the input, when you type a text. Here is the video:

Screen Recording 2020-01-29 at 10 12 15

just-boris avatar Jan 29 '20 09:01 just-boris

Solved this problem for me by overwriting inputs value though ref. Not sure, that is good, but it works. https://codesandbox.io/s/preact-phone-mask-i8r8y?fontsize=14&hidenavigation=1

precious-void avatar Feb 08 '20 12:02 precious-void

@shtelzerartem tested your example, the same issue when you are trying to insert text in the middle:

Screen Recording 2020-02-08 at 15 17 08

just-boris avatar Feb 08 '20 14:02 just-boris

@just-boris you can try to manage with this, by observing cursor position with selection start/end on key up. https://codesandbox.io/embed/preact-phone-mask-i8r8y?fontsize=14&hidenavigation=1&theme=dark

const handleChange = e => {
    const { selectionStart, value } = e.target;
    const inputValue = doFormat(value, "+* (***) ***-**-**", null);

    // On selection (e.key === undefined)
    if (e.key === undefined) {
      setValue(inputValue);
    }
    // On input change
    else if (e.key.replace(/[^0-9.]/g, "").length || e.key === "Backspace") {
      setValue(inputValue);
      ref.current.value = inputValue;
      const caretPos = doFormat(
        value.slice(0, selectionStart),
        "+* (***) ***-**-**",
        null
      ).length;
      ref.current.setSelectionRange(caretPos, caretPos);
    }
};

precious-void avatar Feb 08 '20 16:02 precious-void

Text inputs are not controllable in Preact, from what I see

umutzd avatar Jul 29 '20 10:07 umutzd

Text inputs are not controllable in Preact, from what I see

Is this still the case?

retsi101 avatar Mar 04 '24 00:03 retsi101

No

umutzd avatar Mar 04 '24 16:03 umutzd