As PureScript is very similar to Haskell and uses strong static types, it is sometimes challenging to puzzle types together, which feels a bit like playing Tetris.
Of course we can state the question:
Why is it so hard to implement something very obvious and simple?
Well, in this case it is really "by design". The package which is responsible for this code is on purpose designed in a PureScript manner. As developers we usually are not supposed to mess and manipulate DOM element by hand. Instead it is strongly motivating to use frameworks like Halogen, which will take care of the mechanics below. You can imagine this in the following way: If you would like to send a message over the network, you would rather use a predefined and well tested protocol instead of trying to implement low-level code yourself.
With this in mind, let's examine the getElementById function from the Web.DOM.NonElementParentNode module:
getElementById :: String -> NonElementParentNode -> Effect (Maybe Element)
As you can see, we rely here on a string (obviously our id to search for) and a NonElementParentNode Type. The result is an optional element. Hence, if it exists in the DOM, we will get a Just and a Nothing if there is no such element.
Now, what is this NonElementParentNode? In fact, it is nothing specific to PureScript. PureScript makes it just explicit due to it's strong static types. NonEelmentParentNode is a native class/interface which is supported by the browser. It is the element which supports getElementById. You can find in several different languages/documentations (Dart / Apple Developer Docs). We just need to keep in mind that we need this element to be able to call getElementById on it.
Next question is: How do we get such an element? The Web.DOM.Document module exports a method called getNonElementParentNode which expects a document as input value:
toNonElementParentNode :: Document -> NonElementParentNode
Finally - with all this information - we can combine our functions as follows to get the element which we can use our getElementById function on with:
import Data.Foldable (for_)
import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)
import Web.HTML (window)
import Web.DOM.NonElementParentNode (getElementById)
main :: Effect Unit
= do
main <- map toNonElementParentNode $ document =<< window
maybeDoc $ \doc -> do
for_ maybeDoc <- getElementById "targetElement" doc maybeElement
When I first saw this part of code to just get an element by id, I was surprised that it looks pretty complicated. But in the end, it makes perfect sense.
Thank you for reading this far! Let’s connect. You can @ me on X (@debilofant) with comments, or feel free to follow. Please like/share this article so that it reaches others as well.