#vue #javascript #frontend

Day 4: User Interaction - Events & Forms

Welcome to Day 4! Today we turn our static pages into interactive applications by handling Events and Forms.

Event Handling: v-on or @

We’ve already seen @click. We can listen to any DOM event: input, keyup, submit, mouseover.

<script setup lang="ts">
function greet(event: Event) {
  alert('Hello ' + (event.target as HTMLElement).tagName)
}

function say(message: string) {
  alert(message)
}
</script>

<template>
  <!-- Pass the event object implicitly -->
  <button @click="greet">Greet</button>

  <!-- Pass arguments -->
  <button @click="say('Hello Vue!')">Say Hello</button>
</template>

Event Modifiers

Vue provides sweet shortcuts for common DOM patterns.

  • .prevent: Calls event.preventDefault() (great for forms).
  • .stop: Calls event.stopPropagation().
  • .once: triggers only once.
  • Key modifiers: .enter, .esc, .space.
<!-- Submits, but prevents page reload -->
<form @submit.prevent="onSubmit">...</form>

<!-- Triggers only when Enter is pressed -->
<input @keyup.enter="submit" />

Form Input Bindings: v-model

In the “old days”, you had to bind :value and listen to @input to sync state. v-model does this for you automatically. It creates a two-way binding.

<script setup lang="ts">
import { ref } from 'vue'

const text = ref('')
const checked = ref(false)
const selected = ref('A')
</script>

<template>
  <!-- Text Input -->
  <input v-model="text" placeholder="Type here..." />
  <p>You typed: {{ text }}</p>

  <!-- Checkbox (Boolean) -->
  <input type="checkbox" id="checkbox" v-model="checked" />
  <label for="checkbox">{{ checked }}</label>

  <!-- Select -->
  <select v-model="selected">
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <p>Selected: {{ selected }}</p>
</template>

v-model Modifiers

  • .lazy: Syncs on change event instead of input (user leaves the field).
  • .number: Automatically typecasts input to a number.
  • .trim: Strips whitespace.
<input v-model.number="age" type="number" />

Challenge for Day 4

  1. Create a “Registration Form”.
  2. Inputs: Name (text), Age (number), Newsletter (checkbox).
  3. On submit (prevent default!), show an alert with the data in JSON format: JSON.stringify(form.value).

Solution:

<script setup lang="ts">
import { reactive } from 'vue'

const form = reactive({
  name: '',
  age: 0,
  newsletter: false
})

function submitForm() {
  alert(JSON.stringify(form, null, 2))
}
</script>

<template>
  <form @submit.prevent="submitForm">
    <label>
      Name:
      <input v-model.trim="form.name" required />
    </label>
    
    <label>
      Age:
      <input v-model.number="form.age" type="number" />
    </label>

    <label>
      <input type="checkbox" v-model="form.newsletter" />
      Subscribe to newsletter?
    </label>

    <button type="submit">Register</button>
  </form>
</template>

<style scoped>
label { display: block; margin-bottom: 10px; }
</style>

Excellent! You can now capture user input. But what if we need to calculate something based on that input? That’s where Computed Properties come in. See you on Day 5!