Javascript interop with Elm

It was really easy in Elm 0.18, to add <script>tag with some javascript that will be executed when the element appears in DOM.

div [] [
node “script” [type_ “application/javascript”]
[text “alert(‘whatever’)”]
]

To prevent XSS attacks, Elm 0.19 strips the <script>tags in Elm generated HTML. In our project we had used this trick at a couple of places like to display WYSIWYG editor etc. When upgrading our app to 0.19, as expected the WYSIWYG editor stopped working.

This could be solved with custom elements, but I found it too complex for my taste. A quick Google foo landed me to Arrive.js, it uses Mutation Observers for watching DOM elements creation or removal. It gives us document.arriveand document.leaveevents that are invoked when an element is added or removed from DOM respectively.

document.arrive("#barContainer", () => {
// your javascript code
})
document.leave("#barContainer", () => {
// your javascript code
})

For the sake of a demo, let’s integrate D3.js in our Elm app. Here we wait for appropriate element creation, then render the chart.

Most interesting part of our Elm app, is the viewfunction, here we simply create the appropriate DOM element depending on the state.

When #chartContainerelement is created arrive.js invokes our javascript function and the chart is rendered! It works exactly as if we were having the scripttag in Elm 0.18 app.


Some quirks:

For some reason, our target element needs to be wrapped in an empty div to get detected by arrivediv[HA.id “chartContainer”][..].

More importantly, if we need to update the element with some new content for example, the only way it works is if first remove then re-add the element. That’s the reason I had to enable/disable buttons based on the state. Arrive.js does have some options to get around this, but it didn’t work in our case.

Overall, Arrive.js has served our needs excellently so far and hope you find it useful!

You can check out the Sources/Demo here.