FabienHenon / elm-infinite-list-view / InfiniteList

Displays a virtual infinite list of items by only showing visible items on screen. This is very useful for very long list of items.

This way, instead of showing you 100+ items, with this package you will only be shown maybe 20 depending on their height and your configuration.

How it works: A div element is using the full height of your entire list so that the scroll bar shows a long content. Inside this element we show a few items to fill the parent element and we move them so that they are visible. Which items to show is computed using the scrollTop value from the scroll event.

Initialization

init : Model

Creates a new Model.

initModel : Model
initModel =
    { infiniteList = InfiniteList.init }

Configuration

config : { itemView : Basics.Int -> Basics.Int -> item -> Html msg, itemHeight : ItemHeight item, containerHeight : Basics.Int } -> Config item msg

Creates a new Config. This function will need a few mandatory parameters and you will be able to customize it more with with... functions

config : InfiniteList.Config String msg
config =
    InfiniteList.config
        { itemView = itemView
        , itemHeight = InfiniteList.withConstantHeight 20
        , containerHeight = 300
        }

itemView : Int -> Int -> String -> Html Msg
itemView idx listIdx item =
    -- view code

The itemView parameter is the function used to render each item of your list. Parameters of this function are

Note: If you can't know the exact container's height it's not a problem. Just specify a height you are sure is greater than the maximum possible container's height. You can also specify the window's height. Having a height greater than the actual container's height will just make you show a little more items than if you specified the exact container's height.

withConstantHeight : Basics.Int -> ItemHeight item

Specifies that the items' height will always be the same. This function needs the height of the items

config : InfiniteList.Config String msg
config =
    InfiniteList.config
        { itemView = itemView
        , itemHeight = InfiniteList.withConstantHeight 20
        , containerHeight = 300
        }

withVariableHeight : (Basics.Int -> item -> Basics.Int) -> ItemHeight item

Specifies that the items' height will change according to the item. This function needs a function taking the index of the item in your list of items, and the current item. It must return the item's height

config : InfiniteList.Config String msg
config =
    InfiniteList.config
        { itemView = itemView
        , itemHeight = InfiniteList.withVariableHeight getItemHeight
        , containerHeight = 300
        }

getItemHeight : Int -> String -> Int
getItemHeight idx item =
    if remainderBy 2 idx == 0 then
        20

    else
        40

withKeepFirst : Basics.Int -> Config item msg -> Config item msg

Specifies the number of elements on the top of the list to always render.

This can be used if the first element is a header which is shown sticky for example.

The default is 0, removing all items from the top when scrolling down.

Scroll

onScroll : (Model -> msg) -> Html.Attribute msg

This function returns the onScroll attribute to be added to the attributes of your infinite list container.

type Msg
    = InfiniteListMsg InfiniteList.Model

view : Model -> Html Msg
view model =
    div
        [ style "width" "100%"
        , style "height" "100%"
        , style "overflow-x" "hidden"
        , style "overflow-y" "auto"
        , style "-webkit-overflow-scrolling" "touch"
        , InfiniteList.onScroll InfiniteListMsg
        ]
        [ InfiniteList.view config model.infiniteList list ]

View

view : Config item msg -> Model -> List item -> Html msg

Function used to display your long list

The element's height must be explicitly set, otherwise scroll event won't be triggered

config : InfiniteList.Config String Msg
config =
    InfiniteList.config
        { itemView = itemView
        , itemHeight = InfiniteList.withConstantHeight 20
        , containerHeight = 300
        }

itemView : Int -> Int -> String -> Html Msg
itemView idx listIdx item =
    div [] [ text item ]

view : Model -> Html Msg
view model =
    div
        [ style "width" "100%"
        , style "height" "100%"
        , style "overflow-x" "hidden"
        , style "overflow-y" "auto"
        , style "-webkit-overflow-scrolling" "touch"
        , InfiniteList.onScroll InfiniteListMsg
        , id "myslist" -- set an HTML id if you want to use scrollToNthItem later
        ]
        [ InfiniteList.view config model.infiniteList list ]

Customization

withOffset : Basics.Int -> Config item msg -> Config item msg

Changes the default offset.

The offset is a value that represents a margin at the top and bottom of the container so that items will be displayed up to these margins.

This avoids showing blank spaces as you scroll.

The default value is 200px. If you want more margin, you can specify a greater value, but be careful as it will display more items on screen.

withCustomContainer : (List ( String, String ) -> List (Html msg) -> Html msg) -> Config item msg -> Config item msg

Specifies a custom container to use instead of the default div one inside the top div container. The function to pass takes a list of styles you will have to apply, and a list of children (your items) you will have to display (See example below).

The default structure of this infinite list is:

div
    -- Top container --
    []
    [ div
        -- Items container --
        []
        [ items ]
    ]

For instance, if you want to display a list (li elements) you prably want to replace the default div container by an ul element. Here is how to do:

InfiniteList.withCustomContainer customContainer config

customContainer : List (String, String) -> List (Html msg) -> Html msg
customContainer styles children =
    ul [ style styles ] children

withClass : String -> Config item msg -> Config item msg

Specifies a class to set to the top container div.

withStyles : List ( String, String ) -> Config item msg -> Config item msg

Specifies styles to set to the top container div.

This module also specified styles that may override yours.

withId : String -> Config item msg -> Config item msg

Specifies an id to set to the top container div.

Advanced

updateScroll : Json.Decode.Value -> Model -> Model

Only use this function if you handle on "scroll" event yourself (for instance if another package is also using the scroll event on the same node)

You have to pass it a Json.Decode.Value directly coming from on "scroll" event you handle, and the Model. It returns the updated Model

type Msg
    = OnScroll JsonDecoder.Value

view : Model -> Html Msg
view model =
    div
        [ style "width" "100%"
        , style "height" "100%"
        , style "overflow-x" "hidden"
        , style "overflow-y" "auto"
        , style "-webkit-overflow-scrolling" "touch"
        , on "scroll" (JsonDecoder.map OnScroll JsonDecoder.value)
        ]
        [ InfiniteList.view config model.infiniteList list ]

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        -- ... --
        OnScroll value ->
            ( { model | infiniteList = InfList.updateScroll value model.infiniteList }, Cmd.none )

scrollToNthItem : { postScrollMessage : msg, listHtmlId : String, itemIndex : Basics.Int, configValue : Config item msg, items : List item } -> Platform.Cmd.Cmd msg

Function used to change the list scrolling from your program, so that the nth item of the list is displayed on top

Types


type Model

Model of the infinite list module. You need to create a new one using init function.


type Config item msg

Configuration for your infinite list, describing the look and feel. Note: Your Config should never be held in your model. It should only appear in view code.


type ItemHeight item

Item height description