If you don't need the data on the client after the page has loaded, you can just run your query and serve your page's initial view/HTML based on it (aka server-side rendering).

If you do need the data in your client model as well, you can use reactive vars to bind that view state instantly (for simple models), use some inlines to send your data as a JSON string with your HTML and read it back to a model (for larger models), or initiate an extra/parallel RPC call as you say to "sync" that data into your client model.

By on 12/3/2020 7:48 PM ()

Thanks a lot for the reply.

1. Reactive vars. I'm probably doing something wrong, but when I do this:
1
2
3
4
5
6
7
8
9

module Site =
open WebSharper.UI.Html

let myconst = Var.Create "flop"
let HomePage ctx =
Templating.Main ctx EndPoint.Home "Home" [
h1 [] [text "Say Hi to the server!"]
div [] [client <@ Client.Main myconst @>]
]

where Client.Main is a function in a module marked with [<JavaScript>], I get the "Method name not found in JavaScript compilation" error. Could you help me out with how to do this? Note: I'm getting the same error if I add the [<JavaScript>] attribute to the myconst declaration.

1. Use some inlines. I understand the concept for sure and I think this is what I'm looking for, but I'm not sure how I would do this in practice. Would I render the data into a comment? Or a script tag? Or something else entirely?

By on 12/4/2020 12:09 AM ()

In 1) you are getting an error message, because you are trying to use a reactive variable (which are client-side by design) in your server-side code (in a page served by a sitelet). The solution is to move myconst to Client.Main or into any other client-side namespace as part of your client-side model. Or better yet, just mark the UI controls you are sending from the server with your prefilled data with a ws-var=... attribute, and you can read those values back on the client using the matching reactive variable. If all goes well, the view state you assigned from the server should reflect back just fine.

In 2), you could convert your data to JSON on the server and pass it (as a string literal) to a hardcoded function (say, one you annotated with [<JavaScript>] in your F# code).

By on 12/4/2020 7:35 AM ()

Hey Adam, this works! Thanks a lot already. I tried to encapsulate this into a function, but the F# Compiler has been giving me some trouble. I'm not sure if this is fixable?

My component (as you can see, I already screwed around with the type parameters and inlining, etc)

1
2
3
4

let inline transferToClient< ^a > (toTransfer: ^a) (target: ^a Var) =
span [attr.data- "transfer" ((Json.Serialize< ^a > toTransfer).ToString()) ;
on.afterRender (fun el -> target.Set (Json.Decode< ^a > (Json.Parse (el.GetAttribute "data-transfer"))))
] []

Depending on how I use the type parameters and/or the inline attribute, I get the following error at compile time

1

WebSharper error FS9001: Macro 'WebSharper.ClientSideJson+Macro+SerializeMacro' requires a resolved type argument for type parameter index 0. Mark the member with the Inline attribute.

Or at Runtime:

1

System.Exception: Failed to look up translated field name for this in type Microsoft.FSharp.Core.FSharpFunc2 with fields:

For clarity I should mention this does 100% compile and run when I have this code inlined in my (serverside rendered) Doc, so without the function abstraction.

I'm an F# noob and this is already quite deep into the rabbit hole, but ok, this would be awesome to end my search. Even if there is no generic solution for this, I'm very impressed by WebSharper!

By on 12/5/2020 5:00 AM ()

Hi!

As the WebSharper error message suggests, adding an [<Inline>] attribute to your generic function with statically resolved type parameter might solve your issue. WebSharper's inlining is controlled separately from F# inline` with this attribute, and WebSharper is delaying macro executions that would use the type parameter.

By on 12/7/2020 10:41 AM ()