Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve behavior of setTimeout in Elm

Tags:

elm

An updated and simplified version of @wintvelt's answer is now:

delay : Time.Time -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.perform (\_ -> msg)

with the same usage


One thing that may not be obvious at first is the fact that subscriptions can change based on the model. They are effectively evaluated after every update. You can use this fact, coupled with some fields in your model, to control what subscriptions are active at any time.

Here is an example that allows for a variable cursor blink interval:

subscriptions : Model -> Sub Msg
subscriptions model =
    if model.showCursor
        then Time.every model.cursorBlinkInterval (always ToggleCursor)
        else Sub.none

If I understand your concerns, this should overcome the potential for handling unnecessary ticks. You can have multiple subscriptions of different intervals by using Sub.batch.


If you want something to happen "every x seconds", then a subscription like solution, as described by @ChadGilbert is what you need. (which is more or less like javascript's setInterval().

If, on the other hand you want something to happen only "once, after x seconds", then Process.sleep route is the way to go. This is the equivalent of javascript's setTimeOut(): after some time has passed, it does something once.

You probably have to make your own wrapper for it. Something like

-- for Elm 0.18
delay : Time -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.andThen (always <| Task.succeed msg)
  |> Task.perform identity

To use e.g. like this:

---
update msg model =
  case msg of
    NewStuff somethingNew ->
      ...

    Defer somethingNew ->
      model
      ! [ delay (Time.second * 5) <| NewStuff somethingNew ]

Elm 0.19:

To execute once and delay:

delay : Float -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.andThen (always <| Task.succeed msg)
  |> Task.perform identity

To execute a repeating task:

every : Float -> (Posix -> msg) -> Sub msg