4.4 KiB
Executable File
Templates, v-model, and Events
This note explains how Vue templates talk to your script code.
Templates are HTML with Vue features
Example:
<template>
<p>{{ username }}</p>
<input v-model="username" />
<button @click="reset">Reset</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const username = ref('mathias');
function reset() {
username.value = '';
}
</script>
The same variable is:
- shown inside
{{ username }} - edited by
<input v-model="username" /> - changed by the
reset()function
{{ ... }}: show a value
<p>{{ username }}</p>
<p>{{ isLoading ? 'Loading...' : 'Done' }}</p>
<p>{{ 2 + 3 }}</p>
This is interpolation. It prints a value into the rendered HTML.
v-model: two-way binding
v-model connects a form field and a reactive variable.
<input v-model="email" />
const email = ref('');
Two-way binding means:
- if the user types,
emailchanges - if code changes
email, the input display changes
Example with a select
<v-select
v-model="selectedCountry"
:items="countries"
label="Country"
/>
const countries = ['Germany', 'France', 'Spain'];
const selectedCountry = ref<string | null>(null);
When the user picks France, selectedCountry.value becomes 'France'.
Your real example
From FlexibilityTable:
<v-select
v-model="selectedPeriodStartFrom"
:items="periodStartOptions"
item-title="title"
item-value="value"
label="Period start from"
/>
This means:
- the dropdown shows options from
periodStartOptions - each option is an object
titleis shown to the uservalueis stored inselectedPeriodStartFrom
If one item is:
{ title: '2026-03-23', value: '2026-03-23T23:00:00.000Z' }
then the user sees:
2026-03-23
but the stored value becomes:
selectedPeriodStartFrom.value = '2026-03-23T23:00:00.000Z';
Events with @click
@click means: call a function when the element is clicked.
<button @click="increment">Add</button>
function increment() {
count.value += 1;
}
Other common events:
<input @input="onInput" />
<form @submit.prevent="submitForm" />
<select @change="onChange" />
Binding attributes with :
The : shorthand means "bind this HTML or component prop to JavaScript".
<button :disabled="isLoading">Save</button>
Equivalent long form:
<button v-bind:disabled="isLoading">Save</button>
If isLoading is true, the button becomes disabled.
Example: disable refresh button
In your component:
<v-btn
:disabled="loading || !hasValidPeriodRange"
@click="applyDateFilters"
>
Refresh
</v-btn>
This means:
- disable the button if data is loading
- also disable it if the selected date range is invalid
- when clicked, run
applyDateFilters
Conditional rendering
Show something only if a condition is true:
<p v-if="errorMessage">{{ errorMessage }}</p>
<p v-else>No errors</p>
Loops with v-for
<li v-for="user in users" :key="user.id">
{{ user.name }}
</li>
This repeats the element for each item.
Common beginner confusion: where does a template variable come from?
If you see this in a template:
<p>{{ total }}</p>
search the script for:
const total = ...let total = ...function total() ...computed(() => ...)defineProps(...)
The template only knows values exposed by the script.
Mental model for reading templates
For every template line, ask:
- Is it displaying a value?
- Is it binding a prop?
- Is it listening for an event?
- Which script variable or function does it connect to?
Mini Example: search box
<template>
<input v-model="searchText" placeholder="Search users" />
<button :disabled="!searchText" @click="search">Search</button>
<p>You entered: {{ searchText }}</p>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const searchText = ref('');
function search() {
console.log('Searching for', searchText.value);
}
</script>
Flow:
- user types into input
searchTextupdates- paragraph updates immediately
- button disable state updates immediately
- clicking Search uses current
searchText