Modifying the DOM with external JS libraries

133 views
Skip to first unread message

Marco Perone

unread,
Jul 27, 2016, 11:00:49 AM7/27/16
to Elm Discuss, maxmak....@gmail.com
Hello everybody,

I am building an application in Elm and I need to call an external JS library that interacts directly with the DOM (in my case, highlights a <pre><code> section). I built a port to communicate from Elm to Javascript and, on the Javascript side, I'd like to call my external library as soon as the element appears on the page.
My first try was to use the port command in the init function on my Elm application, but this doesn't seem to work, because when the JS callback is executed, the element of the DOM I need to interact with is not present yet.
For the moment I solved it on the Javascript side, just by retrying until the element is actually present, with something like this:

var highlightWhenReady = function () {
    if (!document.getElementById("part-to-highlight")) {
        window.requestAnimationFrame(highlightWhenReady);
    }
    hljs.highlightBlock(document.getElementById("part-to-highlight"));
};

but it seems really dirty, and certainly not the Elm way to do it.
What is the recommended way to do such things the Elm way? How could I know when the DOM element actually got rendered in the page?

Thank you!

marco

OvermindDL1

unread,
Jul 27, 2016, 11:07:18 AM7/27/16
to Elm Discuss, maxmak....@gmail.com
The call cycle seems to be:
0. main
1. init
2. subscribe
3. view (subscribe and view might be the other way, does not matter)
4. loop when receive msg
  1. receive msg -> update
  2. subscribe
  3. view

So instead of calling on init instead make a new Msg specifically for sending the command to your javascript port a cycle 'later'.  So in your init do `Cmd.cmd CallMyJSPort` or so, and put that again every time you need to run it again.  In your update callback for the `CallMyJSPort` message then call the port.  I do this and it works perfect every time.  *However*, you should not be mutating the Elm DOM as if it gets out of sync from the virtual DOM then weird bad things can happen.  You are 'generally' safe if you, say, add things to an empty elm-div or if you absolutely never alter the DOM parts in elm again after mutating them in JS, but not recommended regardless.

victo...@gmail.com

unread,
Jul 27, 2016, 11:34:20 AM7/27/16
to Elm Discuss, maxmak....@gmail.com
I think one of the main problem will be that Elm uses the virtualdom and so even if you modify the DOM, it could be reverted by the virtualdom on refresh (or something like that, I'm not an expert ^^).

There exists alternatives to virtualdom (such as morphdom: https://github.com/patrick-steele-idem/morphdom) that works differently and thus let you modify the DOM without problem externally but Elm does not use them.

OvermindDL1

unread,
Jul 27, 2016, 12:10:34 PM7/27/16
to Elm Discuss, maxmak....@gmail.com
Actually it only overwrite it in 'some' cases, in other times it will fill your javascript console with errors saying the DOM item does not exist or so forth.  ;-)

Ian Mackenzie

unread,
Jul 27, 2016, 6:46:46 PM7/27/16
to Elm Discuss
In this particular case, if you're just using highlight.js to highlight a block of code, you might also be able to use evancz/elm-markdown (http://package.elm-lang.org/packages/evancz/elm-markdown/3.0.0/). You'll still need to load a version of highlight.js in your HTML as described by the elm-markdown README, but then you should just be able to render a Markdown fragment containing a code block without worrying about weird DOM interactions.

Marco Perone

unread,
Jul 28, 2016, 9:43:00 AM7/28/16
to elm-d...@googlegroups.com
Thanks Ian, elm-markdown did the trick!

2016-07-28 0:46 GMT+02:00 Ian Mackenzie <ian.e.m...@gmail.com>:
In this particular case, if you're just using highlight.js to highlight a block of code, you might also be able to use evancz/elm-markdown (http://package.elm-lang.org/packages/evancz/elm-markdown/3.0.0/). You'll still need to load a version of highlight.js in your HTML as described by the elm-markdown README, but then you should just be able to render a Markdown fragment containing a code block without worrying about weird DOM interactions.

--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/JrrIWHZDckU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages