4
votes

I'm using purescript-halogen, and I want to scroll to bottom of div when the child component's message were caught. However, it seems not present that scroll action control in Halogen. So, how can I Scroll to bottom of div?

One solution I think is that call other, not Halogen, process from Main when the event caught. I'm not sure that this solution is not bad.

2

2 Answers

4
votes

Setting the scroll position is just done through using the normal DOM functionality, targeting the rendered node.

To do this, you'll need to add a ref property in the HTML DSL to the node you want to scroll:

-- Define this in the same module as / in the `where` for a component
containerRef ∷ H.RefLabel
containerRef = H.RefLabel "container"

-- Use it with the `ref` property like so:
render =
  HH.div
    [ HP.ref containerRef ]
    [ someContent ]

And then in the eval for the component you can get hold of the actual DOM element created, using getHTMLElementRef, and then update the scroll position on that:

eval (ScrollToBottom next) = do
  ref ← H.getHTMLElementRef containerRef
  for_ ref \el → H.liftEff do
    scrollHeight ← DOM.scrollHeight el
    offsetHeight ← DOM.offsetHeight el
    let maxScroll ← scrollHeight - offsetHeight 
    DOM.setScrollTop maxScroll el
  pure next

The snippets here are modified from some real world code that does something similar, so should do the trick!

0
votes

Essentially the same answer as https://stackoverflow.com/a/44543329/1685973, but I had a hard time finding the different imports:

import Halogen as H
import Halogen.HTML as HH
import Data.Foldable (for_)
import DOM.HTML.Types (htmlElementToElement)
import DOM.Node.Element (scrollHeight, setScrollTop)
import DOM.HTML.HTMLElement (offsetHeight)

...

-- Define this in the same module as / in the `where` for a component
containerRef ∷ H.RefLabel
containerRef = H.RefLabel "container"

-- Use it with the `ref` property like so:
render =
  HH.div
    [ HP.ref containerRef ]
    [ someContent ]

...

eval (ScrollToBottom next) = do
  ref <- H.getHTMLElementRef containerRef
  for_ ref $ \el -> H.liftEff $ do
    let hel = htmlElementToElement el
    sh <- scrollHeight hel
    oh <- offsetHeight el
    let maxScroll = sh - oh
    setScrollTop maxScroll hel
  pure next