2016-03-03 17 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

相關問題