Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to auto-scroll to the bottom of a div in Elm

Tags:

elm

elm-port

I add <div>s to a wrapper <div> and I need to be able to scroll to the last one added each time. How do I do this in Elm?

<div class="messages" style="height: 7em; overflow: scroll">
  <div>Anonymous: Hello</div>
  <div>John: Hi</div>
</div>

Intuitively, it seems like I could call a port that runs the JavaScript code element.scrollTop = element.scrollHeight:

AddChatMessage chatMessage ->
  ( { model | chatMessages = model.chatMessages ++ [ chatMessage ] } , scrollToBottomPort "div.messages" )

The problem is scrollToBottom gets called before the model gets updated. So no big deal, I convert that into a Task. But still, even though the model gets updated first now, the view does not get updated yet. So I end up scrolling to the 2nd item from the bottom!

This maybe leads to a more general question I'm curious about in Elm, how do you run a Cmd after the view is updated due to a change in the model?

like image 305
at. Avatar asked Dec 09 '16 03:12

at.


1 Answers

As of Elm 0.19, with functions Browser.Dom.getViewportOf and Browser.Dom.setViewportOf you can go to the bottom of the container everytime the new element is added to it.

jumpToBottom : String -> Cmd Msg
jumpToBottom id =
    Dom.getViewportOf id
        |> Task.andThen (\info -> Dom.setViewportOf id 0 info.scene.height)
        |> Task.attempt (\_ -> NoOp)
like image 158
MooMoo Avatar answered Sep 24 '22 17:09

MooMoo