Skip to content

Interfacing with Javascript libraries

Tom Clarke edited this page Mar 20, 2019 · 9 revisions

This page is top-level notes on how to interface with Javascript libraries.

Before you start

  • Big web frameworks etc may not be compatible
  • Libraries added should be published as npm packages and have no dependence on JQuery (which has problems with Monaco, resolving them is possible but may take you too long - I've not done it).
  • A lot of info on how to interface with JS from F# source files is in the FABLE documentation on interop - you may need this but can often avoid it.
  • Beware using React libraries - since React is complex and uses virtual DOM. I know it can be got to work with Visual2 but have not tried and maybe this will take a bit of effort. OTOH maybe it will just work...

Adding a library

The basic procedure is:

  • Add npm library to dependencies section of package.json. NB - this is definitely best done by yarn add packagename see yarn documentation.
  • Rerun setup.cmd to download and get dependencies of the new library
  • Find sample code from library pages and add the required "initialise library" function call (if there is one)to Refs.fs.
    • Vex and Tippy libraries have been added like this, see sample F# code for this
    • Single JS method calls can be implemented using emit as shown for Vex
    • It is a bit fiddly to add stuff but possible
    • If given multiple samples ES6 compatible ones are best
  • Add template CSS and JS libraries to ./app/index.html.
  • Call library functions as methods on the top-level library object as needed using dynamic function calls (avoiding types) with ? operator which does object?method calls. See the Usage of Vex and Tippy for examples.

Standard techniques

Importing and initialisation

To add Vex library I added CSS to app/index.html:

<head>
    <title>VisUAL2</title>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="css/photon.css">
    <link rel="stylesheet" href="css/vistally.css">
    <link rel="stylesheet" href="css/vex.css" />
    <link rel="stylesheet" href="css/vex-theme-default.css" />
    <!--<link rel="stylesheet" href="css/material-icons.css">-->
</head>

I added the Vex minified library code to index.html body:

    <script src="js/vex.combined.min.js"></script>

It is still necessary to use require as below to get a reference to the Vex library main object.

The code in Refs.fs shows the sample functionality

/// interfaces to vex.js top-level objects needed to do Vex stuff
[<Emit("require('vex-js');")>]
let vex : obj = jsNative

[<Emit("require('vex-dialog');")>]
let vexDialog : obj = jsNative

Emit is used to output JS direct from F# source. require is used here to import the libraries

Interacting with JS from F#

vex?defaultOptions?className <- "vex-theme-default" // sets a property

vex?registerPlugin vexDialog // calls a method with a parameter

? calls a method of an object. <- sets a property. All this is dynamic types (no type checking). You can add type checked interfaces for nicer use of libraries - but that is more work.

Creating JS objects / records / callbacks

Typically this is done to interface with JS methods. The Vex documentation shows how to create a button object in Javascript:

button {
    type: string, // the DOM `type` attribute
    text: string, // the textContent of the button
    className: string // the CSS class(es)
}

A (not quite identical) case of this, returned by an F# function with a parameter for the captoon, is as below. Note that a click property has been added that contains a callbackwritten as an F# anonymous function.

let vButton (caption : string) =
    let b = createObj [
        "text" ==> caption
        "click" ==> fun () -> "abc"
    ]
    b

let showVexConfirm (htmlMessage : string) (callBack : bool -> unit) =
    vex?dialog?confirm (createObj [
        "unsafeMessage" ==> htmlMessage;
        "callback" ==> callBack ])
    ()
  • createObj <list> creates an object with properties as given in the list. Each property is propName ==> propValue.
  • callbacks can be F# functions with parameter whatever the callback is called with.

Warning - you have no static type checking here!

Clone this wiki locally