1

I have the following scenario:

when a user stops typing in the text area, I want to wait for 2 seconds and if the user didn't change anything in the textarea within those 2 seconds, I want to save the content of the textarea to the server. If the user changes something in the textarea within those 2 seconds, I want to restart the wait timeout.

In JavaScript, I would implement it something like this

http://codepen.io/ondrejsevcik/pen/LRxWQP

// Html
<textarea id="textarea"></textarea>
<pre id="server"></pre>

// JavaScript
var textarea = document.querySelector('#textarea');

var textValue = "";
textarea.oninput = function (e) {
  textValue = e.target.value;
  setSaveTimeout();
}

let saveTimeout;
function setSaveTimeout() {
  if (saveTimeout) {
    clearTimeout(saveTimeout);
  }
  saveTimeout = setTimeout(saveToServer, 2000);
}

function saveToServer() {
  document.querySelector('#server').innerText =
    'Value saved to server: ' + textValue;
}
ondrej
  • 967
  • 7
  • 26
  • 1
    [`Process.sleep`](http://package.elm-lang.org/packages/elm-lang/core/4.0.5/Process#sleep) is the `setTimeout` equivalent in Elm, apparently. I was able to find [this example](https://github.com/fredcy/example-elm-debounce/blob/master/Debounce.elm) of using it to debounce, but whether or not it's the best way, I'm not sure. – Joe Clay Sep 22 '16 at 10:27
  • 1
    Additionally, here is a thread from the usergroup discussing how to debounce: https://groups.google.com/forum/#!topic/elm-discuss/w4MwjIaTiIY – Joe Clay Sep 22 '16 at 10:29

1 Answers1

0

One way to achieve the behavior is to..

  1. Hook onInput event
  2. Within onInput handler, create a task which fires 2 sec later, with a current value of textarea. Also store the textarea contents.
  3. check if the value has changed or not, and save it if value did not change.

Here, it doesn't cancel the Task, so it may not be efficient.

-- MODEL
type alias Model =
  { str : String
  , saved : String
  }

init : (Model, Cmd Msg)
init =
  (Model "" "", Cmd.none)

-- UPDATE
type Msg
  = ChangeText String
  | Save String
  | NoOp ()

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    NoOp _ -> (model, Cmd.none)
    Save str ->
      let
        _ = Debug.log "save" str
        newmodel =
          if model.str /= str
          then model
          else { model | saved = str }
      in (newmodel, Cmd.none)    
    ChangeText str ->
      let
        _ = Debug.log "textarea" str
        cmd = Task.perform NoOp Save <|
          Process.sleep (2 * Time.second)
          `Task.andThen`
          \_ -> Task.succeed str
      in ({ model | str = str }, cmd)

-- VIEW
view : Model -> Html Msg
view model =
  Html.div []
  [ Html.textarea [ onInput ChangeText ] []
  , Html.div [] [ Html.text <| "saved: " ++ model.saved ]
  ]
Tosh
  • 35,955
  • 11
  • 65
  • 55