The Js_of_ocaml library

Base types

Base values are not represented the same way in OCaml and Javascript. In particular, OCaml strings are mutable arrays of bytes, while Javascript strings are constant arrays of UTF-16 code points. We list here the correspondance between base types. Conversion functions are provided.

OCaml values Ocaml type of Javascript values Actual Javascript type
int int Number
float float or float Js.t Number
bool bool Js.t Boolean
string Js.js_string Js.t String
array Js.js_array Js.t Array

Integers are implemented as Javascript numbers. They can thus be directly passed to and from Javascript. To allow a possible compatibility with Obrowser, where floats are boxed, we use to types for floats. Numbers of type float can be passed to Javascript functions. We rely in implicit coercion to perform unboxing when needed. On the other hand, Javascript will return unboxed float, of type float Js.t.

Typing Javascript objects

Javascript objects are given types of the shape <m_1 : t_1; ...; m_n : t_n> Js.t, using a phantom object type. The methods m_i stands for the field of the Javascript object. For instance, a Javascript object of type:

   < data : js_string t Js.prop;
     appendData : js_string t -> unit Js.meth> Js.t

has a property data containing a Javascript string, and a method appendData taking a Javascript string as argument and returning no value.

Some overloading is possible using a syntactic trick: names _foo, foo_abcd and foo are all mapped to a same Javascript field name foo: when accessing a field of an object, the name given in the OCaml code is transformed by removing a leading underscore and then removing all characters starting from the last underscore; this yields the corresponding Javascript name. For instance, these for types correspond to the same Javascript method drawImage:

    drawImage :
        imageElement t -> float -> float -> unit meth
    drawImage_withSize :
        imageElement t -> float -> float -> float -> float -> unit meth
    drawImage_fromCanvas :
        canvasElement t -> float -> float -> unit meth

This trick can also be used to refer to Javascript fields type or URL, for instance as _type and _URL.

Syntax extension

A syntax extension is available for manipulating object properties, invoking methods and creating objects. The syntax and typing rules are as follows:

  • Getting a property
            obj : <m : u prop> Js.t
            -----------------------
                 obj##m : u
  • Setting a property
            obj : <m : u prop> Js.t
              e : u
            -----------------------
               obj##m <- e : unit
  • Invoking a method
            obj : <m : t_1 -> ... -> t_n -> u meth; ..> Js.t
                e_i : t_i               (1 <= i <= n)
            -------------------------------------------------
                      obj##m(e_1, ..., e_n) : u
  • Creating an object
            constr : (t_1 -> ... -> t_n -> u Js.t) Js.constr
            e_i : t_i               (1 <= i <= n)
            ------------------------------------------------
                    jsnew constr (e1, ..., en) : u

OCaml and Javascript functions

OCaml and Javascript do not follow the same calling convention. In OCaml, functions can be partially applied, returning a function closure. In Javascript, when only some of the parameters are passed, the others are set to the undefined value. As a consequence, it is not possible to call a Javascript function from OCaml as if it was an OCaml function, and conversely.

Calling Javascript functions

At the moment, there is no syntactic sugar for calling Javascript functions. You should use either Js.Unsafe.call or Js.Unsafe.fun_call, depending whether you want this to be bound to some particular object in the function body or not.

You can also refer to a Javascript function using an OCaml external declaration. Then, you need to write stub functions in C so that the OCaml compiler accept the external declaration:

   Ocaml file:
      external foo : t1 -> t2 = "foo"
   C file:
      #include <stdlib.h>
      #define D(f) void f () { exit(1); }
      D(foo)

You can call this function as if it was an OCaml function, as the Javascript function is appropriately wrapped by the system.

Using OCaml functions from JS

You should use function Js.wrap_callback or function Js.wrap_meth_callback to wrap an OCaml function so that it can be called from Javascript.

To call an OCaml function from Javascript, follow this example:

(Js.Unsafe.coerce Dom_html.window)##plop <- Js.wrap_callback f

Or, to create a JS object with OCaml methods:

(Js.Unsafe.coerce Dom_html.window)##plop <- 
  Js.Unsafe.obj [| ("f", Js.wrap_meth_callback f);
                   ("g", Js.wrap_meth_callback g) |]

IO

The Json module allows to marshall and unmarshall the javascript representation of OCaml values into the corresponding JSON string. The unmarshalling is unsafe in the same way the OCaml Marshall.from_string function is.

Type-safe unmarshalling may be achieved with the deriving-ocsigen library using either the optionnal Json class or the Pickle class.

  • The Json class use a Json as external representation and do not preserve potential sharings in the data representation. See Deriving_Json for more information.
  • The Pickle class use a binary format as external representation and preserve sharings in the data representation.

Events

Besides the functions provided by Dom_html to register event handlers (mainly Dom_html.​addEventListener) using the usual Javascript way, js_of_ocaml provides another module to program event handlers very easily and concisely, in the module Lwt_js_events.

This module defines functions you can call on a DOM element to create an Lwt thread that will return when the event occures.

Example:

Lwt.ignore_result (Lwt_js_events.click target >>= handler);

The handler receives the JS event as parameter.

Each of these functions has a version (same name with an ending "s") that loops when the handler terminates. Example:

Lwt.ignore_result (Lwt_js_events.clicks target handler);

To remove an event handler, cancel the Lwt threads using Lwt.cancel. It is also possible to use Lwt.pick. For example the following piece of code waits for a click on one of t1 or t2:

Lwt.pick [Lwt_js_events.click t1 >>= handler1;
          Lwt_js_events.click t2 >>= handler2]

Warning: If you are using Lwt.pick and your handlers take time, be aware that other events listeners will not be cancelled before the handler has terminated. It is probably a better idea to return immediately after having launched the long handlers.

Look at the API documentation for more information.