tam.dangc
tam.dangc

Reputation: 2032

Pass event handler from elm to JS through port

In JS we have a function like this:

const handleClick = event => {
  event.preventDefault();
  // some more code
}

<button onClick={this.handleClick}>Add to bag</button>

My Elm code:

main.elm

port addToBag : Value -> Cmd msg

type Msg
  = ClickBag Item

update msg model =
  case msg of
   ClickBag item ->
      let
        data =
          Encode.object
            [ ("price", Encode.string item.price)
            , ("sku", Encode.string item.sku)
            ]
      in
        ( model, addToBag data )

view model =
  button [onClick ClickBag model.item] [text "Add to bag"]

index.html

<div id="elm"></div>

<script type="text/javascript">

  const addToBag = (params, btnSelector = null) => {
    console.log('json data', params)
  }

  const ElmApp = Elm.Main.init(document.getElementById('elm'))

  ElmApp.ports.addToBag.subscribe(addToBag)

</script>

For now, I can get the params value but don't know how to pass the event handler(like event in JS code) from Elm file to JS through port(pass that value to btnSelector), so I can use that value for the legacy code. Anyone can help me?

Thanks a lot!

Upvotes: 2

Views: 463

Answers (1)

pdamoc
pdamoc

Reputation: 2923

You can extract the full event object as a Value and pass that through the port.

port toJS : Value -> Cmd msg

onClickWithValue : (Value -> msg) -> Attribute msg 
onClickWithValue toMsg =
    on "click" (Json.map toMsg Json.value)

and in update have something like

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SomeTag value ->
            ( { model | count = model.count + 1 }, toJS value )

on a side note, if the values you pass to JS are basic values (Bool, Int, Float, String, Maybe, Json.Decode.Value and List, Array, tuples or records of the previous types) , you can just pass them as a record. So, in your case, you can have:

type alias Item = 
    { price: String 
    , sku: String 
    }

port addToBag : (Item, Value) -> Cmd msg

type Msg
  = ClickBag Item Value

view model =
  button [onClickWithValue (ClickBag model.item)] [text "Add to bag"]

update msg model =
  case msg of
   ClickBag item value ->
        ( model, addToBag ( item, value ) )

Upvotes: 4

Related Questions