Files
it-know-how/vue/02-Templates, v-model, and Events.md
2026-03-27 12:58:01 +01:00

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, email changes
  • 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
  • title is shown to the user
  • value is stored in selectedPeriodStartFrom

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:

  1. Is it displaying a value?
  2. Is it binding a prop?
  3. Is it listening for an event?
  4. Which script variable or function does it connect to?
<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
  • searchText updates
  • paragraph updates immediately
  • button disable state updates immediately
  • clicking Search uses current searchText