Het patroon
Een login- of register-form is een gewoon Vue formulier dat na succes drie dingen doet:
- De auth store updaten via
auth.login(user) - De gebruiker doorsturen naar het dashboard met
router.push() - Errors tonen als er iets misging
Deze pagina bouwt voort op Forms, Auth Store Setup en useRouter.
Login formulier
<!-- src/views/LoginView.vue -->
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
const router = useRouter()
const auth = useAuthStore()
const email = ref('')
const password = ref('')
const error = ref('')
const handleLogin = () => {
error.value = ''
// Validatie
if (!email.value || !password.value) {
error.value = 'Vul alle velden in'
return
}
// Voor nu: dummy login (geen echte API)
// Bij echte app: fetch naar /api/login (zie verderop)
auth.login({
email: email.value,
name: email.value.split('@')[0]
})
router.push('/dashboard')
}
</script>
<template>
<form @submit.prevent="handleLogin" class="auth-form">
<h1>Inloggen</h1>
<label>
Email:
<input v-model="email" type="email" required />
</label>
<label>
Wachtwoord:
<input v-model="password" type="password" required />
</label>
<p v-if="error" class="error">{{ error }}</p>
<button type="submit">Inloggen</button>
<p>
Nog geen account?
<RouterLink to="/register">Registreer</RouterLink>
</p>
</form>
</template>
Vier kritieke regels:
@submit.prevent— voorkomt page refreshauth.login(...)— vult de Pinia storerouter.push('/dashboard')— stuurt doorerrorref voor feedback
Register formulier
Vrijwel identiek aan login — met een extra naam-veld en password-bevestiging.
<!-- src/views/RegisterView.vue -->
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
const router = useRouter()
const auth = useAuthStore()
const form = ref({
name: '',
email: '',
password: '',
confirmPassword: ''
})
const error = ref('')
const handleRegister = () => {
error.value = ''
// Validatie
if (form.value.password.length < 8) {
error.value = 'Wachtwoord moet minimaal 8 tekens zijn'
return
}
if (form.value.password !== form.value.confirmPassword) {
error.value = 'Wachtwoorden komen niet overeen'
return
}
// Account aanmaken + meteen inloggen
auth.login({
name: form.value.name,
email: form.value.email
})
router.push('/dashboard')
}
</script>
<template>
<form @submit.prevent="handleRegister" class="auth-form">
<h1>Account aanmaken</h1>
<label>
Naam:
<input v-model="form.name" type="text" required />
</label>
<label>
Email:
<input v-model="form.email" type="email" required />
</label>
<label>
Wachtwoord:
<input v-model="form.password" type="password" required />
</label>
<label>
Herhaal wachtwoord:
<input v-model="form.confirmPassword" type="password" required />
</label>
<p v-if="error" class="error">{{ error }}</p>
<button type="submit">Registreer</button>
</form>
</template>
Met een echte API
In een echte app vraag je de server om in te loggen. Vervang de dummy auth.login() aanroep door een fetch:
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
const router = useRouter()
const auth = useAuthStore()
const email = ref('')
const password = ref('')
const error = ref('')
const loading = ref(false)
const handleLogin = async () => {
error.value = ''
loading.value = true
try {
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: email.value,
password: password.value
})
})
if (!res.ok) {
throw new Error('Ongeldige inloggegevens')
}
const userData = await res.json()
auth.login(userData)
router.push('/dashboard')
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
}
</script>
<template>
<form @submit.prevent="handleLogin">
<input v-model="email" type="email" />
<input v-model="password" type="password" />
<p v-if="error">{{ error }}</p>
<button type="submit" :disabled="loading">
{{ loading ? 'Bezig...' : 'Inloggen' }}
</button>
</form>
</template>
Het patroon is precies wat je leerde op de Loading & Error pagina: loading, error, finally. Hier toegepast op een form-submit i.p.v. een GET-fetch.
Belangrijke Regels
- Altijd
@submit.preventop het<form> - Na
auth.login()meteenrouter.push() - Error feedback via een ref, niet alleen
alert() - Disable de submit-knop tijdens loading bij echte API-calls
- Wachtwoord nooit in localStorage — alleen het token of user-object
Veelgemaakte Fouten
Fout — geen redirect na login:
const handleLogin = () => {
auth.login({ name: email.value })
// ❌ user blijft op login-pagina staan
}
Goed:
const handleLogin = () => {
auth.login({ name: email.value })
router.push('/dashboard') // ✅
}
Fout — error niet resetten:
const handleLogin = async () => {
// ❌ error van vorige poging blijft staan tijdens nieuwe poging
try { ... } catch (e) { error.value = e.message }
}
Goed — reset bovenaan:
const handleLogin = async () => {
error.value = '' // ✅ reset
try { ... } catch (e) { error.value = e.message }
}