连接端口和订阅时遇到问题

Trouble Connecting Ports and Subscriptions

我正在通读 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

myValue1 形式打印到控制台的事实表明 f() 端口被调用,但 g() 端口从未被发送返回或处理得当。

很难判断这是否是设计决定,但 initHtml.App 订阅任何端口之前被调用。

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

我使用 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)

如果您只是想将默认值从 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 });