Have you ever found yourself writing repetitive watcher code for form fields in Vue? Or struggled with debouncing form updates to prevent API spam? Today, I'll introduce you to vue-form-watchers
, a lightweight utility that makes form state management in Vue 3 a breeze.
The Problem
In typical Vue applications, managing form state often involves:
- Setting up individual watchers for each form field
- Implementing debouncing to prevent excessive API calls
- Handling programmatic updates without triggering watchers
- Adding new form fields and their corresponding watchers
This leads to boilerplate code that looks something like this:
const form = ref({
username: '',
email: '',
age: 0
})
// Individual watchers for each field
watch(() => form.value.username, debounce((value) => {
updateServer('username', value)
}, 500))
watch(() => form.value.email, debounce((value) => {
updateServer('email', value)
}, 500))
watch(() => form.value.age, debounce((value) => {
updateServer('age', value)
}, 500))
Enter vue-form-watchers
vue-form-watchers
solves these problems by providing a simple, declarative way to handle form state changes. Here's how to get started:
npm install vue-form-watchers
Basic Usage
import { ref } from 'vue'
import { createFormWatchers } from 'vue-form-watchers'
const form = ref({
username: '',
email: '',
age: 0
})
createFormWatchers(
form.value,
(key, value) => {
console.log(`${key} changed to ${value}`)
// Handle the update (e.g., API calls, validation)
},
{
debounceTime: 300 // Optional: default is 500ms
}
)
That's it! The library automatically creates debounced watchers for all form fields.
Real-World Examples
1. Auto-Saving Draft Posts
Here's how you can implement an auto-saving draft system for a blog editor:
import { ref } from 'vue'
import { createFormWatchers } from 'vue-form-watchers'
export default {
setup() {
const draft = ref({
title: '',
content: '',
tags: []
})
const { markUpdateAsExternal } = createFormWatchers(
draft.value,
async (key, value) => {
try {
await api.saveDraft({ [key]: value })
toast.success('Draft saved')
} catch (error) {
toast.error('Failed to save draft')
}
},
{
debounceTime: 1000 // Wait for 1 second of inactivity
}
)
// Load existing draft
const loadDraft = async () => {
const savedDraft = await api.getDraft()
markUpdateAsExternal(() => {
Object.assign(draft.value, savedDraft)
})
}
return { draft, loadDraft }
}
}
2. Real-Time Form Validation
Here's how to implement real-time validation with error messages:
import { ref } from 'vue'
import { createFormWatchers } from 'vue-form-watchers'
export default {
setup() {
const form = ref({
email: '',
password: '',
confirmPassword: ''
})
const errors = ref({})
createFormWatchers(
form.value,
async (key, value) => {
errors.value[key] = await validateField(key, value, form.value)
},
{
debounceTime: 300,
immediate: true // Validate fields immediately
}
)
async function validateField(key, value, formData) {
switch (key) {
case 'email':
return !value.includes('@') ? 'Invalid email' : null
case 'password':
return value.length < 8 ? 'Password too short' : null
case 'confirmPassword':
return value !== formData.password ? 'Passwords do not match' : null
}
}
return { form, errors }
}
}
3. Multi-Step Form with API Updates
For complex forms that span multiple steps:
import { ref } from 'vue'
import { createFormWatchers } from 'vue-form-watchers'
export default {
setup() {
const userForm = ref({
// Step 1: Basic Info
firstName: '',
lastName: '',
email: '',
// Step 2: Address
street: '',
city: '',
country: '',
// Step 3: Preferences
notifications: false,
theme: 'light'
})
const { markUpdateAsExternal } = createFormWatchers(
userForm.value,
async (key, value, source) => {
if (source === 'user') {
await api.updateUserProfile({ [key]: value })
}
},
{
skipExternalUpdates: true,
isExternalUpdate: (key, newValue, oldValue) => {
// Custom logic to determine external updates
return false
}
}
)
return { userForm }
}
}
Advanced Features
1. Handling External Updates
The library provides a markUpdateAsExternal
utility for handling programmatic updates without triggering the update callback:
const { markUpdateAsExternal } = createFormWatchers(form.value, updateCallback)
// Later, when updating form programmatically:
markUpdateAsExternal(() => {
form.value.username = 'John'
form.value.email = 'john@example.com'
})
2. Debug Mode
Enable debug mode during development to get detailed logs:
createFormWatchers(form.value, updateCallback, {
debug: process.env.NODE_ENV === 'development'
})
Why Use vue-form-watchers?
- Zero Dependencies: Apart from Vue 3, the package has no external dependencies
- TypeScript Support: Full TypeScript support with type definitions
- Automatic Property Detection: Automatically handles new properties added to the form
- Performance: Built-in debouncing prevents excessive updates
- Small Bundle Size: Lightweight and optimized for production
Conclusion
vue-form-watchers
simplifies form state management in Vue 3 applications by providing a clean, declarative API for handling form updates. It eliminates boilerplate code while adding powerful features like debouncing and external update handling.
Whether you're building a simple contact form or a complex multi-step wizard, this utility can help you write cleaner, more maintainable code.
Give it a try in your next Vue project and let me know how it works for you! The package is open source and available on GitHub.
Happy coding! ๐
Top comments (0)