Halogen HTML Element ID

The Current State of Affairs

So I’ve been wrapping a few components from MDC Web (Material Design).

When I create an html element

HH.div [ HP.id $ "prefix-string-" <> show generatedId ] [ ]

Say I want a reference to the HTMLElement I’ve just created, I can use the web-dom and web-html libraries to get a reference:

    window 
    >>= document 
    >>= 
        (   \doc -> querySelector 
            (QuerySelector "#prefix-string-17625")
            (toParentNode doc)
        )

I can put the element into my component’s state so I can instantiate the MDC Web component with a root element during initialization and call mdcComponent.destroy() (Via FFI) when the halogen component is finalized to clean up the MDC Web component.

The Question

Right now, if I supply my component with an ID, this works pretty straight forwardly. If not, however, I need to generate an ID that is unique across the entire SPA.

It means that either every button in my app must becomes aware of some global state or every button must be given an unique ID by it’s parent component (by whatever means).

I’m pretty new to a lot of this, are there any mechanisms exposed by Halogen that would get me away from using low level libraries like web-dom and web-html?

If I were doing this wholesale with Javascript, I could get the reference while creating the element and bypass the need to deal with explicit ids.

const elem = document.createElement('div');

Halogen has React-like refs to get references to underlying nodes. You can look at the Ace editor example to see how to mount a third party component into Halogen’s VDOM.

2 Likes

Oh nice

Combining
HP.ref $ H.RefLabel "some-label"
and
getHTMLElementRef $ H.RefLabel "some-label"

That’s much cleaner, thanks.


off topic, but a quick aside:

Is there ever a case where these two are not interchangeable?

handleAction = case _ of
  Initialize -> do
    ...

and

handleAction 
  Initialize = do
    ...

I see the first variant used a lot with Halogen Apps but not so much elsewhere. Is it a stylistic choice?

Yes, these two are completely equivalent.

1 Like

As far as I can tell, a RefLabel is just a string, so I still need to do the work to ensure that the string I choose is unique.

This is still much cleaner than using web-dom and web-html libraries, but it doesn’t solve the “keep a reference to a DOM element” problem as such.

I understand that this is sort of complicated by the fact that it is the diffing algorithm that effectively drives the creation/removal of DOM elements, so getting that reference once it’s created requires an extra level of redirection.

Perhaps this is the best way for now. I can see how to make this work via a naming convention such as “child-elements are given a ref string that has their parent ref string as a prefix”.

Ref ids are local to the component. They do not have to be globally unique like DOM ids. Read through https://github.com/purescript-halogen/purescript-halogen/issues/651 and linked issues if you only need a reference to something for initialization and don’t want to use ref ids.

3 Likes