By Loïc Denuzière on Wednesday, September 2, 2015 — 0 comments

WebSharper 3.4.14 released Core team

We are happy to announce the availability of WebSharper 3.4.14, which you can download here. Here are the main highlights of this release.

ASP.NET-hosted OWIN

Previously, a bug prevented the WebSharper.Owin middleware from running on top of ASP.NET using Microsoft.Owin.Host.SystemWeb. This has now been solved, and the following is now possible:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
open global.Owin
open Microsoft.Owin
open WebSharper
open WebSharper.Owin

module Site =
    let Main = Application.SinglePage(fun ctx -> Content.Text "Hello world!")

type Startup() =
    member this.Configuration(app: IAppBuilder) =
        app.UseSitelet(System.Web.HttpRuntime.AppDomainAppPath, Site.Main)
        |> ignore

[<assembly:OwinStartup(typeof<Startup>)>]
do ()

For this you need to install the following NuGet packages in your web application: WebSharper, WebSharper.Owin, Microsoft.Owin.Host.SystemWeb and Mono.Cecil.

On the topic of Owin, the Suave team recently pre-released support for running Owin middleware; we will soon publish a blog entry about running WebSharper applications within Suave.

WebSharper UI.Next

A number of new features have also been added to UI.Next.

Data binding: abstract references and lenses

Until now, UI.Next interactive elements such as Doc.Input were only able to interact directly with a Var of primitive type. This was quite limiting in terms of how you could structure your data at the root of the dataflow graph. For example, if you wanted to have a ListModel with a record type for items, and display it with input fields to edit the individual record fields, then those record fields would need to have type Var<'T> themselves.

The new abstract reference type IRef<'T> relieves this restriction. IRef<'T> is an interface type that represents data that can be directly read or written, or observed by a View<'T>. Conceptually, that's exactly what Var<'T> is, and of course Var<'T> implements this interface; but not only. There are now methods on Var<'T> and ListModel<'K, 'T> that return IRef<'U>s where 'U represents a part of the original 'T. This concept is called lensing. For example:

1
2
3
4
5
6
7
8
type Person = { FirstName: string; LastName: string; Id: Key }

let me : Var<Person> =
  Var.Create { FirstName = "Loïc"; LastName = "Denuzière"; Id = Key.Fresh() }
let myFirstName : IRef<string> =
  me.Lens (fun p -> p.FirstName) (fun p n -> { p with FirstName = n })
let myFirstNameInput =
  Doc.Input [] myFirstName

In the above code, myFirstName is an IRef<string> that lenses into the FirstName field of me. Retrieving myFirstName's value retrieves the FirstName field of the current value of me, and setting myFirstName performs a record update on the current value of me. It is therefore possible to create an input field that is bound to the FirstName field of me. Note how the type Person is able to be entirely immutable.

Even more useful is lensing into ListModels. See for example the following editable list of people:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let people = ListModel.Create (fun p -> p.Id) []
let firstNameOf : Key -> IRef<string> =
  people.LensInto (fun p -> p.FirstName) (fun p n -> { p with FirstName = n })
let lastNameOf : Key -> IRef<string> =
  people.LensInto (fun p -> p.LastName) (fun p n -> { p with LastName = n })
let displayPeople =
  ul [
    people.View |> Doc.ConvertSeqBy people.Key (fun pid person ->
      li [
        Doc.Input [] (firstNameOf pid)
        Doc.Input [] (lastNameOf pid)
      ]
    )
  ]

Creating a lensed reference is currently somewhat awkward, since you have to provide both the get and update functions. We are planning on providing a macro that will be able to infer the update function based on the getter function, making lenses more convenient to use.

Submitters

A simple way to allow the dataflow to react to isolated events is to have a view whose value is taken from an input view, but only gets updated when events occur. This was already possible using View.SnapshotOn, but somewhat more involved than it needed to be. The new type Submitter<'T> simplifies this task:

1
2
3
4
5
6
7
8
9
10
let rvInput = Var.Create "the input data"
let submit = Submitter.Create rvInput.View "no data submitted yet"
div [
  Doc.Input [] rvInput
  Doc.Button "Submit" [] submit.Trigger
  p [
    text "You entered: "
    textView submit.View
  ]
]

Other UI.Next features

  • Add some instance equivalents to static members: the functions View.Map, View.Bind and ListModel.View are now available as instance members on the corresponding types, allowing slightly shorter code for those who prefer this style.

  • ListModel.Key: both as a static and instance member, retrieves the function that is used by a ListModel to get the key of an item. Typically needed by View.Convert*By or Doc.Convert*By (see the lens example above).

  • Doc.BindView: it is rare, when inserting a dynamic doc using Doc.EmbedView, to have a View<Doc> handy; instead, you generally have a View<'T> that needs to be mapped to a View<Doc>. The new function Doc.BindView : ('T -> Doc) -> View<'T> -> Doc combines these two steps in a single function call.

  • Event handlers that can use a View's current value: it is fairly common to need the current value of a reactive View inside the callback of an event handler. It is now very easy to do so using the function Attr.HandlerView, or methods such as on.clickView.

  • Templating: allow an element to be both a hole and a subtemplate. This is useful for example when the hole is to be filled with a list of items, and the subtemplate describes how these items will be displayed.

  • doc.On* methods for standard events have been added, akin to the on.* attributes. They also exist in server-side friendly version, taking a quotation as argument.

  • on.* attributes have been converted to camelCase; for example, on.animationend is now on.animationEnd.

Bug fixes

  • #464: Fixed the client-side JSON encoding of option<_> union case arguments.

  • #463: Track dependencies from the body of [<Macro>]-annotated functions.

  • Fixed the type of JQuery.Position fields from int to float.

  • UI.Next#28: correctly map from string the value of Doc.IntInput and Doc.FloatInput.

Future plans

As mentioned in previous blog entries, our intention is to merge UI.Next into the main WebSharper distribution and to obsolete Html.Client and Html.Server. We are planning to have this done for version 3.5.

At the same time, we are starting to implement UI.Next-based Formlets and Piglets. Piglets are pretty much usable already, while Formlets are still in a more early phase. In both cases, we are seeing huge gains compared with the IntelliFactory.Reactive-based counterparts in terms of code simplicity and safety. Look forward to being able to use Piglets and Formlets within UI.Next!

Happy coding!

By Adam Granicz on Tuesday, September 1, 2015 — 0 comments

Live F# coding and snippets with dependencies in Try WebSharper Core team

Try WebSharper reached an important milestone today: we just released the first bits of on-the-fly typechecking and code completion, and you can now develop F# web snippets, without any installation, online more easily than ever.

Here is what it looks like:

You don't have to do anything fancy, just start typing and the type checker will guide you, including code completion with Ctrl+Space as you would expect. When you are ready to run your snippet, hit Run and you will see your snippet run in the Result panel.

Snippets with dependencies

You may also notice the little gear icon in the F# source tab, with that, now you can set up dependencies for your snippet. Currently, we support a wide range of WebSharper extensions, with more coming soon:

Type

Packages

Charting

WebSharper.Charting, WebSharper.ChartJs

Visualization

WebSharper.D3, WebSharper.Google.Visualization

3D graphics

WebSharper.GlMatrix, WebSharper.O3D

Mobile UIs/apps

WebSharper.SenchaTouch, WebSharper.MaterialUI

WebSharper abstractions

WebSharper.Formlets, WebSharper.Piglets

Reactive development

WebSharper.React, WebSharper.UI.Next

We will add third-party extensions shortly, including a variant of FSharp.Data to enable data-aware snippets that communicate with web services, etc.

Even more enhancements will be coming shortly, until then happy coding!

By Frank Joppe on Friday, August 28, 2015 — 0 comments

FSharpArm - part 2 Community

Read the previous article: FSharpArm - part 1 As the previous article was "current-status". Progress brought new insights, and so the following corrections apply:I develop in VS2015 under Windows, so I didn’t need to install Akka.Net on the RPi; installing fsharp for Debian/Ubuntu Linux is enough; The Self-Hosted Websharper template does not work -fully- as was described, see below; Control Panel [...]
>> Read the full article on fjoppe.weebly.com
By István Gansperger on Wednesday, August 26, 2015 — 0 comments

Try WebSharper: update notes for snippets Community

A new version of Try WebSharper just hit the live site featuring update notes to complement the addition of updates from the last release along with some quality of life changes.

  1. When updating your snippet you can now specify notes regarding that specific update. This is similar to the description field with the intent of only showing what changes were made and why. Later we might compile all the notes from the previous versions and show them all for a given snippet.

    which will show up under the description in the next version:

  2. We now have previous and next links on the embed page as well meaning you can switch between versions in an embedded snippet.

  3. You can use WebSharper.React and WebSharper.MaterialUi in your snippets. The extensions have not been publicly released yet so you can access them only on Try WebSharper!

  4. Extensions have been updated to the latest versions which means bugfixes — most notably UI.Next enhancements — and other improvements!

