3
votes

Im using start-app to shape my application. Html.Events supports creating custom events with custom Signal.message. But how to send that message is abstracted behind the Html library. Also there is a library called which implements debouncing (http://package.elm-lang.org/packages/Apanatshka/elm-signal-extra/5.7.0/Signal-Time#settledAfter).

SearchBar.elm:

module PhotosApp.SearchBar (view) where

import Html exposing (input, div, button, text, Html)
import Html.Events exposing (on, onClick, targetValue)
import Html.Attributes exposing (value, type')

import Effects exposing (Effects, Never)

import PhotosApp.Actions as Actions

onTextChange : Signal.Address a -> (String -> a) -> Html.Attribute
onTextChange address contentToValue =
    on "input" targetValue (\str -> Signal.message address (contentToValue str))

view : Signal.Address Actions.Action -> String -> Html
view address model =
    div []
        [ input  [ type' "text", value model, onTextChange address Actions.Search] []
        , button [ onClick address Actions.Clear ] [text "Clear"]
        ]
1

1 Answers

2
votes

You can set up debouncing from an HTML attribute by going through a proxy mailbox before tying into @Apanatshka's settledAfter function.

(Note that since you're using StartApp, we don't have direct access to the main Address and therefore I've had to compromise a few of these functions by ignoring the address passed into view. You could get something more generalized by not using StartApp, but this should hopefully get you started)

Since event attributes cannot create tasks directly, we have to use an intermediate proxy mailbox. We can set that up like this:

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

Note that the above function expects a NoOp Action, common in Elm architecture, which just means the update function makes no changes to the model.

Now we need to set up another Signal which listens to the proxy mailbox, then passes the signal through the settledAfter function. We can define this signal like this:

debounce : Signal Action
debounce =
  settledAfter (500 * Time.millisecond) debounceProxy.signal

We can now change the onTextChange function to point at the proxy mailbox. Notice that I've taken out the first Address parameter since it's being ignored (see my earlier comment about conforming to StartApp):

onTextChange : (String -> Action) -> Html.Attribute
onTextChange contentToValue =
    on "input" targetValue (\str -> Signal.message debounceProxy.address (contentToValue str))

Lastly, you have to tie in the debounce signal into StartApp's inputs parameter, which means your call to start will look something like this:

app = StartApp.start
  { init = init
  , update = update
  , view = view
  , inputs = [ debounce ]
  }

I've pasted the full working example at a gist here.