我已经动态创建了通过端口与Elm模型进行通信的Javascript组件。他们通过port sendData : ((ComponentId, String) ...
在榆树方面,有一个ChildComponent
模块代表他们的模型:
type alias ComponentId =
Int
port sendData : ((ComponentId, String) -> msg) -> Sub msg
type Msg
= ProcessData String
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch [
sendData ProcessData
]
在Parent
我有:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ChildMessage componentId msg -> ...
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ Sub.map (ChildMessage componentId) (ChildComponent.subscriptions model.child) ]
显然这会导致
Cannot find variable `componentId`
310| Sub.map (ChildMessage componentId) (ChildComponent.subscriptions (getChildModel (componentId model))) ]
^^^^^^^^^^^
如何从端口数据中“提取”componentId
?或者也许我正在做的是完全错误的?
更新
我已将问题(由@ChadGilbert建议添加一些内容)分离到项目中https://github.com/lguminski/ElmMultipleComponentsSubscription
答案 0 :(得分:0)
使用Sub.map
时,您需要一个接受子模型作为参数的函数。您可以将ChildMessage
定义为
-- in Parent.elm
type Model =
...
| ChildMessage Child.Model
您的父订阅功能需要更新:
-- in Parent.elm
subscriptions model =
Sub.batch
[ Sub.map ChildMessage (ChildComponent.subscriptions model.child) ]
当涉及从子端口处理数据时,您需要一个Msg
,其第一个参数与端口中定义的类型相同,主要是(ComponentId, String)
。考虑向您的孩子添加这样的内容,然后新的RouteData
消息可以在需要时调用ProcessData
更新案例,否则忽略它。
-- in Child.elm
type Msg
= ProcessData String
| RouteData (ComponentId, String)
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch [
sendData RouteData
]
update msg model =
case msg of
RouteData (componentId, val) ->
if componentId == "my-component-id" then
update (ProcessData val) model
else
model ! []
ProcessData val -> ...
<强>更新强>
根据您的其他详细信息,我建议您将端口和子Msg路由移出Child模块并进入Parent。然后,您可以将以下更新案例添加到父级:
ChildMessage componentId childMessage ->
let
childUpdates =
List.map (\c -> if c.id == componentId then updateChild c else c ! []) model.children
updateChild child =
let
(updatedChildModel, cmd) =
Child.update childMessage child
in
updatedChildModel ! [ Cmd.map (ChildMessage child.id) cmd ]
in
{ model | children = List.map Tuple.first childUpdates }
! (List.map Tuple.second childUpdates)
RouteData (componentId, val) ->
update (ChildMessage componentId (Child.ProcessData val)) model