Skip to content

Instantly share code, notes, and snippets.

@newlandsvalley
Created March 2, 2016 12:30
Show Gist options
  • Save newlandsvalley/c3f67710eb9520768845 to your computer and use it in GitHub Desktop.
Save newlandsvalley/c3f67710eb9520768845 to your computer and use it in GitHub Desktop.
Disable a button in elm whilst the task which it kicks off is in flight
module Disable where
{-
This gist shows one method of temporarily disabling a button whilst a task (which it has kicked off)
is in flight. My need to do this comes from an audio 'play' button which kicks of an audio
'play sounds' task. Although the task returns immediately, I know the duration of the sound clip
so I suspend the UI whilst the clip is played. The trick is to split the 'play' task into two parts
so that the view has the chance to update in between them. The first action (Play) disables the button
and plays the clip, the second action (ShowButton) re-enables the button.
Many thanks to Max GoldStein and Dave Keen on elm-discuss for their helpful suggestions.
-}
import Effects exposing (Effects, Never, task)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import Task exposing (Task, andThen, succeed)
import String exposing (..)
import Debug exposing (..)
-- MODEL
type alias Model =
{
buttonDisabled : Bool
}
init : String -> (Model, Effects Action)
init topic =
( {
buttonDisabled = False
}
, Effects.none
)
-- UPDATE
type Action
= NoOp
| Play
| ShowButton
update : Action -> Model -> (Model, Effects Action)
update action model =
case (log "action" action) of
NoOp -> (model, Effects.none )
Play -> ({model | buttonDisabled = True } , play )
ShowButton -> ( {model | buttonDisabled = False } , Effects.none )
{- play the clip, supend the UI and then set the next action to ShowButton -}
play : Effects Action
play =
playAndSuspend
|> Task.map (\_ -> ShowButton)
|> Effects.task
{- play the task and suspend the UI -}
playAndSuspend : Task Never Action
playAndSuspend =
succeed (True) -- this task just simulates the player which actually returns immediately
`andThen` (\_ -> suspend 5)
{- sleep for a number od seconds -}
suspend : Int -> Task Never Action
suspend secs =
let
time = 1000 * secs
in
Task.sleep time
`andThen` (\_ -> succeed (NoOp))
{- just the ShowButton action wrapped in a Task -}
showButton : Task Never Action
showButton = succeed (ShowButton)
-- VIEW
view : Signal.Address Action -> Model -> Html
view address model =
div []
[
h1 [ bStyle ] [ text ("test disabling buttons - disabled " ++ toString model.buttonDisabled)]
, div
[ bStyle ]
-- I'm trying to wait a few seconds before disabling the button
[ button [ onClick address Play, disabled model.buttonDisabled ] [ text "play" ]
]
]
bStyle : Attribute
bStyle =
style
[
("text-align", "center")
, ("margin", "auto")
]
-- INPUTS
signals : List (Signal Action)
signals = []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment