Getting started

Links

Use Link instead of <a> to move between pages without a full reload.

import { Link } from 'nestjs-mvc/react'

export default function Home() {
  return <Link href="/users">All users</Link>
}
<script setup lang="ts">
import { Link } from 'nestjs-mvc/vue'
</script>

<template>
  <Link href="/users">All users</Link>
</template>

Link renders a regular <a> tag. When someone clicks it, it gets the data for /users from your controller and swaps the page. The URL and the back button keep working like you'd expect.

A link can also send a POST, PUT, PATCH or DELETE. Since it's really a button at that point, render it as one:

<Link href="/logout" method="post" as="button">
  Log out
</Link>

<Link href={`/users/${user.id}`} method="delete" as="button">
  Delete
</Link>
<Link href="/logout" method="post" as="button">
  Log out
</Link>

<Link :href="`/users/${user.id}`" method="delete" as="button">
  Delete
</Link>

On the server it's a regular route:

@Delete(':id')
async remove(@Param('id', ParseIntPipe) id: number) {
  await this.users.remove(id)
  return this.view.redirect('/users')
}

After you change something, redirect to a page. The redirects page explains why.

Sometimes you want to navigate from a click handler or a search box. That's what router is for:

import { router } from 'nestjs-mvc/react'

function Search() {
  return (
    <input
      placeholder="Search"
      onChange={(e) => router.get('/users', { search: e.target.value }, { preserveState: true, replace: true })}
    />
  )
}
<script setup lang="ts">
import { router } from 'nestjs-mvc/vue'

function search(event: Event) {
  const value = (event.target as HTMLInputElement).value
  router.get('/users', { search: value }, { preserveState: true, replace: true })
}
</script>

<template>
  <input placeholder="Search" @input="search" />
</template>

router.get('/users', { search }) visits /users?search=..., and your controller reads the value with @Query('search').

With preserveState: true, whatever the user typed stays in the input while the page updates. And replace: true updates the current entry in the browser's history instead of adding one, so the back button doesn't step through every letter.

If only part of the page depends on the search, you can ask for just that part. Loading only what you need shows how.

Keep the scroll position

After a visit the page scrolls back to the top. If you'd rather stay where you are, add preserveScrollpreserve-scroll:

<Link href="/users?page=2" preserveScroll>
  Next page
</Link>
<Link href="/users?page=2" preserve-scroll>
  Next page
</Link>

The current URL

usePage gives you the current URL, which is useful for highlighting the active menu item:

import { Link, usePage } from 'nestjs-mvc/react'

function Menu() {
  const { url } = usePage()

  return (
    <Link href="/users" className={url.startsWith('/users') ? 'active' : ''}>
      Users
    </Link>
  )
}
<script setup lang="ts">
import { Link, usePage } from 'nestjs-mvc/vue'

const page = usePage()
</script>

<template>
  <Link href="/users" :class="{ active: page.url.startsWith('/users') }">
    Users
  </Link>
</template>

Load before the click

A link can fetch its page as soon as the mouse is over it, so the page is there the moment someone clicks. See Prefetching.