Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Several inputs and arguments with onInput in Elm

Tags:

elm

I'm experimenting a little with Elm. Right now I have several input range on the screen and I want to control individually their values, but I don't know how to distinct between them (in Js I would send the ID and the VALUE of the input on the onInput callback) since I only can send ONE argument with the Elm's onInput

inp : Input -> Html Msg
inp inp =
    div [ class "input" ]
        [ p [] [ text inp.name ]
        , input [ id (toString inp.id), type' "range", value inp.volume, onInput ChangeInput ] []
        , controls inp.name inp.id
        ]

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Play id ->
            ( play model id, Cmd.none )

        ChangeInput id value ->
            -- Here I want to grab the id and the value coming from the input --

        NoOp ->
            ( model, Cmd.none )

Any help? Thanks!!

like image 586
Trajan Avatar asked Nov 07 '16 10:11

Trajan


3 Answers

Your message definition should be:

type Msg =
  ...
  | ChangeInput Id String

This gives it a signature of (Id -> String -> Msg). it takes an Id and a String and it returns a Msg. And the message includes id and string.

You can supply your own additional arguments by making the following change in your view:

onInput (ChangeInput id)

The formula (ChangeInput id) is a partial application:

You do not supply all arguments, but only one, so the result will be a function, that takes in the remaining arguments, and outputs the Msg type.

you already provide the Id to the message (Id -> String -> Msg), so the remaining signature will be (String -> Msg), which is what onInput is looking for.

like image 161
wintvelt Avatar answered Nov 08 '22 04:11

wintvelt


When you define a Union Type, you define both: type annotation definition and value constructor for it.

type Msg
    = NoOp
    | SomeMessage Int String

Union Type annotation definition

Here you will use Msg to define type annotation definitions for functions like:

update: Msg -> Model -> ( Model, Cmd Msg )

Union Type value constructors

Then you will use NoOp and SomeMessage as constructor functions for values of type Msg

Here is an example of function, which constructs a SomeMessage value and returns it:

createSomeMessage: Int -> Msg
createSomeMessage number =
    SomeMessage number "Hello!"

createSomeMessage 1 -- SomeMessage 1 "Hello!"

Union Type value constructors with with partial application

Elm supports Partial Application, which means, you can wait with the construction of values of Msg type, until you have all required arguments.

Here is how it works:

-- Partially applied value constructor, which expects new argument
messageWithId : String -> Msg
messageWithId =
    SomeMessage 1

{- Later in the view, (SomeMessage 1) will wait for the String from the
   input DOM event
-}
input [ onInput messageWithId ] []

-- Alternative way to express the same thing:

input [ onInput (SomeMessage 1) ] []

The example above shows, how you can use value constructors to apply some arguments, before the DOM event fires. That will result in to a message with data from partially applied function and the event itself.

Here's one example of described technique in action.

like image 2
halfzebra Avatar answered Nov 08 '22 05:11

halfzebra


Use partial application: onInput <| ChangeInput inp.id

The resultant function being passed now takes a single string argument as expected by onInput.

like image 1
Sridhar Ratnakumar Avatar answered Nov 08 '22 04:11

Sridhar Ratnakumar