Has anyone integrated an Elm element into Angular?

Angular lets you access the native DOM of a component. You can use this to “embed” a Browser.element into an application.

What I’m struggling to wrap my head around is how this works with Angular’s change detection. Let’s say I embed my Elm element inside a component with a template like this

<div>
  @if (something) {
    <p> Display Something </p>
  }
  <div #elmElement></div>
</div>

Now, I assume change detection doesn’t actually work like this, but I’m essentially under the impression that the framework could redraw any part of the DOM it wants at any time. That is, if this is your Angular template, and something changes, there’s really nothing that says the whole component couldn’t be re-rendered in principal, unless Angular makes a promise somewhere that it won’t. Elm, for its part, points out that without the help of Html.Keyed, adding an element to a List can cause the diffing algorithm to update every subsequent node, which is fine since the view is a pure function of your Model, but Angular doesn’t know about your Model!

I guess what I’m getting at here is that embedding a native element that then gets modified outside of Angular feels like relying on some implementation detail inside Angular, hoping that your element persists, and I’ve tried to search for something that says otherwise, but I’ve come up short. They also say in the API docs for ElementRef that it’s a last resort (though I’m guessing that’s for security as they point out).

Use with caution

Use this API as the last resort when direct access to DOM is needed. Use templating and data-binding provided by Angular instead. If used, it is recommended in combination with DomSanitizer for maxiumum security;

Also, I don’t know what happens to a Browser.element if some external JS removes the DOM element that it’s “controlling” - does it crash, gracefully terminate itself, hang around in memory, updating an element tree that’s not actually in window.document anymore.

I’d appreciate it if anyone could answer any of these questions or link to some documentation that clearly outlines what guarantees Angular makes with respect to elements’ lifetimes.

Does Angular work with a VDOM? If it manages it’s own VDOM then it might just consider the element empty and not destroy it when diffing. Elm pretty reliably does this. In fact I usually use empty element like div[][] to bind non elm libraries like text editors etc.

Also, I don’t know what happens to a Browser.element if some external JS removes the DOM element that it’s “controlling” - does it crash, gracefully terminate itself, hang around in memory, updating an element tree that’s not actually in window.document anymore.

We were just discussing that here :grinning_face:

Basically… No it doesn’t gracefully clean itself up.

Thanks - I believe Angular works with a virtual DOM, but words like “might” are what I’m trying to avoid :slight_smile: . Perhaps I should post this in an Angular forum.

In fact I usually use empty element like div[][] to bind non elm libraries like text editors etc.

Very interesting - do you have an example? I’m curious in what situations this works, though AFAIK nothing in Elm’s official docs guarantee this either.

The best way to check is to set up that empty div, add an Elm program to it and then try create a huge diff to force Angular to compare all the children. You will see almost immediately what it does.

VDOM frameworks usually have to do these checks because otherwise you end up messing up input focus etc. So I would say Angular, considering how mature it is, is pretty clever around this, and when comparing a diff with an empty element simply ignores it. I agree though Angular forum might be best place to ask.

Very interesting - do you have an example? I’m curious in what situations this works, though AFAIK nothing in Elm’s official docs guarantee this either.

It’s just how Elm’s VDOM works, it sees an empty div and will leave it’s children alone because according to Elm, there are no children.

I posted recently talking about an example that uses this pattern. Can check it out here.

In Elm it’s basically this:

div [contentEditable True, data-lexical-editor="<lexical-state-managed-by-elm>"] []

Elm will faithfully compare attributes but preserve children, again, because according to elm there are no children. Meanwhile there is a full text editor working inside that div.

Not sure if it would be practical, but couldn’t you wrap your Elm program inside a custom element, and then use that custom element in angular like any other element?

This could work, because custom elements are a well defined concept, so it seems likely to me that angular could deal with that. Perhaps you could event attach the elm render output as shadow dom, to really make sure angular doesn’t touch it.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.