2015-12-16 28 views
0

我在Elm中相當新。目前我正在嘗試使用該語言。雖然信號的使用看起來很複雜。下面是我的網頁的一個工作示例,它處理多個段落(添加,刪除,編輯...)。爲一個模型組合多個信號(使用Html.Events和Keyboard信號)

-- start 
main: Signal Html.Html 
main = Signal.map (view actions.address) model 

view: (Signal.Address Action) -> Model -> Html 
view address model = ... (displaying paragraphs with buttons, ect) 

這段代碼啓動模型。通過映射的操作使用Signal.map模型,我能夠從按鈕(導入的HTML +事件模塊)處理單擊事件

model: Signal Model 
model = Signal.foldp update makeEmptyModel actions.signal 

在這裏,我開始使用空模型。 update函數允許我在點擊按鈕事件後更新模型。

update: Action -> Model -> Model 
update action model = .... 

Action是處理我都喜歡「AddParagraph」,「RemoveParagraph」中定義多個操作的類型......

到目前爲止是這種情況。現在,當檢查包裹時,我發現Keyboard。這似乎很有趣,所以我想添加一個新的功能。如果用戶按下Alt + A,則選擇所有段落。 (像文件資源管理器中的Ctrl + A)

但是,它似乎並不容易與當前的信號映射相結合。我決定鑽進Signal,發現Signal.merge。所以我可以正確使用它?我試圖鍵盤信號合併到我的電流信號是

main = Signal.merge 
    (Signal.map (view actions.address) model) 
    (Signal.map (view actions.address) keysDown) 

(該keysDown爲import Keyboard exposing (keysDown)進口)

但是,這並不工作。我得到一個錯誤

The 2nd argument to function `map` is causing a mismatch. 
160│  Signal.map (view actions.address) keysDown) 
              ^^^^^^^^ 
Function `map` is expecting the 2nd argument to be: 
Signal { focused : Bool, selected : Bool, ... } 

But it is: 
    Signal (Set.Set Char.KeyCode) 

看來,使用Signal.merge時,它預計它處理同一個輸出多個信號。那麼這就是我想要。但似乎並不奏效。

問:如何將鍵盤信號添加到當前設計?

或者我錯了我的期望Signal.merge?我正在使用Signal.merge用於錯誤目的?我應該用Signal.map2代替嗎?如果是這樣,我怎麼能用我目前的例子*?還是有更好的方法?

  • 如果解決方案是map2,可以添加解釋嗎?那是因爲我不明白「MAP2」東西

回答

3

您發送到merge信號必須是同一類型的。您需要添加另一個功能,在合併之前將鍵盤輸入映射到Action

有幾種方法可以實現這一點。以下是使用基本計數器示例和Signal.merge的示例。重要的是,使用keyPressesToAction信號映射函數的

import Signal 
import Html exposing (..) 
import Html.Events exposing (..) 
import Keyboard 
import Char 

type Action = NoOp | Increment | Decrement 

actions : Signal.Mailbox Action 
actions = 
    Signal.mailbox NoOp 

update action model = 
    case action of 
    NoOp -> model 
    Increment -> model + 1 
    Decrement -> model - 1 

model = 
    Signal.foldp update 0 (Signal.merge actions.signal keyPressesToAction) 

keyPressesToAction = 
    let 
    keyCodeToAction keyCode = 
     case Char.fromCode keyCode of 
     '+' -> Increment 
     '-' -> Decrement 
     _ -> NoOp 
    in 
    Signal.map keyCodeToAction Keyboard.presses 

main = 
    Signal.map (view actions.address) model 

view address model = 
    div [] 
    [ button [ onClick address Decrement ] [ text "-" ] 
    , text <| toString model 
    , button [ onClick address Increment ] [ text "+" ] 
    ] 

的另一種方式,以實現所期望的結果是,通過使用專用於轉換按鍵來action信號port。這消除了合併信號的需要,因爲它會導致按鍵觸發您已經設置的郵箱。

在這種情況下,該功能model返回到它的方式,那麼我們添加下面稱爲triggerActionOnKeyPress的端口,其使用相同keyPressesToAction信號映射函數從上方。這裏是相關的行:

model = 
    Signal.foldp update 0 actions.signal 

port triggerActionOnKeyPress : Signal (Task.Task Effects.Never()) 
port triggerActionOnKeyPress = 
    Signal.map (Signal.send actions.address) keyPressesToAction 
+0

所以,我用'Signal.merge'不正確......但是,現在我無法添加段落。我有一個textarea,我可以插入文本。當我點擊按鈕時,它將文本添加到我創建的段落中。即使使用您的端口解決方案,我甚至無法將文本數據輸入到我的textarea。這是因爲keyPressesToAction的'_ - > NoOp'覆蓋了它。我如何確保只有按下Alt鍵才能發送信號?然後我可以使用Alt + A只需 – KarelG

+0

如果沒有看到您的代碼很難診斷。這聽起來像別的東西可能是錯的。處理按鍵信號不應該影響輸入文本框。 –

+0

我已經把你的例子(第一個代碼塊)放到了[在線編輯器](http://elm-lang.org/try)上,並且在那裏使用「+」和「 - 」鍵沒有工作。點擊這些按鈕然而工作。可能有些東西是不對的:) – KarelG