Creating a reactive Single-Page App in F# with WebSharper UI.Next and Bootstrap – Part 1

Wow! That’s a lot of buzzwords we got here in that title! I’m not lying though, this is exactly what we are going to cover in today’s post. I hope you are familiar with all the terms above, but in case you’re not, let me start by explaining some of them.

Single-Page Application

Or SPA for short. A particular type of website that consists of a single HTML page that gets updated dynamically as the users interact with it. A good sign that a given website is a SPA is that it is not being refreshed every time you click on a link. This gives an experience similar to when using a desktop application. Gmail is a great example of a SPA.

Reactive Programming

Or RP for short. To keep things simple, it is a programming paradigm where you define data-sources that can be auto-magically observed. If the data-sources get updated (say, by a user or an external process), the elements that observe those data-sources will get notified and automatically react to the changes. The following pseudo-code illustrates a traditional, non-reactive approach:

var a <= 1
var b <= 2
var c <= a + b
echo c // c equals 3
a <= 2
echo c // c still equals 3

The next snippet illustrates the reactive approach however. Here c gets updated automatically every time a or b change, thus:

var a <= 1
var b <= 2
var c <= a + b
echo c // c equals 3
a <= 2
echo c // a changed, so c now equals 4!

This is obviously a very naive example and I encourage you to encourage you to do your own research about the topic and make your own opinion of it. There is a lot of information (and debates!) available online. I particularly like this presentation because it gives a global overview of different flavours of Reactive Programming.

Back to our application. We are going to use WebSharper UI.Next which is a library that enables both Reactive Programming and SPA within WebSharper. You can basically write entire reactive Single-Page apps from the comfort of your own F# editor! Isn’t it cool? Even Keanu Reeves approves!

Creating a dynamic Bootstrap navbar

That’s right. We will make a small application that allows users to dynamically customize a Bootstrap navbar:

Why Bootstrap? Because it is good-looking and easy enough so that even a back-end developer can use it! Before we go into the details of the implementation, let’s see how the app looks like:

(click on the .gif to enlarge)The application effectively offers the following functionalities:

  • Dynamically update the navbar-brand component by typing its name in a text input below.
  • Add a new item to the navbar by defining its name and URL.
  • The 2 text inputs along the Create new tab button get reset automatically upon adding a new item.
  • The new items are clickable and contain a working hyperlink. In the demo above, most hyperlinks are set to ‘#’, which will point to the current page. However I set the value of the last hyperlink to ‘test’ for the last item. As this URL doesn’t exist, a 404 error page is being shown instead.
  • Navbar items are set as active when clicked (different appearance than the inactive items), rendering all other items as inactive.

During the implementation, I used the term ‘Tab’ to refer to those navbar items. I came to realize that this is a bit misleading and I will probably update it in the future. My apologies for the potential confusion!

As usual, you will find the source code associated with this post on my GitHub repo.

The implementation

EDIT (July 2017): The explanations and code samples below we created under WebSharper 3.6. As Adam Granicz (one of the authors of WebSharper) rightly reminded me, the newest WebSharper 4.0 Beta features a revamped version of the HTML templating engine. More details about those changes can be found in the official documentation.

Let’s start by looking at the project’s structure. There are 4 files of interest:

  • index.html / 16 lines -> the HTML skeleton of the page.
  • bootstrap_navbar.html / 14 lines -> a file containing the default markup for the navbar. We will use it as a template for WebSharper later in this post.
  • navbar_sample.html / 23 lines -> a file containing the markup for the rest of the controls on the page (the 3 text inputs and the button below the navbar).
  • Client.fs / 63 lines -> the F# file containing the whole logic behind the application.

That’s 116 lines of code and markup I had to write for the entire application. The details of each file are presented below:

Index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Dynamic BootStrap NavBar</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!--<link rel="stylesheet" type="text/css" href="Content/UI.Next.Demo.css" />-->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
    <script type="text/javascript" src="Content/UI.Next.Demo.head.js"></script>
</head>
<body>
    <div id="main"/>

    <script type="text/javascript" src="Content/UI.Next.Demo.min.js"></script>
</body>
</html>

Nothing out of the ordinary here. We use the hosted version of Boostrap here, and Content/UI.Next.Demo.min.js contains the minified JavaScript logic of our application (transpiled from the F# code in Client.fs). The <div id=”main” /> will serve as an injection point for our navbar and custom controls.

bootstrap_navbar.html

<div id="navbar-template">
    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">$!{Brand}</a>
            </div>
            <ul class="nav navbar-nav" data-hole="Tabs">
                <li data-template="Tab" data-attr="ActiveClass">
                    <a data-event-click="SetActive" href="$!{Url}">$!{Name}</a>
                </li>
            </ul>
        </div>
    </nav>
</div>

This file contains the standard markup for a bootstrap navbar, decorated with a few WebSharper-specific attributes. All those elements can be directly accessed and manipulated from our F# code.

  • data-hole=”Tabs” defines a hole called Tabs that we can use as an injection point. If you want more information on the topic please check my other post here.
  • data-template=”Tab” defines an HTML template called Tab. The template corresponds to a single HTML <li> element with a nested <a href> .
  • data-attr=”ActiveClass” defines something similar to the data-hole above, but for injecting an HTML attribute instead. This is something new and very useful that I haven’t covered in my previous posts.
  • data-event-click=”SetActive” is another custom WebSharper attribute that allows us to define an action called SetActive. The action will get called when the user clicks on the associated <a href> link. Once again, we can access and setup this action directly from our F# code!
  • $!{Brand}, $!{Url}, and $!{Name} are the reactive equivalents of text holes that I covered in this previous post. If you don’t know what those are, they basically allow to display the values of their associated reactive variables. We will declare those reactive variables (In our case, Brand, Url, and Name respectively) in the Client.fs F# file.

navbar_sample.html

<div id="displayNavBar" data-replace="NavBar" />

<form class="form-horizontal">
    <div class="form-group">
        <div class="col-md-2">
            <input data-var="Brand" type="text" placeholder="Enter NavBar's brand" class="form-control" />
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-2">
            <input data-var="NewTabName" type="text" placeholder="Name of the new tab" class="form-control" />
        </div>

        <div class="col-md-2">
            <input data-var="NewTabUrl" type="text" placeholder="Url of the new tab" class="form-control" />
        </div>

        <div class="col-md-2">
            <button type="button" data-event-click="CreateNewTab" class="btn btn-success">Create new tab</button>
        </div>
    </div>
</form>

This file contains the HTML markup for the controls available to customize the navbar. There are a few more WebSharper attributes defined in the file:

  • data-var=”Brand” binds whatever value entered in the associated text input to the same Brand reactive value described above. It means that any change made to the reactive variable will be reflected in real time everywhere where the $!{Brand} text hole is used.
  • The same logic applies to data-var=”NewTabName” and data-var=”NewTabUrl” except that those are mapped to $!{Name}, and $!{Url} respectively.
  • Finally, there is one more data-event-click attribute with data-event-click=”CreateNewTab”. We will use this action to define the logic of creating a new navbar item.

That’s it for the HTML part, I believe this has been straightforward so far.We’ll cover the F# logic in the next post as things will get a bit more complicated!

To be continued!

2 thoughts on “Creating a reactive Single-Page App in F# with WebSharper UI.Next and Bootstrap – Part 1

  1. Pingback: Creating a reactive Single-Page App in F# with WebSharper UI.Next and Bootstrap – Part 2 – Youenn Bouglouan

  2. Pingback: dotnetomaniak.pl

Leave a Reply

Your email address will not be published. Required fields are marked *