Infinite scroll allows you to load more content for the user as they scroll (up or down).
The infinite scroll must be bound to an Html
element and will execute your own Cmd
when the user
scrolled to the bottom (or top) of the element.
The Cmd
can be anything you want from local data fetching or complex requests on remote APIs.
All it has to do is to return a Cmd msg
and call stopLoading
once fetching is finished so that
the infinite scroll can continue asking for more content.
Direction -> Platform.Cmd.Cmd msg
Definition of the function you must provide to the API. This function will be called as soon as new content is required
loadMore : InfiniteScroll.Direction -> Cmd Msg
loadMore dir =
Task.perform OnLoadMore <| Task.succeed dir
InfiniteScroll.init loadMore
Scroll direction.
Top
means new content will be asked when the user scrolls to the top of the elementBottom
means new content will be asked when the user scrolls to the bottom of the elementinit : LoadMoreCmd msg -> Model msg
Creates a new Model
. This function needs a LoadMoreCmd
that will be called when new data is required.
type Msg
= OnLoadMore InfiniteScroll.Direction
type alias Model =
{ infiniteScroll : InfiniteScroll.Model Msg }
loadMore : InfiniteScroll.Direction -> Cmd Msg
loadMore dir =
Task.perform OnLoadMore <| Task.succeed dir
initModel : Model
initModel =
{ infiniteScroll = InfiniteScroll.init loadMore }
timeout : Basics.Float -> Model msg -> Model msg
Sets a different timeout value (default is 5 seconds)
When timeout is exceeded stopLoading
will be automatically called so that infinite scroll can continue asking more content
event when previous request did not finished.
init loadMore
|> timeout (10 * 1000)
offset : Basics.Int -> Model msg -> Model msg
Sets a different offset (default 50).
Offset is the number of pixels from top or bottom (depending on Direction
value) from which infinite scroll
will detect it needs more content.
For instance with offset set to 50 and direction to Top
. Once scroll position is 50 pixels or less from the top of the element it will require new content.
The same applies with a direction set to Bottom
except it will check for the distance with the bottom of the element.
init loadMore
|> offset 100
direction : Direction -> Model msg -> Model msg
Sets a different direction (default to Bottom
).
A direction set to Bottom
will check distance of the scroll bar from the bottom of the element, whereas a direction set to Top
will check distance of the scroll bar from the top of the element.
init loadMore
|> direction Top
loadMoreCmd : LoadMoreCmd msg -> Model msg -> Model msg
Sets a different command to load content.
It is useful if you need to change your request between two commands. You probably use it when your request is received.
newRequest page =
Task.perform OnLoadMore <| Task.succeed page
{ model | infiniteScroll =
model.infiniteScroll
|> loadMoreCmd (newRequest model.page)
}
update : (Msg -> msg) -> Msg -> Model msg -> ( Model msg, Platform.Cmd.Cmd msg )
The update function must be called in your own update function. It will return an updated Model
and commands to execute.
type Msg
= InfiniteScrollMsg InfiniteScroll.Msg
type alias Model =
{ infiniteScroll : InfiniteScroll.Model Msg }
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
InfiniteScrollMsg msg_ ->
let
( infiniteScroll, cmd ) =
InfiniteScroll.update InfiniteScrollMsg msg_ model.infiniteScroll
in
( { model | infiniteScroll = infiniteScroll }, cmd )
infiniteScroll : (Msg -> msg) -> Html.Attribute msg
Function used to bind the infinite scroll on an element.
The element's height must be explicitly set, otherwise scroll event won't be triggered
type Msg
= InfiniteScrollMsg InfiniteScroll.Msg
view : Model -> Html Msg
view _ =
let
styles =
[ ( "height", "300px" ) ]
in
div [ infiniteScroll InfiniteScrollMsg, Attributes.style styles ]
[ -- Here will be my long list -- ]
stopLoading : Model msg -> Model msg
Stops loading. You should call this function when you have finished fetching new data. This tells infinite scroll that it can continue asking you more content.
If you forget to call this function or if your data fetching is too long, you will be asked to retrieve more content after timeout has expired.
startLoading : Model msg -> Model msg
Starts loading more data. You should never have to use this function has it is automatically called
when new content is required and your loadMore
command is executed.
isLoading : Model msg -> Basics.Bool
Checks if the infinite scroll is currently in a loading state.
Which means it won't ask for more data even if the user scrolls
cmdFromScrollEvent : (Msg -> msg) -> Json.Decode.Value -> Platform.Cmd.Cmd msg
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)
If you wish to use the document
scroll, you should create a port to catch the document scroll and
send it to this function via the subscriptions
The function returns a Cmd msg
that will perform the model update normally done with infiniteScroll
.
You have to pass it a Json.Decode.Value
directly coming from on "scroll"
event
type Msg
= InfiniteScrollMsg InfiniteScroll.Msg
| OnScroll JsonDecoder.Value
view : Model -> Html Msg
view model =
div [ on "scroll" (JsonDecoder.map OnScroll JsonDecoder.value) ] [ -- content -- ]
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
-- ... --
InfiniteScrollMsg msg_ ->
let
( infScroll, cmd ) =
InfiniteScroll.update InfiniteScrollMsg msg_ model.infScroll
in
( { model | infScroll = infScroll }, cmd )
OnScroll value ->
( model, InfiniteScroll.cmdFromScrollEvent InfiniteScrollMsg value )
onScrollUpdate : (Msg -> msg) -> Json.Decode.Value -> Model msg -> ( Model msg, Platform.Cmd.Cmd msg )
Like cmdFromScrollEvent
except it returns the updated Model
and the Cmd
to send instead of only a simple Cmd
that will be executed after
Model of the infinite scroll module. You need to create a new one using init
function.
Infinite scroll messages you have to give to the update
function.