The documentation for setViewportOf
includes a function jumpToBottom
.
Below is a small example program which uses it:
module Main exposing (..)
import Browser
import Html exposing (..)
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import Browser.Dom
import Task
type Msg = AddText | NoOp
type alias Model = { messages : List String }
jumpToBottom : String -> Cmd Msg
jumpToBottom id =
Browser.Dom.getViewportOf id
|> Task.andThen (\info -> Browser.Dom.setViewportOf id 0 info.scene.height)
|> Task.attempt (\_ -> NoOp)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
AddText -> ({ model | messages = model.messages ++ [ "abc" ]}, jumpToBottom "messages")
NoOp -> (model, Cmd.none)
view : Model -> Html Msg
view model =
div [ id "outer" ]
[
div [ id "messages" ]
[
ul [] (List.map (\message -> li [] [ text message ]) model.messages)
],
button [ onClick AddText ] [ text "Add" ]
]
init : () -> (Model, Cmd Msg)
init _ = ({ messages = [] }, Cmd.none)
main = Browser.element { init = init, view = view, update = update, subscriptions = (\_ -> Sub.none) }
This program can be pasted into Try Elm to test it out.
Each time you press the button, text will be added to the page. Eventually, more text than can fit on the screen will be added and the scrollbar will appear. I'd like for the page to scroll automatically, but that doesn't seem to be happening.
If I change
jumpToBottom "messages"
to
jumpToBottom "outer"
that does not seem to have an effect.
Any suggestions are welcome! :-)
This is a CSS layout problem. To better understand, add this to your page CSS (you can test this on https://ellie-app.com/ ).
#messages {
max-height: 200px;
overflow-y:auto;
}
The above makes messages
a scrollable element that can have its viewport set. Without some kind of constrain on the height, the messages
div will just expand as needed and the viewport will always be the same as the scene, or, in other words, it will never scroll.