无法连接端口和订阅

时间:2016-06-02 08:51:25

标签: javascript interop elm

我正在阅读Elm guide和他们的JavaScript interOp。这是一个简化版本:

port module FooBar exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.App as Html
import String

main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

-- subscriptions
port f : () -> Cmd msg
port g : ( Int -> msg ) -> Sub msg

subscriptions: Model -> Sub Msg
subscriptions model = g Get

-- MODEL
type alias Model = { pt :  Int }

-- VIEW
view: Model -> Html Msg
view model = Html.text ( toString model.pt )

-- UPDATE
type Msg = Ask | Get Int

update: Msg -> Model -> (Model, Cmd msg)
update msg model =
  case msg of
    Ask  -> (model, f () )
    Get x -> ( Model x, Cmd.none )

-- INIT
init: (Model, Cmd Msg)
init = ( Model 0, f ())

该应用最初设置为 0 ,但它应该从JavaScript中读取消息并设置为 1 。但是,它仍然 0 。 Elm端口是否设置正确?

         

<div id="foobar"></div>
<script src="foo.js"></script>
<script>
  var node = document.getElementById("foobar");
  var app  = Elm.FooBar.embed(node);

  app.ports.f.subscribe(
    function(){
      var myValue = 1;
      console.log(myValue);
      app.ports.g.send(myValue);
    }
  );
</script>

</body>

我放在:elm-make foo.elm --output=foo.js

myValue 1 打印到控制台的事实表明已调用f()端口,但g()端口永远不会被回送或正确处理。

2 个答案:

答案 0 :(得分:3)

很难判断这是否是一项设计决定,但在init订阅任何端口之前调用了Html.App

因此,从f ()调用init将无效。

我使用send函数,它运行一个虚拟任务并始终发送Ask消息,这将触发传出端口。

考虑更改您的init以发送将数据发送到端口的消息:

-- INIT


init : ( Model, Cmd Msg )
init =
    -- ( Model 0, f ())
    ( Model 0, send Ask )


send : msg -> Cmd msg
send msg =
  Task.perform identity identity (Task.succeed msg)

答案 1 :(得分:2)

如果您只想将Javascript中的默认值发送到您的Elm应用程序,则可以使用programWithFlags,无需尝试连接到尚未设置的端口:

main =
  Html.programWithFlags
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

-- INIT
type alias Flags = { initialValue : Int }

init : Flags -> (Model, Cmd Msg)
init flags = ( Model flags.initialValue, Cmd.none )

这允许您通过Javascript发送该初始值,如下所示:

var app  = Elm.FooBar.embed(node, { initialValue : 2 });