More on external "components"

165 views
Skip to first unread message

Mark Hamburg

unread,
Mar 28, 2016, 7:37:58 PM3/28/16
to Elm Discuss
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


jhan...@shellshadow.com

unread,
Oct 22, 2016, 10:13:39 AM10/22/16
to Elm Discuss
Hi Mark,
We're looking at possibly starting our first Elm project.
Our app would in the first phase rely heavily on a robust multi-file (images) uploader such as DropZone.js

Over time we would need other sophisticated js libs such as Quill.js

Do you have time to share your experience or suggestions with me?

I'm at a tough point where I have to decide go or no go for Elm on this project.  

thanks, Jon

OvermindDL1

unread,
Oct 22, 2016, 3:46:18 PM10/22/16
to Elm Discuss
Elm's VirtualDom has such a thing just for that:  https://github.com/elm-lang/virtual-dom/blob/master/src/Native/VirtualDom.js#L88-L98

However, it is only accessible via 'native' code javascript, thus you'd have to make a native module, which if that is fine for you...

I also have no clue if it is 'official' api in any way, so unsure on its future-proofness.

Do note that it is very low level, you create the node and return it from `impl` based on the model data passed in to it, of which the VDom will mutate it further as necessary (or not at all if you do not put any mutations on if you want to handle it all yourself, so keep that in mind).

Mark Hamburg

unread,
Oct 23, 2016, 3:11:37 PM10/23/16
to elm-d...@googlegroups.com
The project in question was Elm 0.16 based and we've moved on to other work so the details need some translation (which I will attempt to handle here), but the net was that it worked reasonably well with some caveats and hacks.

The first problem is getting Dropzone.js to attach its logic to the node. If Dropzone supports web components, it sounds like people are having reasonably good luck with those. Otherwise, you need a way to watch for node creation. We'd seen warnings about performance problems regarding the hook points one would expect to use regarding DOM elements and so used the relatively twisted alternative of using a very fast CSS animation and watching for the end of the animation. However, you go about it, you make a div and write a small JavaScript hook to attach the Dropzone handling to it.

The second thing to watch out for is lifetime management. This matters both from the standpoint of keeping the node alive and generating new nodes if you need a different target for the dropzone. I posted at greater length about that here recently, but the basic rule is that you want to use Html.Keyed and you may want to use it all the way up your view tree for any places where positional equivalence won't be sufficient. You need to guide the virtual DOM diff logic so that it knows what it should consider as being the "same" DOM element and what it should consider to be a different DOM element.

The last thing is managing how the element communicates back. It may be able to do so via DOM events but in the case of Dropzone at least, it was easier to plug in to its callbacks and have those post messages to an Elm port to which the app could then subscribe.

We haven't used any other significant JS components at this point, but I would expect the same points would apply there as well.

Mark

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages