Congratulations on taking the first step to learn WebSharper! We have carefully put together this hands-on tutorial with the aim to help you get started with WebSharper and on your way to learn functional, reactive web development, putting you on a fast track to unleash the real web developer in you. The skills you pick up with WebSharper will make you a better web developer, and the concepts you learn will remain valid and useful with other functional, reactive web frameworks and libraries as well. You can find links to further material below and the sources of this tutorial in the bottom of this page, and you can see the resulting app in action live on Try WebSharper.
In this tutorial, you will learn how to work with external HTML files (aka. templates) and how to implement your application logic into them. For this, you will take a login page from dansup's wonderful free Bulma template collection. Your app will look pretty much the same and also implement basic form validation:
The main takeaway of this tutorial is that you should use HTML templates as much as possible instead of inlining HTML code into your application logic. While it's certainly easy to construct HTML in C# or F# (by using the HTML combinators defined in
WebSharper.UI.Html
), it's our recommendation that you avoid it as much as you can for better logic vs. presentation separation.
To get the most out of this tutorial, make sure you have installed:
Grab a command prompt, cd
into the folder you want to use for your new project, and type:
dotnet new websharper-spa -lang f# -n MyProject
This will create a new WebSharper SPA project for you. You will use F# for this tutorial, but you can also choose to create a C# project (just leave off the -lang f#
part) and adapt the sources we discuss here. Go ahead and open this project with your favorite editor.
wwwroot/index.html
- Your main SPA - this is the file you open to run your appClient.fs
- The logic for your SPA - this is where your F# code will beMyProject.fsproj
- The .NET Core project file for your SPAProgram.fs
/ Startup.fs
- The minimal boilerplate to run/host your app with the default ASP.NET Core web serverwsconfig.json
- Your WebSharper configuration file - normally, it's all set up for youThe SPA project you just created consists of a sample template that you can simply replace with the new markup from the login template. To see what's going on underneath, follow these steps:
Replace wwwroot/index.html
with the source of the login page
Download login.css
from the login template as wwwroot/css/login.css
, and update the reference to it in wwwroot/index.html
accordingly:
..
<link rel="stylesheet" type="text/css" href="css/login.css">
</head>
Feel free to remove the reference to bulma.js
- it is not strictly needed.
Re-add the following block to the bottom of the <head>
section:
<style>
[ws-template], [ws-children-template] { display: none; }
.hidden { display: none; }
</style>
<script type="text/javascript" src="Content/MyProject.head.js"></script>
This will give you a .hidden
CSS class to hide things (always comes handy), and also make sure that any dependencies are correctly brought into the page by WebSharper when needed.
Re-add the following block to the bottom of the <body>
section:
<script type="text/javascript" src="Content/MyProject.min.js"></script>
This will load the JavaScript code WebSharper generates for your SPA.
Feel free to update the <title>...</title>
with the title you prefer to give to your app.
Change the links below the login form as you see fit (we won't deal with those in this tutorial.)
Now that you have the skeleton of your login page, you can quickly wire in the necessary logic. First, you need to be able to access the email and password values the user types in. The WebSharper way of doing that is going into the template and marking the input controls that supply values to the F# layer with a ws-var
attribute. You also want to implement some basic validation and use Bulma's is-danger
class to visually indicate when an input control is not giving what you are expecting. So add in ws-attr
attributes as well, and change the relevant lines to:
...
<input ws-var="Email" ws-attr="AttrEmail" class="input is-large" type="email" placeholder="Your Email" autofocus="">
...
<input ws-var="Password" ws-attr="AttrPassword" class="input is-large" type="password" placeholder="Your Password">
...
<input ws-var="RememberMe" type="checkbox">
...
Also, add a ws-onclick
attribute to the Login button so you can wire a click event handler to it:
...
<button ws-onclick="Login" class="button is-block is-info is-large is-fullwidth">Login</button>
...
Now, you are ready to write your F# logic and switch over to Client.fs
. If you didn't have to worry about validation, things would be super simple, but in this case you want the full enchilada, so you will also use a couple reactive variables as a mini data model (passwordValid
and emailValid
) to tell whether the email and password fields are valid.
At this point, you can see that the WebSharper UI templating type provider conveniently feeds back the reactive variables and attributes you defined in your master template, and you can simply set these up as follows:
Show a visual validation error for the Email input box if emailValid
is false by applying Bulma's is-danger
class:
MySPA()
.AttrEmail(Attr.ClassPred "is-danger" (not emailValid.V))
Here,
emailValid.V
is a shorthand WebSharper uses (it's a type-directed macro) that enables to treat a Var or a View as the underlying value in reactive scenarios/functions (such asAttr.ClassPred
.)
Similary, show a validation error for the password field is passwordValid
is false:
.AttrPassword(Attr.ClassPred "is-danger" (not passwordValid.V))
Now, handle the Login button click - this is what decides what constitutes a valid input (no empty fields) and simply putting up a popup alert if login is successful (this is where you would do a server call to authenticate your users and to log them in by creating a user session):
.Login(fun e ->
passwordValid := not (String.IsNullOrWhiteSpace e.Vars.Password.Value)
emailValid := not (String.IsNullOrWhiteSpace e.Vars.Email.Value)
if passwordValid.Value && emailValid.Value then
JS.Alert (sprintf "Your email is %s" e.Vars.Email.Value)
e.Event.PreventDefault()
)
Note how
e
in the login handler enables you to access all the input values throughe.Vars
. You can also use these to set their values on the UI - two-way binding in WebSharper UI really rocks.
And last, seal these and bind your logic to the SPA:
.Bind()
And boom, you are done.
Your login app is 30 lines of F# code, and even for a short tutorial like this one, you can pull off one more trick. Say, you wanted to add error messages below the input boxes that are failing validation. Bulma's way is to add these to the markup after each input control. In addition, all you need as extra is another ws-attr
attribute:
<div class="field">
<div class="control">
<input ...>
</div>
<p ws-attr="AttrEmailMessage" class="is-danger help">Please enter an email address</p>
</div>
The last bit is handling the showing/hiding of this error message in Client.fs
by applying the hidden
class you added to the template earlier:
.AttrEmailMessage(Attr.ClassPred "hidden" emailValid.V)
As a bonus exercise, you can add a similar error message for the password field as well, and just a hint: it will look exactly like what you did above.
You can fork this SPA project via GitHub, it's a whopping 35 LOC F# in its entirety - enjoy! You can also try out a slightly adapted version live on Try WebSharper.
Happy coding!
Can’t find what you were looking for? Drop us a line.
20221229 · 30 min read
20211230 · 20 min read