This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
A module to handle unexpected behavior when using `lazy` with `input` tag.
version 1.0.3
license MIT
native-modules False
elm-version 0.18.0 <= v < 0.19.0
Tag 1.0.3
Committed At 2017-08-12 12:37:59 UTC
elm-lang/html 2.0.0 <= v < 3.0.0 2.0.0
elm-lang/core 5.0.0 <= v < 6.0.0 5.1.1
arturopala/elm-monocle 1.4.0 <= v < 2.0.0 1.7.0




Build Status


A module to handle unexpected behavior when using lazy with input tag.

When should we use this?

If you use Html.Lazy.lazy (or lazy2, lazy3, etc...) to a view function it contains input tag, you should give a thought to use IString.

Let's see one example case that have to use IString. Here is a excerpt of an example code in /example directory.

type alias Model =
    { ...
    , value : String

type Msg
    = ...
    | UpdateValue String

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        UpdateValue str ->
            ( { model
                | value = normalize str
            , Cmd.none

view : Model -> Html Msg
view model =
        [ ...
        , digitInput model.value

digitInput : String -> Html Msg
digitInput str =
    Debug.log "digitInput was called." <|
            [ onInput UpdateValue
            , value str

This code do just update model.value when a user inputs a key on the input tag. The only thing, that is special, is it do some sort of "normalization" before updates.

{-| Filter only digit characters.

    normalize "s"
    --> ""

    normalize "9"
    --> "9"

    normalize "asl20la2"
    --> "202"

normalize : String -> String
normalize =
    String.fromList << List.filter Char.isDigit << String.toList

Here, the normalize function above only filters digit characters. As a result, only digit characters are shown on the input tag. All user inputs except digit characters are discarded.

Let's assume that you pushed keyboard keys "s" "3" "a" sequentially. The first "s" you entered does not affect at all because it is not a digit number. After pushing second key "3", the input field shows "3" as it is the only digit character you pushed. And finally, when you input "a", it still shows "3".

Here's sample page, which built the source code above.

One of the problem of this code is that this calles digitInput on every time some event updates Model, even if the updates are not related to model.value.

You can assure that by opening web console on the sample page. All the time you click "dummy event" button, which does not affect model.value at all, digitInput was called.: ... will be printed on your web console.

So, here we should use Html.Lazy.lazy to reduce useless rerendering of digitInput. I'll pick up a snippet from example/src/Lazy.elm.

view : Model -> Html Msg
view model =
        [ ...
        , lazy digitInput model.value

It only changes to use lazy on view function.

Though it successfully reduces some useless rerendering events, it changes the behavior of input field!

To ensure, enter "s" "3" "a", as previously we did, on sample page. If you enter "s", it shows "s" on input field and the "s" remains till you push "3". Furthermore, if you input "a" after that, "3a" is shown on the input field...

This is because input tags have some sort of their own state, and it breaks Single Source of Truth of our code.

Initially, model.value is "", and the input tag has state "" as its value. How it goes after entering "s"? The normalize function convert it to "", it is as same as initial value, so lazy decides not to rerender digitInput. On the other hand, the input tag changes its state "" to "s", and it is not overwritten by Elm because digitInput is not called. This causes the unexpected behavior mentioned above.

The IString solves this problem. You only have to replace the type of model.value String with IString, and ask compiler what to do. See example for details.