This short tutorial is an example of client-server Eliom application. It gives an example of client-server widgets. You can find the original version of this tutorial (and many others) here.
It is probably a good starting point if you know OCaml well, and want to quickly learn how to write a client-server Eliom application with a short example and concise explanations. For more detailed explanations, see the “Graffiti” tutorial, or read the manuals.
The goal is to show that, unlike many JavaScript libraries that build their widgets programmatically (by instantiating classes or calling functions), Eliom enables server-side widget generation, before sending them to the client. Pages can thus be indexed by search engines.
This tutorial also shows that it is possible to use the same code to build the widget either on client or server side.
We choose a very simple widget, that could be the base for example for implementing a drop-down menu. It consists of several boxes with a title and a content. Clicking on the title opens or closes the content. Furthermore, it is possible to group some of the boxes together to make them behave like radio buttons: when you open one of them, the previously opened one is closed.
The following code defines a client-server Web application with only one service, registered at URL / (the root of the website).
The code also defines a client-side application (section [%%client ... ]
) that appends a client-side generated widget to the page. Section [%%shared ... ]
is compiled on both the server and client side programs. Alternatively, you can write let%client
, let%server
or let%shared
(default) to define values on client side, on server side, or on both sides.
To compile it, first create a project by calling
eliom-distillery -name ex -template basic.ppx
The name of the project must match the name given to the functor Eliom_registration.App
.
After you adapt the file ex.eliom
, you can compile by calling make, and run the server by calling make test.byte
. Download the CSS file and place it in directory static/css
. Then open a browser window and go to URL http://localhost:8080
.
Screenshot:
This section gives very quick explanations on the rest of the program. For more detailed explanations, see the tutorial for the graffiti app or the manual of each of the projects.
Ex_app
).##
is used to call a JS method from OCaml and ##.
to access a JS object field (See Js_of_ocaml’s documentation: Ppx_js).Lwt
is the concurrent library used to program threads on both client and server sides. The syntax let%lwt a = e1 in e2
allows waiting (without blocking the rest of the program) for an Lwt thread to terminate before continuing. e2
must ben a Lwt thread itself. Lwt.return
enables creating an already-terminated Lwt thread.Lwt_js_events
defines a convenient way to program interface events (mouse, keyboard, …). For example, Lwt_js_events.onload
is a Lwt thread that waits until the page is loaded. There are similar functions to wait for other events, e.g., for a click on an element of the page, or for a key press.To make the widget work, we must bind the click event. Replace function mywidget
by the following lines:
Lwt_js_events
. Function clicks
is used to bind a handler to clicks on a specific element.async
runs an Lwt
thread asynchronously (without waiting for its result).Lwt_js_events.clicks elt f
calls function f
for each mouseclick on element elt
.To_dom.of_element
, Js.string
and Js.to_bool
are conversion functions between OCaml values and JS values.The following version of the program shows how to generate the widget on server side, before sending it to the client.
The code is exactly the same, with the following modifications:
[%client (... : unit) ]
. This code will be executed by the client-side program when it receives the page. Note that you must give the type (here unit
), as the type inference for client values is currently very limited. The client section may refer to server side values, using the ~%x
syntax. These values will be serialized and sent to the client automatically with the page.If you make function mywidget
shared, it will be available both on server and client sides:
Screenshot:
To implement this, we record a client-side reference to a function for closing the currently opened window.
Now we want to enable several sets of widgets in the same page. A single reference no longer suffices. In the following version, the server-side program asks the client-side program to generate two different references, by calling function new_set
. This function returns what we call a client value. Client values are values of the client side program that can be manipulated on server side (but not evaluated). On server side, they have an abstract type.
Screenshot:
An important feature missing from this tutorial is the ability to call server functions from the client-side program (“server functions”). You can find a quick description of this in this mini HOWTO or in Eliom’s manual.
For many applications, you will need several services. By default, client-side Eliom programs do not stop when you follow a link or send a form. This enables combining rich client side features (playing music, animations, stateful applications …) with traditional Web interaction (links, forms, bookmarks, back button …). Eliom proposes several ways to identify services, either by the URL (and parameters), or by a session identifier (we call this kind of service a coservice). Eliom also allows creating new (co-)services dynamically, for example coservices depending on previous interaction with a user. More information on the service identification mechanism in Eliom’s manual.
Eliom also offers a rich session mechanism, with scopes (see Eliom’s manual).