How to initiate an event from update

I have a process that takes several seconds to complete, but I want to ensure that the user gets immediate feedback that what they’ve done was initiated. So, when they click on a active cell in a table for example, I want to highlight the cell, then trigger a new event that actually does the action. Looking at the docs it looked like Task.perform would do it, but for the life of me, I can’t figure out the syntax. In the doc it uses an example with Time.now, but that returns:

> import Time
> Time.now
<internals> : Task.Task x Time.Posix

Which looks like the doc says, but how does one use it?

I’m starting to wonder if maybe Task.perform isn’t the right tool. If it is, can somebody share an example of using it? Otherwise, how does one initiate an event programmatically?

Hi bwanab, when you say “trigger a new event that actually does the action”, I believe you mean “trigger a new Msg to be handled by the Update function which will then perform the real work of the action”.

Great question. This is a common design pattern: In response to a user event/message, you want to immediately update the model (and therefore the DOM) to provide immediate feedback to the user, but then you want to continue on with the actual work the user event/message represents.

And you were right on the money - use Task, but there is a bit of Task transformation you need to perform to turn it into a Cmd msg that can be sent to actually trigger the Msg that does the real work.

Here is some utility code that illustrates my preferred way of doing just that.:

performMessage : msg -> Cmd msg
performMessage msg =
    Task.perform identity <| Task.succeed msg

performMessages : List msg -> Cmd msg
performMessages msgs =
    Cmd.batch <| List.map performMessage msgs

Now simply return your next Msg (the one that does all the work) as a command and, using the TEA Msg => Update flow, Update will be called with your new Msg.

For example:

update msg model =
    case msg of
        …
        ClickedOnCell entity_id ->
            ( { model | cell_message = "Working on your request!" }
            , performMessage <| UpdateEntityMembers entity_id
            )
        UpdateEntityMembers entity_id ->
            let
                completed_work = lotsOfWorkHere entity_id
            in
            ({ model
                | cell_message = "All done!"
                , completed_work = completed_work
             }
            , Cmd.none
            )
        …

Hope that helps!

Thanks so much, Dirk. That did the trick. I’m going to have to do some serious thinking on how performMessage is turning

(a -> msg) -> Task Never a -> Cmd msg

into

Cmd msg

But, it does work as advertised!

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.