N
Nuxt3mo ago
Insight

Pagination files/folder duplicated code between root and pages?

I have been working with nuxt 3 and nuxt content and trying to add pagination. from the picture you can see my rough outline of the folders/pages. I am wondering is there a way to make the /blog/index the same as /blog/page/1 so I don't have to duplicate code between the 2 different pages? I have been trying to find if there is a more intuitive way to accomplish this and saw some posts online about a 301 redirect but they all had other ways which didn't work in my project. I expect the pages to look something like the following. /blog/ - Root which shows all blog posts with pagination (really just /blog/page/1) /blog/2024/05/01 - A single blog post /blog/page/2 - Page 2
No description
20 Replies
Single
Single3mo ago
You can add an index.vue to /blog and create a component that is being used from within this index.vue and /blog/page/[page]. Or, you can redirect from /blog(/index.vue) to /blog/page/1 if you don't mind. I am not sure if aliases could help you here too:
/**
* Aliases for the record. Allows defining extra paths that will behave like a
* copy of the record. Allows having paths shorthands like `/users/:id` and
* `/u/:id`. All `alias` and `path` values must share the same params.
*/
alias?: string | string[];
/**
* Aliases for the record. Allows defining extra paths that will behave like a
* copy of the record. Allows having paths shorthands like `/users/:id` and
* `/u/:id`. All `alias` and `path` values must share the same params.
*/
alias?: string | string[];
Insight
Insight3mo ago
What would be considered more standard? I am somewhat new to nuxt so trying to do things in a way that make most sense
pyplacca
pyplacca3mo ago
Is there a reason why you’re opting to use subpages for that kind of pagination instead of query parameters?
Insight
Insight3mo ago
Just basing things off tutorials I have seen
pyplacca
pyplacca3mo ago
I see. For simplicity use a query parameter and treat the page number as a state since that’s what it is Don’t complicate your work
Insight
Insight3mo ago
Would you happen to have an example of what that would look like? That is what I was initially thinking but everthing I found showed it set up like I have it in my initial post I come from c# land with asp.net so lots of the stuff in js/typescript is new to me
pyplacca
pyplacca3mo ago
Follow @Single’s suggestion of creating an index file in the blog folder One moment
Insight
Insight3mo ago
I have that, the index you see at the bottom is inside the blog folder. but all the stuff I have seen is to use the folders and slugs for things like the pages of blog posts
pyplacca
pyplacca3mo ago
@Insight https://stackblitz.com/edit/github-ovypvr?file=pages%2Fblog%2Findex.vue,app.vue PS: you don't need the catch-all route for the single blog post page. You can see from the structure in the link I've shared
Insight
Insight3mo ago
intersting, so 2 questions from that. 1. the goToPage doesn't appear to change the actual url itself, is it supposed to? 2. First time seeing the +() from a quick search is it just trying to turn it into a number?
pyplacca
pyplacca3mo ago
1. it does. I'm just not sure how the preview window in Stackblitz handles it. you can try it locally 2. yeahh. type coercion 😃 using the url to manage the state is just one way. there're other ways, but url as a state manager seems to be getting a comeback with web apps
Insight
Insight3mo ago
Thanks! I haven't been able to get to this just yet... I have been so busy... I plan to give it a try soon though!
pyplacca
pyplacca3mo ago
No worries
Insight
Insight3mo ago
@pyplacca I got it working, however I am running into a situation where I have to call refreshNuxtData() here is the code. Is ther a way to make it refresh with out using that? Or is that expected to be used in a situation like this?
<script setup lang="ts">
const pageSize = 1;
const page = computed(() => +(useRoute().query.page || 1));

const route = useRoute();
const count = await queryContent('/blog').sort({ _path: -1 }).count()
const { data } = await useAsyncData(() => queryContent('/blog').limit(pageSize).skip((page.value - 1) * pageSize).sort({ _path: -1 }).find());



async function goToPage(n: number) {

if(n == 1){
navigateTo(`/blog`, { replace: true });
} else {
navigateTo(`?page=${n}`, { replace: true });
}


const data = await queryContent('/blog').limit(pageSize).skip((n - 1) * pageSize).sort({ _path: -1 }).find();
refreshNuxtData();
}
</script>

<template>

<div class="max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto">
<div class="flex gap-6">
<div class="flex-1 p-6 bg-white shadow-md dark:bg-slate-800 rounded-xl">

<BlogArticleList :articles="data" />

<Pagination :page="page" :perPage="pageSize" :total="count" @changePage="goToPage" />
</div>
<div class="flex-none w-4/12 p-6 bg-white shadow-md dark:bg-slate-800 rounded-xl">
<BlogTag v-for="(value, key) in tagsArray" :href="'/blog/tag/' + encodeURIComponent(value.name)"
:tag="value" />
</div>
</div>
</div>

</template>
<script setup lang="ts">
const pageSize = 1;
const page = computed(() => +(useRoute().query.page || 1));

const route = useRoute();
const count = await queryContent('/blog').sort({ _path: -1 }).count()
const { data } = await useAsyncData(() => queryContent('/blog').limit(pageSize).skip((page.value - 1) * pageSize).sort({ _path: -1 }).find());



async function goToPage(n: number) {

if(n == 1){
navigateTo(`/blog`, { replace: true });
} else {
navigateTo(`?page=${n}`, { replace: true });
}


const data = await queryContent('/blog').limit(pageSize).skip((n - 1) * pageSize).sort({ _path: -1 }).find();
refreshNuxtData();
}
</script>

<template>

<div class="max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto">
<div class="flex gap-6">
<div class="flex-1 p-6 bg-white shadow-md dark:bg-slate-800 rounded-xl">

<BlogArticleList :articles="data" />

<Pagination :page="page" :perPage="pageSize" :total="count" @changePage="goToPage" />
</div>
<div class="flex-none w-4/12 p-6 bg-white shadow-md dark:bg-slate-800 rounded-xl">
<BlogTag v-for="(value, key) in tagsArray" :href="'/blog/tag/' + encodeURIComponent(value.name)"
:tag="value" />
</div>
</div>
</div>

</template>
pyplacca
pyplacca3mo ago
Add the page as a watch dependency
Nuxt
useAsyncData · Nuxt Composables
useAsyncData provides access to data that resolves asynchronously in an SSR-friendly composable.
pyplacca
pyplacca3mo ago
Also, if your ever need to trigger a refresh, you can use the execute or refresh method the composable returns
Nuxt
useAsyncData · Nuxt Composables
useAsyncData provides access to data that resolves asynchronously in an SSR-friendly composable.
Insight
Insight3mo ago
huh interesting. so much to learn and remember lol. Thanks for all your help! I appreciate it
pyplacca
pyplacca3mo ago
You’ll get the hang of it in no time. My pleasure
Insight
Insight3mo ago
haven't even really gotten into state or using database or user authentication...
pyplacca
pyplacca3mo ago
Don’t worry. You will with time