2016-03-03 65 views
2

我只试过了Elm几天,并且遇到了我无法弄清楚的常见情况。如何将操作传递给Elm中的子组件

我有一个包含项目列表的父组件。为了呈现列表,我有一个子组件,父组件调用传递给地址和模型的子视图函数。由于Action类型不同,我认为编译器正在抱怨,但我真的不确定。

父组件:

type alias Model = List ToDoItem.Model 

type Action 
    = Remove Int 

update : Action -> Model -> Model 
update action model = 
    case action of 
    Remove id -> 
     List.filter (\todo -> todo.id /= id) model 

view : Signal.Address Action -> Model -> Html 
view address model = 
    let 
    buildToDos = 
     List.map (ToDoItem.view address) model 
    in 
    div [] [ buildToDos ] 

子组件:

type alias Model = 
    { id : Int 
    , name : String 
    , description : String 
    , complete: Bool 
    } 

type alias ID = Int 

type Action 
    = Toggle Bool 

update : Action -> Model -> Model 
update action model = 
    case action of 
    Toggle toggle -> 
     if toggle == True then 
      { model | complete = False } 
     else 
     { model | complete = True } 

view : Signal.Address Action -> Model -> Html 
view address model = 
    let 
    toggleText : Bool -> String 
    toggleText complete = 
     case complete of 
     True -> "Incomplete" 
     False -> "Complete" 

    in 

    div 
    [ class "wrapper" ] 
    [ span [] [ text ("[" ++ toString model.id ++ "]") ] 
    , span [ class "name" ] [ text model.name ] 
    , div [ class "description" ] [ text model.description ] 
    , a [ onClick address (Toggle model.complete)] [ text (toggleText model.complete)] 
    ] 

编译器错误:

-- TYPE MISMATCH ---------------------------------------------- 

The type annotation for `view` does not match its definition. 

20│ view : Signal.Address Action -> Model -> Html 
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
The type annotation is saying: 

    Address Action -> List ToDoItem.Model -> Html 

But I am inferring that the definition has this type: 

    Address ToDoItem.Action -> List ToDoItem.Model -> Html 

-- TYPE MISMATCH ---------------------------------------------- 

The 2nd argument to function `div` is causing a mismatch. 

26│  div [] [ buildToDos ] 
       ^^^^^^^^^^^^^^ 
Function `div` is expecting the 2nd argument to be: 

    List VirtualDom.Node 

But it is: 

    List (List Html) 

如何申报或者子组件的视图功能正常或传入参数从父母正确的孩子的视图功能?

实际上,我实际上并不想将任何操作传递给子组件 - 我只想渲染它。子组件中的动作是针对onClick的。

然后,也许我走了,因为这是我榆树生活的第二天。

回答

3

Elm Architecture Tutorial涵盖子视图问题。再看看示例4是如何实现的。

总之,你需要有一个封装了孩子动作父的动作:

type Action = Remove Int | ToDo Int ToDoItem.Action 

而且你需要在update这个动作转发到相应的项目。

view中,您需要为每个ToDoItem视图创建一个转发地址。

view : Signal.Address Action -> Model -> Html 
view address model = 
    let 
    fwd idx = Signal.forwardTo address (ToDo idx) 
    toDoList = 
     List.indexedMap (\(idx, m) -> ToDoItem.view (fwd idx) m) model 
    in 
    div [] toDoList 

请注意,您的旧buildToDos已经是一个列表,并说[buildToDos]实际上是说List (List Html)这就是为什么你得到了第二个错误。

+0

谢谢。我已经多次阅读过这个例子,但它似乎并不是我所需要的。我实际上并不需要将信号转发给子组件,因为它不需要知道有关父操作的任何信息。我不能用某种noOp或某种方式调用子视图fn吗? – BoxerBucks

+0

我能够根据这个答案找出问题。我刚刚创建了一个NoOp操作,其中包含一个与子组件操作关联的类似于我刚删除索引的类似操作,因为我不需要它。然后我通过Signal.forwardTo发送。我还不清楚的是信号如何流动。这是否需要与每个父母子女关系发生?行动总是需要被转发? – BoxerBucks

+1

如果ToDoItem具有自己的状态并且改变此状态的操作,那么这种委托在更新和转发视图中是必需的。 这主要是由一个单一的状态产生的。 [此图片](http://staltz.com/img/mvu-unidir-ui-arch.jpg)可以直观地展现榆树发生的事情。 有了Elm架构,人们很少使用信号。 StartApp中有一个很大的'Signal.foldp',很少有'inputs'信号,就是这样。 – pdamoc

0

编译器已经告诉过你答案。首先,

Address Action -> List ToDoItem.Model -> Html 这里的行动必须指定给儿童行动。刚修好它像编译器告诉你:

view : Signal.Address TodoItem.Action -> Model -> Html

第二个,因为您buildToDos已经是一个列表,你只需要: div [] buildToDos

花一些时间了解类型的注释,并严格遵循编译那么你应该能够自己解决这类问题。

+0

我以前试过。改变该类型签名的问题是我使用start-app,并且start-app期望Signal.Address是List ToDoItem.Model的类型。 – BoxerBucks