You can use View.WithInit or View.WithInitOption. WithInitOption gives a View whose initial value is None, and then Some <value_of_vResponse> as soon as vResponse gets a value.

1
2
3
4
5
6
vResponse
|> View.WithInitOption
|> Doc.BindView (function
    | None -> text "Please wait, db retrieval is running..."
    | Some response -> TableRetrieve response
)
By on 7/22/2019 4:12 AM ()

Cool, thanks, looks like the simplest solution

By on 7/22/2019 4:31 AM ()

This is what I've done. I use a fake View (that I will ignore, aside from loggin purposes) just to trigger the internal states. I need extended types...

1
type InternalTrigger = | Input of string | Output of ServerTradeResponse

... and manual triggering. Isn't it clumsy or awkward?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
let rvInput = Var.Create ""
let rvAsyncInput = Var.Create (Input "", false)
let submit = Submitter.CreateOption rvInput.View
let submitAsync = Submitter.Create  rvAsyncInput.View (Input "", false)
let ignoreView = submit.View.MapAsync(function
    | None -> async {
                rvAsyncInput.Update(fun (_,running) -> (Input "",running))
                submitAsync.Trigger ()
            }
    | Some str -> async {
                rvAsyncInput.Update(fun (_,running) -> (Input str,running))
                submitAsync.Trigger ()
            }
)
let vResponse =
    submitAsync.View.MapAsync(function
        | _, true -> async { return  NoInput "Please wait, db retrieval is running..."}
        | Input input, false when System.String.IsNullOrWhiteSpace input -> async { return  NoInput "No input"}
        | Input input, false-> async { 
                try
                    rvAsyncInput.Update(fun (_,_) -> (Input input,true))
                    submitAsync.Trigger ()
                    Console.Log("submitAsync triggered with: " + string input)
                    let! trades = Server.RetrieveTrades input 
                    rvAsyncInput.Update(fun (_,_) -> (Output trades,false))
                    submitAsync.Trigger ()
                    Console.Log("returning trades now!!!")
                    return trades
                with | e -> 
                    return Error  <| "Client side: " + e.Message
                }
        | Output trades, _ ->  async { 
                                Console.Log("I need to re-trigger the Output!!!")
                                return trades }
    )
Doc.Concat [
form [] [
        Doc.Input [attr.``type`` "number"; attr.``class`` "mt-1"; attr.``data-`` "role" "input" ;
        attr.``data-`` "prepend" "Retrieve data " ; attr.placeholder " by trade, cargo or cpty num"] rvInput
        Doc.Button "Retrieve from DB" [attr.``class`` "button success"] submit.Trigger
    ]
Doc.BindView (fun l -> Doc.Empty) ignoreView
Doc.BindView TableRetrieve vResponse
h2 [] [text "The response from the server is shown above"]

And, AFAICS, I'm forced to bind to fake internal view to an actual document (even if empty)

1
2
Doc.BindView (fun l -> Doc.Empty) ignoreView
Doc.BindView TableRetrieve vResponse

Is this an acceptable solution?
Maybe it is, if there are no better suggestions ¯\(ツ)

By on 7/22/2019 3:53 AM ()

Hi, I have experimented a bit, and found a weird issue:

http://try.websharper.com/snippet/JankoA/0000Od

Included that counter to show that a pending MapAsync halts the reactive rendering. This is definitely not intended, will investigate.

Workaround is to use a Var instead of vResponse and just run with Async.StartImmediate on click, and set the var when the result is back. But I will try to fix MapAsync, seems like it had been an issue since a while https://github.com/dotnet-websharper/ui/issues/75

By on 7/22/2019 4:13 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper