A teammate and I have been working on integrating Dropzone.js into our Elm page and while we've got it working — including updating to different URLs for posting as the context changes in the model — the implementation isn't exactly pretty. We ended up dependent on sending our JavaScript code a tickle event via a port. This seems likely to either be noisy or to miss things and if Elm were ever to decide to be somewhat lazy about rendering and diffing HTML — e.g., only doing so if there are no pending actions — then this could suffer from timing problems wherein the tick driven JavaScript runs ahead of the actual tree update. There have been a number of proposals that have floated past but they tend to feel complicated. Having just gone through this, I'm trying to think through what the simplest, reasonably general purpose boundary is that could be more robust than just using tick to send data on a delay.
What it feels like we need is a way to create a virtual DOM node type that would create a div and invoke appropriate JavaScript code on it in conjunction with doing the DOM update. Nodes that aren't leaves on the Elm side or going to make the JavaScript side logic a lot more complex, so let's focus on Elm leaves — i.e., nodes with no Elm-managed nodes underneath them. There are three things that happen during updates to leaf nodes. They get created, they get updated, and they get deleted from the DOM.
So, the code to run the Elm app could take a JavaScript function with the signature: function( extensionClassName, eventName, divElement ) This would receive a "class" name specified in Elm — possibly just the standard HTML classname — an event name out of the following set: "willInsertElement", "didUpdateElement", and "didDeleteElement", and the div element. The hook code can then create or update the children within this div node. Other actions like changing the attributes of the div node or adding, removing, or moving it within the tree should be disallowed. Note that I tried to set these events up so that run before the node is in the tree or after it's been removed from insert and delete and the update event comes after the node has been updated so that it only sees new values. These seemed like the most "useful" choices but others may differ.
In the case of Dropzone, I would have used these hooks as follows:
willInsertElement: Create a child div that gets handed to the Dropzone setup code and for which we track the upload target URL.
didUpdateElement: If the upload target (indicated as an attribute of the hook div) has changed, then remove any existing Dropzone child div and add a new one. Note that in progress uploads can still continue and we can cache the old one in case we switch back.
didDeleteElement: If we're caching, any child Dropzone div can be moved to the cache at this point.
In Elm, I might have written something like hook [ class "dropzone-container", action targetUrl ].
The net effect of this would be that I can easily expose hook classes in my JavaScript code and use them in my Elm code. They do all of their communication for configuration via the standard virtual dom mechanism without needing port hooks to trigger updates.
Return data flow can probably just be via ports as it is right now though I could see it being interesting to expose a standard return message mechanism for hook nodes.
Does this seem like a fruitful path to others who have explored this more thoroughly than I and my team have?
Mark