thomashoneyman/purescript-halogen-portal

How to pass an HTMLElement from another halogen component?

Closed this issue · 6 comments

Let's say i get a HTMLElement with the usual halogen way of using a Ref https://github.com/flip111/purescript-halogen-portal/blob/bigger_example/examples/multiple/Example/Component/Root.purs#L47

For the lifecycle of the Root component it looks like this then:

  1. render
  2. handle Initialize
  3. render again after initialization is done

I'm not really sure why that first render happens but it's been like that from my experience.

Let's pass the obtained HTMLElement to the child component https://github.com/flip111/purescript-halogen-portal/blob/bigger_example/examples/multiple/Example/Component/Root.purs#L55

The child component receives the new input https://github.com/flip111/purescript-halogen-portal/blob/bigger_example/examples/multiple/Example/Component/Child1.purs#L50 and passes that new input to the portal https://github.com/flip111/purescript-halogen-portal/blob/bigger_example/examples/multiple/Example/Component/Child1.purs#L56

However when the portal receives it's new input it just throws it away, never using the correct HTMLElement and just leaves the portal before the </body> closing tag https://github.com/flip111/purescript-halogen-portal/blob/bigger_example/src/Halogen/Portal.purs#L243

I can understand that moving the portal would be difficult to do (but maybe not impossible) so it was a conscious design decision. Though with that decision how is one supposed to get a HTMLElement from within a halogen component on the very first render?

For a project that i am working on only possibly solution might be to make the particular spot in my html where i want the portal to be rendered (a modal) not part of a halogen component, i will have to investigate whether i can keep that area + it's parent dom nodes static so that i can grab the HTMLElement and pass it as the very first input to my root component (to be eventually passed to the portal on first input).

I know the library is not really supported anymore but i would like to ask whether the use case of getting HTMLElement from another halogen component has been considered somehow or if i should try to work around it with static html.

Second question would be if it would be possibly to implement moving the portal. I'm not sure if that can be done while keeping the state of the portal intact.

If you pass an HTMLElement to the portal then it should render there. It won’t respond to further input but it shouldn’t just go to the — that sounds like a bug.

Thanks for the input. I might see later about fixing this bug around this location https://github.com/flip111/purescript-halogen-portal/blob/bigger_example/src/Halogen/Portal.purs#L243 i will leave this issue open until it's fixed. Not sure if i will start on this soon though

I don't think that the receiver is the issue — the component isn't designed to be unmounted and re-mounted if you change the target HTML element you give it; you should really just give it a target element once.

However, if you are giving it a target element and it's just mounting to the body instead, then something is wrong here:
https://github.com/flip111/purescript-halogen-portal/blob/2d96f2d7f5d15f6d7efc718199e995037480689d/src/Halogen/Portal.purs#L227-L228

I give the target HTML element as a later input not as the very first one. What would "unmounting" entail actually? Is it anything more than just removing the previous created DOM node?

Would it be ok to change the design to allow for re-mounting somewhere else? that way the target element can be setup in an Initialization method.

I give the target HTML element as a later input not as the very first one.

It sounds like you might want to wait to render the portal until you have the target element, then. For example:

type State = { target :: Maybe HTMLElement }

render state = case state.target of
  Nothing -> HH.text ""
  Just elem -> Portal.portalAff ... { target: Just elem }

Once you run runUI you can't move the element around.

Would it be ok to change the design to allow for re-mounting somewhere else?

This library is very small and unmaintained, so I would suggest that you copy the closest portal code into your application and tweak it so that it behaves the way you'd like!