elmdebouncing

Debounce with elm in let expressions


I’m tyring to understand why is this not working. I’m trying to debounce, but not a user event from view. By idea this should go into the continiuos flow, which will happen once, but every few seconds. Main idea of this architecture is that events might be triggered from various places, but it will happen only once. I have made a simple example app:

module Main exposing (main)

import Html exposing (Html)


import Html
import Process
import Task
import Debug
import Time
import Control exposing (Control)
import Control.Debounce as Debounce


main : Program Never Model Msg
main =
    Html.program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


type alias Model =
    { counter : Int
    , state : Control.State Msg
    }


init : ( Model, Cmd Msg )
init =
  { counter = 0, state = Control.initialState }
  ! [ delay (Time.second * 3) <| ContinuousDebouncing ]


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none


type Msg
    = Deb (Control Msg)
    | ContinuousDebouncing


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of

        Deb debMsg ->
            Control.update (\s -> { model | state = s }) model.state debMsg

        ContinuousDebouncing ->
            let
                x = Debug.log "ContinuousDebouncing"
                _ = debounce ContinuousDebouncing
            in
                ( { model | counter = model.counter + 1 }, Cmd.none )


debounce : Msg -> Msg
debounce =
    let
        x = Debug.log "debounce"
    in
        Debounce.trailing Deb (3 * Time.second)


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


view : Model -> Html Msg
view model =
    Html.text (toString model.counter)

https://ellie-app.com/tvQ3L6dGrqa1


Solution

  • In your example app, you only fired the ContinuousDebouncing msg once in the init function, so as expected, the counter only increments once. You probably want to fire ContinuousDebouncing again in the update function.

    I think this achieves what you're after:

    module Main exposing (main)
    
    import Html exposing (Html)
    
    
    import Html
    import Process
    import Task
    import Debug
    import Time
    import Control exposing (Control)
    import Control.Debounce as Debounce
    
    
    main : Program Never Model Msg
    main =
        Html.program
            { init = init
            , view = view
            , update = update
            , subscriptions = subscriptions
            }
    
    
    type alias Model =
        { counter : Int
        , state : Control.State Msg
        }
    
    
    init : ( Model, Cmd Msg )
    init =
      { counter = 0, state = Control.initialState }
      ! [ incrementCounter ]
    
    incrementCounter : Cmd Msg
    incrementCounter = Cmd.map debounce <| delay (Time.second * 3) <| ContinuousDebouncing
    
    subscriptions : Model -> Sub Msg
    subscriptions model =
        Sub.none
    
    
    type Msg
        = Deb (Control Msg)
        | ContinuousDebouncing
    
    
    update : Msg -> Model -> ( Model, Cmd Msg )
    update msg model =
        case msg of
    
            Deb debMsg ->
                Control.update (\s -> { model | state = s }) model.state debMsg
    
            ContinuousDebouncing ->
                let
                    x = Debug.log "ContinuousDebouncing"
                in
                    ( { model | counter = model.counter + 1 }, incrementCounter )
    
    
    debounce : Msg -> Msg
    debounce =
        let
            x = Debug.log "debounce"
        in
            Debounce.trailing Deb (3 * Time.second)
    
    
    delay : Time.Time -> msg -> Cmd msg
    delay time msg =
      Process.sleep time
      |> Task.andThen (always <| Task.succeed msg)
      |> Task.perform identity
    
    
    view : Model -> Html Msg
    view model =
        Html.text (toString model.counter)
    

    https://ellie-app.com/tPymgfNwYda1