通过端口将事件处理程序从Elm传递给JS

时间:2019-06-30 04:01:47

标签: javascript elm ffi

在JS中,我们有一个像这样的函数:

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

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

我的榆木代码:

  

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>

现在,我可以获取params的值,但不知道如何通过event将事件处理程序(如JS代码中的port从Elm文件传递给JS(将该值传递给btnSelector), 因此我可以将该值用于旧版代码。有人可以帮助我吗?

非常感谢!

1 个答案:

答案 0 :(得分:2)

您可以将完整的事件对象提取为Value,并将其通过端口传递。

port toJS : Value -> Cmd msg

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

update中有类似

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SomeTag value ->
            ( { model | count = model.count + 1 }, toJS value )
附带说明,如果传递给JS的值是基本值(Bool,Int,Float,String,Maybe,Json.Decode.Value和List,Array,元组或先前类型的记录),则可以只需将它们作为记录传递。因此,就您而言,您可以:

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 ) )