Going further
Infinite scroll
Load the next page of a list when the user scrolls to the bottom.
The controller
Wrap the list in scroll(). Your function returns one page of rows and tells nestjs-mvc which pages come before and after it.
import { Controller, Get, Query } from '@nestjs/common'
import { View, scroll } from 'nestjs-mvc'
@Controller('posts')
export class PostsController {
constructor(private readonly posts: PostsService) {}
@Get()
@View('Posts/Index')
index(@Query('page') page = '1') {
const current = Number(page)
return {
posts: scroll(async () => {
const [rows, total] = await this.posts.findPage(current, 20)
return {
data: rows,
currentPage: current,
previousPage: current > 1 ? current - 1 : null,
nextPage: current * 20 < total ? current + 1 : null,
}
}),
}
}
}
The rows go under data. On the last page nextPage is null, and that tells the browser to stop.
The page
Wrap the list in InfiniteScroll and name the prop:
import { InfiniteScroll } from 'nestjs-mvc/react'
interface Props {
posts: { data: { id: number; title: string }[] }
}
export default function Index({ posts }: Props) {
return (
<InfiniteScroll data="posts">
{posts.data.map((post) => (
<article key={post.id}>{post.title}</article>
))}
</InfiniteScroll>
)
}
<script setup lang="ts">
import { InfiniteScroll } from 'nestjs-mvc/vue'
defineProps<{ posts: { data: { id: number; title: string }[] } }>()
</script>
<template>
<InfiniteScroll data="posts">
<article v-for="post in posts.data" :key="post.id">{{ post.title }}</article>
</InfiniteScroll>
</template>
As the end of the list comes into view, the browser asks your controller for ?page=2 and adds those rows under the ones it already has.
Starting in the middle
If you open /posts?page=5, the list starts at page 5. Scrolling down loads page 6, and scrolling up puts page 4 in front.
Filters
When a filter changes, the list has to start over, or the new results get added to the old ones. Pass reset for that:
router.get('/posts', { tag }, { only: ['posts'], reset: ['posts'] })
Extra information
Anything else you return next to data gets to the page as it is, which is handy for something like "Showing 20 of 340":
return { data: rows, total, currentPage: current, previousPage, nextPage }