SSCCE
https://ellie-app.com/vGfNrrxcb5ba1
module Main exposing (main)
import Browser
import Html exposing (Html)
import Html.Attributes
import Html.Events
import Html.Lazy
type alias Model =
{ text : String
, lazyText : String
}
initialModel : Model
initialModel =
{ text = ""
, lazyText = ""
}
type Msg
= GotText String
| GotLazyText String
update : Msg -> Model -> Model
update msg model =
case msg of
GotText text ->
{ model | text = String.filter Char.isDigit text }
GotLazyText text ->
{ model | lazyText = String.filter Char.isDigit text }
view : Model -> Html Msg
view model =
Html.div []
[ Html.p [] [ Html.text "These inputs only allow you to type digits. However, it doesn’t really work for the lazy one." ]
, Html.label []
[ Html.text "Regular: "
, viewText model.text |> Html.map GotText
]
, Html.hr [] []
, Html.label []
[ Html.text "Lazy: "
, Html.Lazy.lazy viewText model.lazyText |> Html.map GotLazyText
]
]
viewText : String -> Html String
viewText text =
Html.input
[ Html.Events.onInput identity
, Html.Attributes.value text
]
[]
main : Program () Model Msg
main =
Browser.sandbox
{ init = initialModel
, view = view
, update = update
}
The above code renders two inputs that are identical, except that one of them uses Html.Lazy.lazy. As you type in them, non-digits are filtered away.
Html.Lazy.lazy is not supposed to change behavior (only performance), but in this case it unfortunately does: Non-digits are not filterned away (until you type an actual digit).
Here’s what happens:
- The user types “a”.
- The browser updates
.value of the input to "a".
- The browser fires the
input event.
- The Elm
update code filters "a" to "".
view is called.
For the regular input:
- No diff for
value is detected compared to the previous virtual DOM (it is still the empty string). However, value is special cased and is updated anyway. https://github.com/elm/virtual-dom/blob/1.0.3/src/Elm/Kernel/VirtualDom.js#L511 + https://github.com/elm/virtual-dom/blob/1.0.3/src/Elm/Kernel/VirtualDom.js#L927
- The result is that the user never sees “a” in the input field.
For the lazy input:
- Since the argument to
lazy is unchanged (still the empty string), diffing is skipped.
- The result is that the “a” that the browser put into the input field is left behind (even though the model says it should be the empty string).
SSCCE
https://ellie-app.com/vGfNrrxcb5ba1
The above code renders two inputs that are identical, except that one of them uses
Html.Lazy.lazy. As you type in them, non-digits are filtered away.Html.Lazy.lazyis not supposed to change behavior (only performance), but in this case it unfortunately does: Non-digits are not filterned away (until you type an actual digit).Here’s what happens:
.valueof the input to"a".inputevent.updatecode filters"a"to"".viewis called.For the regular input:
valueis detected compared to the previous virtual DOM (it is still the empty string). However,valueis special cased and is updated anyway. https://github.com/elm/virtual-dom/blob/1.0.3/src/Elm/Kernel/VirtualDom.js#L511 + https://github.com/elm/virtual-dom/blob/1.0.3/src/Elm/Kernel/VirtualDom.js#L927For the lazy input:
lazyis unchanged (still the empty string), diffing is skipped.