comment
WebSharper 4.1.1 is now available on NuGet, and as a vsix installer on the WebSharper website.
It contains enhancements and fixes to some client-server functionality introduced in WebSharper 4.1 (on.* server-side event handlers pre-compiling any form of quotation), special treatment of IsClient value for conditional compilation for server/client, and other bug fixes.
Documentation: WebSharper 4.1 for C# and WebSharper 4.1 for F#.
The release notes are also found on GitHub.
New features
- Server-side event handlers (
on.*) andClientSidecan take any fixed F# quotation now and translates it to JavaScript.
1 2 3 4 5
div [] [ text "div created on the server" ]
client
<@ JavaScript.Console.Log "running client-side code"
div [] [ text "div created on the client" ]
@>- The
IsClientvalue (WebSharper.Pervasives.IsClientfrom C#) and their negations (not IsClientand!Pervasives.IsClient) can be used as a condition in branching logic in shared client-server code to make the JavaScript compiler skip the false branch entirely.
1 2 3
// using WebSharper;
if (Pervasives.IsClient) { ClientSideMethod(); } else { ServerSideMethod(); }
var res = Pervasives.IsClient ? ClientSideMethod() : ServerSideMethod();1
if IsClient then ClientSideMethod() else ServerSideMethod()
New features in WebSharper.UI
- Added
Lensfunction to lens into aVarusing the.Vsyntax. Example usage:
1 2 3
Lens(myvar.V.MyField) // is equivalent to: myVar.LensAuto(fun x -> x.MyField)
1
This returns creates a `Var<T>` where `T` is the type of `MyField` record field, which gets and sets its value by updating the underlying `myVar`.
- Add
Var<list<T>>.MapLensand.DocLens, similar in functionality to theirListModelcounterpart, although with linear-time complexity. Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
type Person = { Id: int; Name: string; Age: int }
let people =
Var.Create (fun p -> p.Id) [
{ Id = 0; Name = "Ann"; Age = 34 }
{ Id = 1; Name = "Brian"; Age = 28 }
{ Id = 2; Name = "Clara"; Age = 43 }
]
let editPeople =
people.DocLens(fun k vp ->
form [] [
Doc.Input [] (Lens vp.V.Name)
Doc.IntInputUnchecked [] (Lens vp.V.Age)
]
)This ties the inputs to the values in people.Value (of type list<Person>), recreating the immutable list if any of the inputs are changed.
Fixes and improvements
- An empty F#
Mappassed to an RPC function is deserialized correctly. - The behavior of the
Stubattribute on constructors and static methods are now consistent with the documented translation logic since WebSharper 3.0. - Multiple server-side event handlers and
ClientSidehaving captured arguments within the same method do not interfere with each other. - The
clienthelper inWebSharper.UIis now available again within client-side code. So adiv [] [ client <@ div [] [] @> ]in server side-code will create the internaldivon the client (the server returning a placeholder) while fully running on the it just creates the internaldivbasically as ifclient <@ @>wrapper was not there. - Server-side event handlers and
ClientSidedo not create extra functions in translated JavaScript code if their expression is containing a single static method call. These functions in back-compatibility packageWebSharper.UI.Nextwork the same as in WebSharper 4.0. - Some quotation forms were missing when exploring for captured arguments inside server-side
on.*event handlers, including tuple gets (used by F# implicitly when passing captured a tuple value to a client-side function taking a tuple, resulting in a runtime failure). This is now working correctly:
1 2 3 4
let t = 1, 2
div [] [
button [ on.click (fun _ _ -> Client.TestTuple t) ] [ text "click me" ]
]






The DocLens functionality works pretty well, but the example has several errors. This is a corrected and more complete version: http://try.websharper.com/snippet/user3359/0000Jz
[<JavaScript>] module HelloWorld = let title txt = Attr.Create "title" txt type Person = { Id: int; Name: string; Age: int } let people = Var.Create [ { Id = 0; Name = "Ann"; Age = 34 } { Id = 1; Name = "Brian"; Age = 28 } { Id = 2; Name = "Clara"; Age = 43 } ] let getId p = p.Id let newId () = people.Value |> List.map getId |> List.max |> ((+) 1) let newPerson () = { Id = newId(); Name = ""; Age = 0 } let insertPerson () = people.Value <- newPerson() :: people.Value let appendPerson () = people.Value <- people.Value |> List.append <| [ newPerson() ] let deletePerson id () = people.Value <- people.Value |> List.filter (getId >> (<>) id) let editPeople () = people.DocLens(getId, fun vp -> form [] [ Doc.Input [] (Lens vp.V.Name) Doc.IntInputUnchecked [] (Lens vp.V.Age) Doc.Button "x" [ title "Remove person" ] (deletePerson vp.Value.Id) ] ) let Main = div [] [ Doc.Button "+" [ title "Insert person" ] insertPerson editPeople() text "----------------------- Again: -----------------------" editPeople() Doc.Button "+" [ title "Append person" ] appendPerson ] |> Doc.RunById "main"