Happy sharing!

By Adam Granicz on Wednesday, August 19, 2015 — 0 comments

Try WebSharper: snippet versioning, gist import, and other enhancements now available Core team

A new Try WebSharper is out adding a couple handy new features and addressing a couple annoyances, making it even more easy to publish your F# and WebSharper snippets. The picture below depicts the main areas of change:

  1. Creating snippets from GitHub gists - You can now easily import a gist, all you have to do is hover over the (+) button in the bottom right corner, hit the GitHub icon and give your gist URL.

  2. Versioning snippets - You can now track different versions of and updates to any given snippet by switching stepping back and forth using the < and > arrows in the main menu. By default, when you visit a snippet you see its latest version, unless the URL includes the exact version (0 being the oldest), such as http://try.websharper.com/snippet/adam.granicz/00002I/1.

  3. Proper indentation support - You may have noticed earlier that highlighting a block of text and hitting Tab or Shift+Tab doesn't exactly behave in a friendly manner: it wipes the selected text instead of indenting. This is now fixed and you get the usual indentation behaviour you'd expect.

  4. Easy embed links - If you need to embed a snippet or "run" it outside of Try WebSharper, you can now easily get those links by following the direct links on the Embed tab.

Keep an eye on this blog and follow @trywebsharper for more awesome upcoming features.

Happy sharing!

By Adam Granicz on Sunday, August 9, 2015 — 4 comments

Share and embed Try WebSharper snippets Core team

Just four days ago we released Try WebSharper, and here we go with the first feature enhancement: embedding snippets. A huge thanks to Don Syme for suggesting it.

Each snippet and example now has an Embed tab, giving you the links or the HTML code for embedding it:

For instance, the snooker example you can play here directly.

You can also view it as an embedded content here, giving you the original source code.

With more features coming soon, we hope you enjoy experimenting and sharing your best F# web programming snippets.

Happy sharing!

By Frank Joppe on Friday, August 7, 2015 — 0 comments

FSharpArm - part 1 Community

I know what's like in the summertime, a bit quiet, so I thought it would be fun to build a Robot Arm, and to control it from a Raspberry Pi using self written F# software. Project goals are: have fun, learn some, and if possible, do a "Sean's dad" trick: inspire a kid.The ingredients are: One Raspberry Pi 2B (quad core!) plus accessories (power, network cable, HDMI cable), a clean Micro SD card (cat 10) with adaptor, a USB keyboard, a MeArm robot arm, four Servo motor cord extensions (3x10cm 1x[...]
>> Read the full article on fjoppe.weebly.com
By Adam Granicz on Thursday, August 6, 2015 — 0 comments

New WebSharper templates Core team

The recent release of WebSharper 3.4 also brought an update to most of the project templates shipped for Visual Studio, MonoDevelop, and Xamarin Studio.

As a quick glance, here is the template client-server (both UI.Next and the older Html type) application, with two simple pages (Home and About), demonstrating how to use master templates and how to make client-server calls.

While the templates organize client and server aspects into separate files (Client.fs, Remoting.fs, Main.fs), here is all the code you need in a single file for the above application (the master template Main.html is not listed here):

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
namespace MyApplication

open WebSharper
open WebSharper.Sitelets
open WebSharper.UI.Next
open WebSharper.UI.Next.Server

type EndPoint =
    | [<EndPoint "/">] Home
    | [<EndPoint "/about">] About

module Server =

    [<Rpc>]
    let DoSomething input =
        let R (s: string) = System.String(Array.rev(s.ToCharArray()))
        async {
            return R input
        }

[<JavaScript>]
module Client =
    open WebSharper.UI.Next.Client
    open WebSharper.UI.Next.Html

    let Start input k =
        async {
            let! data = Server.DoSomething input
            return k data
        }
        |> Async.Start

    let Main () =
        let input = inputAttr [attr.value ""] []
        let output = h1 []
        div [
            input
            buttonAttr [
                on.click (fun _ _ ->
                    async {
                        let! data = Server.DoSomething input.Value
                        output.Text <- data
                    }
                    |> Async.Start
                )
            ] [text "Send"]
            hr []
            h4Attr [attr.``class`` "text-muted"] [text "The server responded:"]
            divAttr [attr.``class`` "jumbotron"] [output]
        ]

