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!

This article might stretch out a bit long, but by the end of it you will not only have an understanding of the Golden Layout extension (be it in C#, F# or JavaScript), but also have made a pretty cool web-app. Think about it: if reading this article takes 15 minutes, the next time you want to code something similar, it might be done before you could reread the article! So good luck!

The Extension

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, Doc templates to enable quick iteration (you can read a bit more on that here), type-safe and easy remoting and an F#/C# to JavaScript compiler. The latter enables us to use any JavaScript library from F# as long as there is a binding for it, and now there’s a binding for Golden Layout!

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.

Our Specimen

Our final product. Looks cool, right?

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 Client.fs and 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.Core version 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.config file of your project. There will be a bindingRedirect tag. Update it to haveoldVersion="0.0.0.0-4.4.1.0" , and set the newVersion to the FSharp.Core version 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.GoldenLayout, Zafir.Remarkable and 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 Client.fs file:

open WebSharper.GoldenLayout
open WebSharper.Google.CodePrettify
open WebSharper.Remarkable

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 (Component and ReactComponent) and ones that aggregate other items (Row, Column, Stack).

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 ComponentName value.

The last crucial but simple step is to initialize the layout manager. This takes exactly one line of code.

What about the CSS?

Good question! As many other JavaScript libraries, Golden Layout comes with its own CSS files to make it look pretty. No, we’re not going to include them in our 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.

Components

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 ItemFactory.CreateComponent do?

<technical rant>
In the original JavaScript library, a Content Item’s config object would have different special fields added depending on the item’s type. As this would not work very well in a statically typed environment, the WebSharper extension takes a slightly different approach:

  1. You have the Item struct with all common properties of Content Items
  2. You have a different config struct for each type with their special properties
  3. You combine them with a method of the ItemFactory class to get the full Content Item config

The result will be of a type called GeneralItemConfig.

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.
</technical rant>

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?

Again, good question! I can see that you’re paying close attention to the article. The thing we’re going to put the components in is called “layout manager”, and is the most important member of the Golden Layout class family. If you’re already familiar with the API of the original JavaScript library, good news for you: this one works just the same!

The class is called GoldenLayout and needs a Layout config object, and an optional Dom.Element or 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 CreateRow?

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:

GoldenLayout.RegisterComponent(
componentName: string,
componentCreator: (Container * obj -> Unit)
): unit

And a componentCreator signature should look something like this:

componentCreator((container: Container) * (state: obj)): unit

The 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 Component and 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 spanAttr live.

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 JQuery.Ignore property.

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?

A side-quest

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 index.html.

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:

lm.Init()

Put that at the end of the Main () function, and we’re done!
…With that?

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!

Getting Reactive

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.

The 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 #inarea-wrapper element.

Doc.InputArea [attr.id "inarea"] codeVar
|> Doc.RunById "inarea-wrapper"

An 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… viewUpdate event?

What’s a View? 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?

…Done?

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!

Done!

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 GoldenLayout class, which is our layout manager. I bet most of you are used to subscribing to JavaScript events with 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 lm.Init() line:

A quick prayer, Ctrl+F5 in Visual Studio, and we should see our awesome reactive markdown editor, with resizeable and movable layouts!

More Examples

If you want to see more examples of working with Golden Layout from WebSharper, you can try these snippet online:

Markdown editor with preview (yes, the one we just made)
Create tabs dynamically
Create tabs statically

The extension’s documentation can be found here.

Afterword

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!

See you!