Calling Haskell from JavaScript
bradrn opened this issue · comments
When using exportHandler
to export a Haskell function to JavaScript, how do you call the exported function from the JavaScript side?
You can use it like an ordinary JavaScript function, e.g.
handler <- ffiExport something
runFunction $ ffi "%1('hello')" handler
I should probably write this down somewhere in the documentation.
I think you misinterpreted my question --- I should probably have been clearer. This is what I meant to ask:
Can you call a Haskell function from a JavaScript script e.g. something like this:
--Main.hs ... handler <- ffiExport something ...
// Script.hs ... runHaskellFunction() ...
Perhaps confusingly, the ffiExport
function does not add a new name to the JavaScript namespace. Instead, it turns a Haskell function into something that can be used on the JavaScript side.
The ffi
function is the only way to transport this function to the JavaScript side. You can always do
handler <- ffiExport something
runFunction $ ffi "window.myFunction = %1" handler
to make a new identifier myFunction
available in the global JavaScript namespace.
Thank you!
You can use it like an ordinary JavaScript function, e.g.
handler <- ffiExport something runFunction $ ffi "%1('hello')" handler
I should probably write this down somewhere in the documentation.
It might also be a good idea to record the method you gave for 'exporting' a Haskell function in the documentation.
P.S.: In case you want to know what I needed this for, I'm using it to create a menu using Electron (see #111 and https://github.com/HeinrichApfelmus/threepenny-gui/blob/master/doc/electron.md). My code:
-- Main.hs
module Main where
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
...
setup :: Window -> UI ()
setup window = do
fname <- UI.input
saveBtn <- UI.button # set text "Save file"
box <- UI.textarea # set UI.id_ "text"
...
let fun = void $ runUI window $ element box # set text "Hello from Haskell!"
handler <- ffiExport fun
runFunction $ ffi "window.sayHello = %1" handler
...
// electron.js
...
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: { nodeIntegration: false },
});
...
app.on('ready', () => {
...
setMainMenu()
});
...
// based on http://stackoverflow.com/a/37798089
function setMainMenu() {
const template = [
{
label: 'Hello',
submenu: [
{
...
label: 'Hello from Haskell',
accelerator: 'CmdOrCtrl+H',
click() {
win.webContents.executeJavaScript('window.sayHello()')
}
}]
}
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
}
});