-
Notifications
You must be signed in to change notification settings - Fork 6
Interfacing with Javascript libraries
This page is top-level notes on how to interface with Javascript libraries.
- 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...
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 doesobject?method
calls. See the Usage of Vex and Tippy for examples.
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
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.
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 ispropName ==> propValue
. - callbacks can be F# functions with parameter whatever the callback is called with.
Warning - you have no static type checking here!