module Templating =
    open WebSharper.UI.Next.Html

    type MainTemplate = Templating.Template<"Main.html">

    // Compute a menubar where the menu item for the given endpoint is active
    let MenuBar (ctx: Context<EndPoint>) endpoint : Doc list =
        let ( => ) txt act =
             liAttr [if endpoint = act then yield attr.``class`` "active"] [
                aAttr [attr.href (ctx.Link act)] [text txt]
             ]
        [
            li ["Home" => EndPoint.Home]
            li ["About" => EndPoint.About]
        ]

    let Main ctx action title body =
        Content.Doc(
            MainTemplate.Doc(
                title = title,
                menubar = MenuBar ctx action,
                body = body
            )
        )

module Site =
    open WebSharper.UI.Next.Html

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

    let AboutPage ctx =
        Templating.Main ctx EndPoint.About "About" [
            h1 [text "About"]
            p [text "This is a template WebSharper client-server application."]
        ]

    [<Website>]
    let Main =
        Application.MultiPage (fun ctx endpoint ->
            match endpoint with
            | EndPoint.Home -> HomePage ctx
            | EndPoint.About -> AboutPage ctx
        )

Future plans

We are planning to introduce additional tools to create WebSharper projects via these standard and other templates without needing the corresponding Visual Studio or Xamarin Studio plugins/extensions installed. This will make it super-easy to create WebSharper projects from within any context, IDE, or OS. Keep an eye on this blog for upcoming announcements.

Happy coding!

By Adam Granicz on Tuesday, August 4, 2015 — 0 comments

Introducing Try WebSharper Core team

We are thrilled to announce the availability of Try WebSharper, a simple and fun way to create and share WebSharper snippets with others!

The code you share can be run (=>Run) right in your browser, and you get basic type checking with warnings and errors showing up as red/yellow squiggles. Currently, this takes a couple seconds to complete so it's not the most convenient way to experiment, but it will get a lot better soon.

We aim to keep this site current with upcoming WebSharper releases, so you can use it to experiment with even the newest WebSharper features, including reactive markup and templating via UI.Next.

Converting F# snippets to WebSharper

