Skip to content

Commit

Permalink
Merge pull request #224 from TimLariviere/cmd-option
Browse files Browse the repository at this point in the history
Optional commands (Cmd.ofMsgOption / Cmd.ofAsyncMsgOption)
  • Loading branch information
TimLariviere committed Nov 7, 2018
2 parents 00ae5a5 + 9489ba4 commit e6407ce
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
42 changes: 42 additions & 0 deletions docs/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,45 @@ let backgroundCmd =
return msg
})
```

Optional commands
------

There might be cases where before a message is sent, you need to check if you want to send it (e.g. check user's preferences, ask user's permission, ...)

Fabulous has 2 helper functions for this:

- `Cmd.ofMsgOption`

```fsharp
let autoSaveCmd =
match userPreference.IsAutoSaveEnabled with
| false -> None
| true ->
autoSave()
Some Msg.AutoSaveDone
let update msg model =
match msg with
| TimedTick -> model, (Cmd.ofMsgOption autoSaveCmd)
| AutoSaveDone -> ...
```

- `Cmd.ofAsyncMsgOption`

```fsharp
let takePictureCmd = async {
try
let! picture = takePictureAsync()
Some (Msg.PictureTaken picture)
with
| exn ->
do! displayAlert("Exception: " + exn.Message)
None
}
let update msg model =
match msg with
| TakePicture -> model, (Cmd.ofAsyncMsgOption takePictureCmd)
| PictureTaken -> ...
```
16 changes: 16 additions & 0 deletions src/Fabulous.Core/ElmishCmd.fs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ module Cmd =
let ofMsg (msg:'msg) : Cmd<'msg> =
[fun dispatch -> dispatch msg]

/// Command to issue a specific message, only when Option.IsSome = true
let ofMsgOption (msg:'msg option) : Cmd<'msg> =
[ fun dispatch ->
match msg with
| None -> ()
| Some msg -> dispatch msg ]

/// When emitting the message, map to another type
let map (f: 'a -> 'msg) (cmd: Cmd<'a>) : Cmd<'msg> =
cmd |> List.map (fun g -> (fun dispatch -> f >> dispatch) >> g)
Expand All @@ -35,8 +42,17 @@ module Cmd =

let dispatch d (cmd: Cmd<_>) = for sub in cmd do sub d

/// Command to issue a message at the end of an asynchronous task
let ofAsyncMsg (p: Async<'msg>) : Cmd<'msg> =
[ fun dispatch -> async { let! msg = p in dispatch msg } |> Async.StartImmediate ]

/// Command to issue a message at the end of an asynchronous task, only when Option.IsSome = true
let ofAsyncMsgOption (p: Async<'msg option>) : Cmd<'msg> =
[ fun dispatch -> async {
let! msg = p
match msg with
| None -> ()
| Some msg -> dispatch msg } |> Async.StartImmediate ]

//let ofAsyncMsgs p : Cmd<_> =
// [ fun dispatch -> p |> AsyncSeq.iter dispatch |> Async.StartImmediate ]
Expand Down

0 comments on commit e6407ce

Please sign in to comment.