2017-01-03 16 views
0

私は、ポート経由でElmモデルと通信するJavascriptコンポーネントを動的に作成しました。私が持っているParentElm 0.18:内容に基づいてSub.mapでメッセージをルーティングするには?

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 
] 

:彼らは彼らのモデルを表しChildComponentモジュールがあるニレ側でフォームport sendData : ((ComponentId, String) ...

のポートを介してデータを送信

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

明らかに、この結果in

Cannot find variable `componentId` 

310|  Sub.map (ChildMessage componentId) (ChildComponent.subscriptions (getChildModel (componentId model))) ] 
           ^^^^^^^^^^^ 

ポートからのデータから「componentId」を抽出するにはどうすればよいですか?あるいは、私がやっていることはまったく間違っていますか?

更新

私はSub.mapを使用している場合、あなたはそのパラメータとして子モデルを受け入れる機能を必要とするプロジェクトにhttps://github.com/lguminski/ElmMultipleComponentsSubscription

答えて

0

を(@ChadGilbertによって提案されたいくつかの追加で)問題を単離しました。代わりに、あなたの親サブスクリプション機能を更新する必要があります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 -> ... 

更新

自分の追加の詳細情報に基づいて、私はあなたが子供のモジュールから出て、親にポートと子メッセージルーティングを移動することを提案します。その後、親に次の更新例を追加することができます。

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 

I have created a pull request for your repository here

+0

感謝を! @ChadGilbert私たちはほとんどそこにいる。唯一の問題は複数の子供がいることです。あなたが提案したように、 'model.child'を先に提供することはできません。また、メッセージに基づいて動的に計算する必要があります。これを説明するためにhttps://github.com/lguminski/ElmMultipleComponentsSubscriptionを作成しました。 –

+0

私はあなたのデザインをわずかに変更して私の答えを更新し、実際の例を使ってあなたのコードにプルリクエストを作成しました。 –

+0

ありがとう@ChadGilbert。私は、あなたが子供の特定のコミュニケーション(ポートとサブスクリプション)を親のレベルに昇格させ、それを処理することがわかります。実際、これは私が子供の抽象化のリークとしてこれを認識するので、私が避けようとしたものです。私はChildにこれをすべてカプセル化する方法があることを期待していました。しかしおそらくそれは不可能です。私の質問を数日間開いてみましょう。誰も良いアイデアが出てこない場合は、有効な回避策として回答します。再度、感謝します。 –

関連する問題