How to automatically scroll the bottom of a div in Elm

I am adding a <div> to the <div> wrapper, and I need to be able to scroll to the last one added each time. How to do it in Elm?

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

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

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

Problem: scrollToBottom gets called before model updated. So it doesn’t matter, I convert it to Task . But still, even if the model now being updated, the view has not yet been updated. Therefore, I finish scrolling to the second element from the bottom!

This may lead to a more general question that interests me in Elm, how do you run Cmd after updating the view due to a model change?

+7
source share
3 answers

You can use the port to scroll to the bottom of the list.
In this case, you need to install javascript to wait for 1 AnimationFrame before doing the scroll. To make sure your list is displayed.

An easier way to do this is to use the Elm Dom.Scroll library.
And use the toBottom function.

If you included this in your code as follows:

 case msg of Add -> ( model ++ [ newItem <| List.length model ] , Task.attempt (always NoOp) <| Scroll.toBottom "idOfContainer" ) NoOp -> model ! [] 

It should work. I made a working example here in runelm.io

+7
source

Dom.Scroll is definitely a path that is easy to implement.

  • Set the incoming HTML element that you want to scroll to have a separate I would.
  • Verify that the specified item has an overflow style of-y: scroll or overflow-x: scroll.
  • Sending a command from any message actually causes the item to open / open (the message opens / displays the item, and the command that you run will scroll). Please note that you are using the command because modifying the DOM is technically a side effect.

Looking at the documentation, let's say scrolling below: toBottom : Id -> Task Error () , you can see that this should be a task, so you can wrap it in Task.attempt . For example: Task.attempt (\_ -> NoOp) (Dom.Scroll.toBottom Id)

Then you need a function to convert Result Error () to Msg, but since scrolling is unlikely to fail, or has a slight flaw, if this happens, you can configure a dummy function, for example (\_ -> NoOp) , how to hack quickly.

+1
source

Starting with version 0.19 Dom deprecated instead, you can set the scroll position using the Html.Attribute.property function.

example

 import Html exposing (Html, text) import Html.Attributes exposing (class, property) import Json.Encode as Encode view : Model -> Html Msg view model = div [ class "flow-editor" , property "scrollLeft" (Encode.float model.scrollLeft) , property "scrollTop" (Encode.float model.scrollTop) ] [ text "placeholder" ] 
0
source

Source: https://habr.com/ru/post/1013017/


All Articles