Professional Layouts In A Few Steps With WebSharper
Everyone likes when their product looks professional, right? But I think there’s something people like even more: a professional product that is easy to produce! Well, that’s just what you get when you use the Golden Layout extension of WebSharper!
Let’s start our little show-case with a quick recap!
WebSharper is a web development framework on top of .NET, which supports F# and C#, and has features like reactive variables,
Golden Layout is “a multi-screen layout manager for webapps” which let’s you build truly professional-looking layouts for your website or application with pretty few lines of code. Today, I’d like to show you how to reach the capabilities of this awesome library from WebSharper.
I wanted to show you a problem that benefits both from layouts and reactivity, so I though I’d walk you through the steps of making a Markdown editor with a preview window, where in one window you could edit your markdown code while instantly seeing the result in another window. You could also change the windows’ layout freely. With the help of Golden Layout and other WebSharper extensions, we can make this idea work in under 120 lines of code!
Step Zero - Get WebSharper!
The WebSharper download page provides you with the means to use WebSharper with Visual Studio and Xamarin Studio. I recommend you download the 4.x beta version (Zafir codename) since it has some cool new features compared to the previous version. If you’re using Visual Studio, close any running instances of it, run the downloaded .vsix file, and you should have WebSharper ready for you the next time you open Visual Studio.
In case you don’t feel like installing WebSharper on your computer, you still have try.websharper.com to play with, where you can try out WebSharper and any of its free extensions. Almost everything we’re doing in this article will work the same in Visual Studio and Try WebSharper.
Creating a Project
With WebSharper installed, you should see a couple of new project templates. In this guide we’re going to work with the one called WebSharper 4 Single Page Application. I’m naming my project “MDEditor”. To get a clean start, let’s delete the example code, and keep the bare minimum before starting to write our application. After cleaning up, your
index.html files should look like this:
Try running the project now! An empty, white page is a good sign.
It’s possible that you’ll get a runtime error when trying to run the applicaton. Don’t panic! The most probable reason for that is that the project is referencing an
FSharp.Coreversion that is not installed on your computer. We can fix this in 2 quick steps:
1. Right-click on your project, click Properties, and select an appropriate Target F# runtime. Save your project settings.
2. Open the
Web.configfile of your project. There will be a
bindingRedirecttag. Update it to have
oldVersion="0.0.0.0-18.104.22.168", and set the
FSharp.Coreversion that you chose in the first step.
If this still doesn’t fix the problem, feel free to ask on the WebSharper Forums or StackOverflow.
Adding The Extensions
WebSharper extensions can be downloaded via NuGet Package Manager. Right-click on your project, click “Manage NuGet Packages…”, select the “Browse” page and check “Include prerelease”. The extensions we’re going to use are these three:
Zafir.Google.CodePrettify. The latter two are needed to make the markdown preview and the code highlighting work. I won’t go into detail about their usage, you can read a bit more about them here. Now we should be able to add these lines to the top of the
Using Golden Layout
Initializing Golden Layout requires a couple of steps in itself.
First, we have to describe a tree of Content Items. These Content Items can be divided into two big roles: ones that have actual content (
ReactComponent) and ones that aggregate other items (
Components have a property called
ComponentName. Opposed to what one would think, it is not the
Title that would appear on the little tab attached to the component but more like the kind of the component. The second step is to register the components, which is done by attaching a creator function to each
The last crucial but simple step is to initialize the layout manager. This takes exactly one line of code.
What about the CSS?
index.html. A WebSharper developer knows better than that. We have at our disposal an attribute called
Require , which servers the purpose of including resources that come with the extensions.
In Golden Layout’s case, we have to include a base CSS, then either a light theme or a dark theme. All of these can be found in the
WebSharper.GoldenLayout.Resources namespace. Keep it in mind that the order of the
Require attributes does count, so that base CSS has to go first in our code, too. Here’s the code:
Done! Golden Layout’s stylesheets will be automatically added to our website now.
As I said earlier, a component’s
ComponentName is more like the component’s type, so let’s look at what type of components do we want to work with:
We will need two types of components: one that holds the text input, and one that shows the preview for that input. Let’s place the following code inside our
module Client = before the
Main () function:
Now, if you are by any chance following (or already familiar with) the original documentation of Golden Layout, your feeling of something being off about this snippet is right. What does that
- You have the
Itemstruct with all common properties of Content Items
- You have a different config struct for each type with their special properties
- You combine them with a method of the
ItemFactoryclass to get the full Content Item config
The result will be of a type called
Note that the
GeneralItemConfig is not meant for you to create the config objects with. It is only used when the original library would return or pass a Content Item config as a parameter. To learn more about this, read the extension’s official documentation.
Okay, technical stuff aside, let’s look at our code a little! As I promised, we gave our components their names, which we will use to add content to them in one of the next few steps. We also set their
Title and disabled their close button. Closing either the input or the preview window would be somewhat counterproductive since we’re not implementing any way to reopen them, so the best we can do is at least prevent the user from shooting themself in the feet. (We’re not working on a new C++ standard anyways.)
But where do we put the components?
The class is called
GoldenLayout and needs a
Layout config object, and an optional
JQuery parameter to create the layout in. The default behavior is that your layout will get appended to the
body of the HTML page, which is perfectly fine in our case by the way.
Let’s put this code inside our
Main () function:
What we have here is the
GoldenLayout (our layout manager) class getting a
Layout config class, which has its
Content property set. This is the ”tree of Content Items” that I’ve told you about a couple paragraphs earlier. This
Content property is the root of that tree, and is expecting an array of Content Items. But how will this make a tree? Well, as you can see in this snippet, Content Items also have a property like this, so Content Items can also have other Content Items as children, which turns this into a tree. Come to think of it, what is that
A row is another kind of Content Item, one for aggregating others. With using the “row”, we’re telling Golden Layout to display its contents vertically, side-by-side. Of course, once the layout is visible to the user, they can freely align these layouts. We make this item impossible to close, too, for the same reason as before.
Registering the components
Earlier I said that registering the components means “attaching a creator function to each
ComponentName value”. But what does that even mean?
We have this function:
componentCreator: (Container * obj -> Unit)
componentCreator signature should look something like this:
componentCreator((container: Container) * (state: obj)): unit
Container class is described in the original documentation, and is there for you to get a hold on the wrapper HTML element which will hold your component‘s content. The
state is there to carry an arbitrary state assigned to the component. It is an optional parameter of the
ReactComponentconfig structs, so you didn’t get to see it before because we didn’t assign it, and we didn’t assign it because we don’t need it in this case. If our markdown editor handled multiple editor-preview window pairs at once, the state would probably hold the unique name of the editor window, and the preview’s state would know which editor the preview belongs to.
Okay, now that the concept of the API is in shape, let’s append the following code to our
Main () function:
You’re most probably going to get some errors, but no worries, just
open WebSharper.UI.Next.Html, that’s where functions like
Now, for a quick review of the snippet: we’re using the
RegisterComponent function described just above, we’re passing the
componentName and the
componentCreator. As I said earlier, we’re only using the
container parameter, so we leave the binding for
state blank. Let’s walk through the inside of the two functions.
The two creator functions are almost identical. First, we define an HTML
span with a unique id and no children, then we get its
Dom through a property, and make a
JQuery object of that.
container.GetElement() returns the component’s wrapper as a
JQuery object, which we empty, and then append our fresh
span to. As the function must return with a
unit, we finish the chain with the
WebSharper has a binding for JQuery out of the box. How handy!
As you can see, these two chains of computations don’t give much content to our components. But what will then?
Before we can move on with our mission to create the best professional-looking layouts, there are other things that we must get out of our way. Namely, to configure
Remarkable. As I said, I won’t be explaining the usage of this extension but there’s a blog post and, you know, the documentation. Just paste this code under our Golden Layout configs before the
let Main () = and we’ve got that sorted out.
Another task which isn’t closely related to working with layouts is giving our soon to be created input and output elements a little style.
I don’t really want to expand on this very much, since I assume that anyone reading this article has at least a basic understanding of CSS. Just go ahead and append that code to the
<header> tag in our
The finishing touch
And with this, we’ve reached the last step in the process of setting up Golden Layout: the actual initialization, which is (as I said) exactly one line of code:
Put that at the end of the
Main () function, and we’re done!
With the layouts!
We have the layouts laid out, but they are not doing anything yet. Prepare to be surprised by the amount of code we’ll need to give behavior to our app!
Reactive programming in F# demands reactive variables. In this case our reactive variable should hold the text the user inputs, so we create it by adding a
let codeVar = Var.Create "# Hello world"line before our
Main () function.
string initial value will force
codeVar to have the type
Var<string>, which is exactly what we need.
We also need something for the user to type into, so let’s create a
textarea input and put in our
Doc.InputArea [attr.id "inarea"] codeVar
|> Doc.RunById "inarea-wrapper"
InputArea needs attributes and a
Var<string>, which we actually happen to have one (coincidence?), and then
Doc.RunById replaces the given element’s content with the
Doc that comes in the last parameter. That’s it!
And now, the code for displaying the preview:
What we see here is a
div with no content (originally) and two attributes: a classic id and a…
View is kind of like the current value of a reactive variable at any given time. The
viewUpdate event takes a
View and a callback, which will get called every time the view’s value changes, and takes two parameters: the source element, and the new value of the view, which is the code the user is typing in this case.
The body of the callback takes this
code, converts the markdown to HTML with
remarkable.Render, then puts that HTML code inside this very
div, then we get the obligatory
JQuery.Ignore, and finally, there’s a call to
PR.PrettyPrint(), which does the syntax highlighting in the preview, since Remarkable is only responsible for the markdown parsing.
Are you surprised? The number of extra code lines that were needed to make the editor and the preview work was an astounding 16. Or was it?
Well, kind of. But you might’ve noticed that I didn’t tell you where to put the last two pieces of code, and that’s exactly because there’s nowhere to put them at the moment. You can see that we are using IDs that are in registered components. So why didn’t we put this code in
registerComponent? Well, to be honest, converting the
inputarea to a DOM element seems to somehow break the connection with our reactive variable. Then how about putting it after
lm.Init()? The layout manager initialization seems to take “quite a lot” of time, so it won’t be finished by the time we want to append elements to it. Then when should we call this code? Exactly when the layout is initialized!
Golden Layout, as it is a good library, has all kind of events for most of its classes. One of these is the
"initialised" event of the
strings but the WebSharper extension took it a step further! We have an
enum for these special events! Wow! And, of course, the event subscription handling functions are overloaded for all of them. All we have to do now is put our previous code in the event handler. Paste this code just before our
A quick prayer, Ctrl+F5 in Visual Studio, and we should see our awesome reactive markdown editor, with resizeable and movable layouts!
If you want to see more examples of working with Golden Layout from WebSharper, you can try these snippet online:
The extension’s documentation can be found here.
I hope you enjoyed this article about WebSharper’s Golden Layout extension! If so, feel free to recommend, tweet or make a tattoo so that you can show the article to many more people! Thanks for reading & sharing!