elm-html icon indicating copy to clipboard operation
elm-html copied to clipboard

Adding a function for virtual-dom's defaultValue property.

Open krisajenkins opened this issue 8 years ago • 9 comments

This is needed if you want to set an initial value for a form element. (In contrast with the "value" property, which sets the value on every re-render.)

krisajenkins avatar Oct 03 '15 21:10 krisajenkins

Can you explain more about this? Is there any documentation?

Is this a custom thing added into the underlying virtual-dom implementation in JS?

Is it possible to avoid reseting on every rerender instead?

evancz avatar Oct 03 '15 22:10 evancz

Yes, sorry, let me back up a bit and explain.

Here's a simple example (which I've lifted from @rtfeldman's signup form sample):

Demo Source

As it says, if you type something into the first input box, move the cursor to the start, and type quickly, the cursor position will jump - somehow the input & rendering get out of sync.

I believe this is because there's an assumption that the input-update-rerender happens in a single step, but I don't think that's the case. I think that if the event queue is busy enough - which I've simulated with an fps ticker - you can get more than one change in into the field before Elm/virtual-dom have caught up. Then the field is more than one character out of sync and gets confused.

I've seen a similar problem where characters are dropped, but the cursor-jump is easiest to replicate.

One solution is fairly easy. Just set the value on the input field once - using defaultValue - and thereafter let the input box's value be the master copy, driving the model. I've hit exactly the same problem using Om/React - react supports this property too - and it works just fine.

Obviously, "not getting out of sync" would be the ideal solution. But this works for me, and defaultValue has a legitimate use if you're using the HTML form-reset mechanism. So I thought I'd write the patch...

krisajenkins avatar Oct 05 '15 21:10 krisajenkins

Yeah, we've run afoul of this with integration tests - the test runner "types" into the input box too fast, so things sometimes get out of sync (but not always - it's a race condition, possibly having to do with requestAnimationFrame batching). We work around it by making it so that our integration tests always fill out forms using a single character (e.g. for firstName filling out "S" instead of "Sam") but that's hardly ideal. :smile:

I've always thought defaultValue was pretty clunky/confusing in React, and it's more so in Elm because reading directly from the DOM is more explicitly discouraged.

I think we should at least discuss other options before doing what React did here. Is there some way to solve the "getting out of sync" race condition problem? Happy to elaborate on stuff we've encountered etc if it would help.

rtfeldman avatar Oct 05 '15 22:10 rtfeldman

I thought I'd post here as it was mentioned in the other discussion thread I was involved with

I believe the problem observed in the examples is with a selection instead as when you modify the input.value it changes input.selectionStart and input.selectionEnd to the end of the value. So what you you observe is when you change cursor position your model and actual DOM state gets out of sync as a side effect of actually not keeping track of selection ranges.

In the project I work we resolved similar issues with input.value by starting to model selection in the input along with value. That way when you update a value you also update cursor position back to it's original and there for avoid getting out of sync with actual DOM. Please note that there are many crucial details on when to update selection and not to update it when it already matches the selection in the input to avoid other races, but given the interest I'm happy to share more details.

Gozala avatar Aug 02 '16 18:08 Gozala

@Gozala Can you share your solution for tracking selection in model?

rofrol avatar Jan 08 '17 00:01 rofrol

@Gozala Can you share your solution for tracking selection in model?

@rofrol I did describe it in the mentioned thread. As of project I mentioned, it is unfortunately not in Elm but in JS that very closely follows Elm architecture and and design (well from version back for now) but feel free to look at how solution looks there:

Here is an implementation of what I would turn into a selection attribute in Elm: https://github.com/browserhtml/browserhtml/blob/master/src/driver/virtual-dom/index.js#L226-L251

If you look at the generic Edit field code both input and selection events carry input selection information with a message so that two stay in sync and avoid issues described.

P.S.: Code is little old & solution is not quite as elegant as a proposal in the discussion thread, but it works.

Gozala avatar Jan 12 '17 19:01 Gozala

I am also having issues with value versus defaultValue for a textarea. This is for an app for composing mathematics (etc) lecture notes online. Here is the saga (1) I originally used value. However, I discovered that when typing other than slowly, the cursor-insertion point would jump around in a crazy way. (2) I switched to defaultValue. That solved the original problem but resulted in a new one: (3) If I then select another document to edit from the list of available documents, the text to edit does not change.

I should say that there are two side by side "panes" -- one, on the left, with the "source" text, the other on the right, with the rendered text (rendered by asciidoctor + mathjax). The right-hand text, which is managed by ports, behaves correctly.

For the moment I can live with this, but won't be able to go into production without a solution. Perhaps there is an easy fix ... ??? When I select a new document, it becomes the current_document in the model, its rendered content is displayed in the right-hand pane, and its left-hand pane is "loaded" with content, aka source text.

jxxcarlson avatar Jun 16 '17 20:06 jxxcarlson

@jxxcarlson You have to also use Html.Keyed, to essentially force Elm to create a new textarea which once again uses the defaultValue. A nice example is here:

https://ellie-app.com/3fPSxX6VHK7a1/0

Look at the way reset is implemented. Without the Html.Keyed, reset would not actually reset the input.

amilner42 avatar Jun 19 '17 19:06 amilner42

Ran into this today with a barcode scanner and an input field. Scanner typed faster than Elm's update/render cycle. This caused characters to get dropped in the input field. It's a shared mutable state problem since both the user and Elm renderer are both writing into value competitively. Using defaultValue fixed the issue.

I see in the documentation that defaultValue has been added to Elm already.

kspeakman avatar Sep 01 '17 16:09 kspeakman