While Try WebSharper is intended primarily for sharing WebSharper snippets (e.g. F# snippets that produce web output), you can also convert simple F# snippets by following a few simple steps.

Say, you wanted to run the following:

1
2
3
open System

sprintf "Time now is %s" (DateTime.Now.ToShortTimeString())

First, it helps to understand that snippets are not simply run as written in F#; they are converted to JavaScript with WebSharper and executed in your browser. For this, we use the single-page application (SPA) WebSharper template. This takes a master HTML document (index.html - and you can write to this file on the second tab) that references the JavaScript code generated from your F# code.

Using JS.Alert

In order for this to have a visible effect, you could simply raise a JavaScript popup with your output:

1
2
3
4
5
6
7
8
open System
open WebSharper
open WebSharper.JavaScript

[<JavaScript>]
let Main =
    sprintf "Time now is %s" (DateTime.Now.ToShortTimeString())
    |> JS.Alert

Note that you will always need to open WebSharper for the [<JavaScript>] attribute and other WebSharper pervasives, and it's also handy to open WebSharper.JavaScript for client-side/EcmaScript functions like JS.Alert.

Caveat

You may be tempted to throw away the name of the top-level binding, but this will yield no output due to let _ = ... being interpreted as do ... - which acts as a module initializer (instead of a top-level binding) that currently is not translated to JavaScript by WebSharper.

1
2
[<JavaScript>]
let _ =  ...

Using WebSharper.Html.Client

Another thing you can do is to show it in the markup that is rendered from index.html as your output. Note, that by default this document has a div node with id=main, which you can write to using the AppendTo member on any HTML.Client element.

1
2
3
4
5
6
7
8
9
open System
open WebSharper
open WebSharper.JavaScript
open WebSharper.Html.Client

[<JavaScript>]
let Main =
    Div([Text (sprintf "Time now is %s" (DateTime.Now.ToLongTimeString()))])
       .AppendTo "main"

Here, you are opening WebSharper.Html.Client for accessing client-side HTML functions like Div.

Using WebSharper.UI.Next

If you followed our recent announcements for WebSharper 3.4, you will likely prefer to do the above via the more flexible reactive HTML language introduced via UI.Next. Here is how that goes:

1
2
3
4
5
6
7
8
9
open System
open WebSharper    
open WebSharper.UI.Next.Html
open WebSharper.UI.Next.Client

[<JavaScript>]
let Main =
    div [text (sprintf "Time now is %s" (DateTime.Now.ToLongTimeString()))]
    |> Doc.RunById "main"

So all in all, these should give you three different strategies to convert F# snippets into WebSharper ones.

Site features and plans

As a code snippets site, Try WebSharper has the usual toolset for snippets: you can create a new snippet by hitting the big red plus (+) button in the bottom right corner, fork an existing snippet (=>Fork), or save the one you are working on (=>Save).

We also added a basic set of examples (with more being moved from WebSharper examples), which you can find under the hamburger icon, along with any saved snippets you may have:

Coming up

In future releases, we will be introducing additional functionality to help with "templating" basic snippets using any one of the above methods, spinning up snippets via GitHub gists, and lighting up much more refined code assistance services (code completion, type checking as you type, hover comments and signatures, etc.)

Happy sharing!

By Loïc Denuzière on Monday, August 3, 2015 — 3 comments

WebSharper UI.Next 3.4: the new HTML syntax Core team

As its name suggests, UI.Next was created to be the next-generation standard library for UI programming in WebSharper. As a consequence, as of WebSharper 4.0, UI.Next will be merged into WebSharper itself under a less "codenamey" moniker that we haven't decided yet. It will completely obsolete the current Html.Client and Html.Server.

The recently released version 3.4 prepares the terrain for this merger. It streamlines the embedded markup syntax, introduces server-side capability and adds client-side functionality.

Streamlined syntax

WebSharper UI.Next 3.4 overhauls the syntax for embedding HTML elements in F# for enhanced readability and familiarity.

The most visible change is the switch to lowercase elements and attributes, making UI.Next code more similar to what you would write in an HTML file. For elements, the function Div0 which creates a <div> tag with child elements becomes simply div, and Div which creates a <div> tag with attributes and child elements becomes divAttr. For attributes, the class attr contains static methods to create standard attributes and on creates event handlers. Here is a list of the new constructors available under WebSharper.UI.Next.Html:

New syntax

Old / Verbose syntax

divAttr [attrs...] [children...]

Div [attrs...] [children...]

div [children...]

Div0 [children...]

text "Hello"

Doc.TextNode "Hello"

textView aView

Doc.TextView aView

Needs open WebSharper.UI.Next.Client

attr.color "black"

Attr.Create Attributes.Color "black"

attr.colorDyn aView

Attr.Dynamic Attributes.Color aView

Needs open WebSharper.UI.Next.Client

attr.colorDynPred aView aBoolView

Attr.DynamicPred Attributes.Color aBoolView aView

Needs open WebSharper.UI.Next.Client

attr.anim aView aFunc aTrans

Attr.Animated aTrans aView aFunc

Needs open WebSharper.UI.Next.Client

See "Tier-specific functionality" below for the rationale behind needing open WebSharper.UI.Next.Client for some of these.

Here is a small code sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// New syntax                              │ /// Old syntax
open WebSharper.UI.Next                     │ open WebSharper.UI.Next
open WebSharper.UI.Next.Html                │ open WebSharper.UI.Next.Html
open WebSharper.UI.Next.Client              │
                                            │
let myDocument =                            │ let myDocument =
  let rvInput = Var.Create ""               │   let rvInput = Var.Create ""
  div [                                     │   Div0 [
    h1 [text "A small example"]             │     H10 [Doc.TextNode "A small example"]
    label [text "Type something here: "]    │     Label0 [Doc.TextNode "Type something here: "]
    Doc.Input [] rvInput                    │     Doc.Input [] rvInput
    pAttr [attr.``class`` "paragraph"] [    │     P [Attr.Create Attributes.Class "paragraph"] [
      text "You typed: "                    │       Doc.TextNode "You typed: "
      textView rvInput.View                 │       Doc.TextView rvInput.View
    ]                                       │     ]
  ]                                         │   ]

Server-side markup

It is now possible to use the Doc type, and the above syntax, to create server-side markup, ie. markup that is generated on the server and output in the HTML document, as opposed to client-side markup, generated dynamically in JavaScript.

Returning a server-side Doc as content

There are two ways to use a Doc as server-side content:

  • Use Content.Doc to create a Sitelets Content<_> value:

    1
    2
    3
    4
    5
    6
    7
    8
    
    open WebSharper.Sitelets
    open WebSharper.UI.Next
    open WebSharper.UI.Next.Server
    
    [<Website>]
    let MyWebsite =
      Application.SinglePage <| fun context ->
        Content.Doc myDocument
  • Convert it to Html.Server elements using Doc.AsElements:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    open WebSharper.Sitelets
    open WebSharper.UI.Next
    open WebSharper.UI.Next.Server
    
    [<Website>]
    let MyWebsite =
      Application.SinglePage <| fun context ->
        Content.Page(
          Body = Doc.AsElements myDocument
        )

Including client-side markup

In order to include a client-generated Doc inside a server-side Doc, you can use the function client. This function is analogous to ClientSide from Html.Server: it takes a quotation of a top-level, [<JavaScript>]-annotated function and includes it in server-side markup.

You can also add event handlers on server-side Docs using the methods in the on class. These methods take a quotation of a top-level, [<JavaScript>]-annotated function and return an Attr value that sets the handler as a static attribute on the element. This means that only one handler of a given type can be added to an element this way: you can't have two instances of eg. on.click <@ ... @> on the same server-side Doc.

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
open WebSharper
open WebSharper.UI.Next
open WebSharper.UI.Next.Html

[<JavaScript>]
module Client =
  open WebSharper.JavaScript
  open WebSharper.UI.Next.Client
  
  let Widget() =
    let rvInput = Var.Create ""
    Doc.Concat [
      Doc.Input [] rvInput
      p [text "You typed: "; textView rvInput.View]
    ]
    
  let Alert el ev =
    JS.Alert "Clicked!"

module Server =
  open WebSharper.Sitelets
  open WebSharper.UI.Next.Server

  [<Website>]
  let MyWebsite =
    Application.SinglePage <| fun context ->
      Content.Doc(
        div [
          h1 [text "Enter text below"]
          client <@ Client.Widget() @>
          buttonAttr [on.click <@ Client.Alert @>] [text "Click me!"]
        ]
      )

Tier-specific functionality

Some Doc functionality is only available on the client, or only on the server. To use such functionality, you need to open WebSharper.UI.Next.Client or WebSharper.UI.Next.Server, respectively.

The following is only available on the client side, and will raise a runtime error if used from the server side:

  • Reactive elements and attributes: textView, Doc.EmbedView, attr.*Dyn, attr.*DynPred, attr.*Anim, Doc.Convert*, reactive form elements (Doc.Input, etc).
  • Doc.Run, Doc.RunById, Doc.AsPagelet
  • on.* event handlers taking a function as argument. On the server you must use the version taking a quotation as argument.
  • Element methods and properties described below in "New client-side functionality".

The following is only available on the server side, and will raise a compile-time error if used from the client side:

  • Content.Doc, Doc.AsElements, Attr.AsAttributes.

New client-side functionality and the Elt type

One challenge in entirely replacing Html.Client with Doc is that existing applications using Html.Client should be convertible without requiring a complete change in paradigm. This means that we need to add as much of the imperative capabilities of Html.Client to Doc as possible. However, a Doc value is not guaranteed to be composed of a single root element, so accessing the element to perform actions such as SetAttribute or Append cannot be guaranteed to succeed. To fix this, we made the following change to the API.

The Doc type is now an abstract class, and there is a new type Elt that inherits from it and represents docs that are guaranteed to be composed of a single root element. The following functions return an Elt:

  • Element constructors, such as div and divAttr.
  • Doc.Element, Doc.SvgElement, Doc.Static.
  • Form input element constructors: Doc.Input, Doc.Button, etc.

Values of type Elt, in addition to being Docs, also have the following properties and methods (non-exhaustive list):

  • Dom returns the underlying Dom.Element.
  • Append(doc) and Prepend(doc) add child Docs to the beginning / end of the element. Reactive Docs are properly handled.
  • Clear() removes all children. Reactive children are properly disconnected from the View graph.
  • Text gets or sets the text content. The setter properly disconnects reactive children from the View graph.
  • Value gets or sets the value.
  • Methods to get, set, remove, test the presence of attributes, classes, styles: GetAttribute, SetProperty, HasClass, etc.
  • On "eventName" function adds an event callback.

We are still ironing out tricky parts required to implement OnAfterRender, which is quite ubiquitous in Html.Client code.

Templating language change

In order to allow using ${string} holes from the server side, the following change has been implemented:

  • ${string} holes now have type string instead of View<string>.
  • $!{string} is the new syntax for holes of type View<string>.

Conclusion

As you can see, a lot of enhancements are necessary to allow UI.Next markup to be usable as a replacement of Html.Client and Html.Server. We are confident that these changes will make it easy to convert existing applications to UI.Next for WebSharper 4.0.

Happy coding!