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
})
const { destroy } = createFormWatchers(
form.value,
(key, value, source) => {
console.log(`${key} changed to ${value} from ${source}`)
// Handle updates (API calls, validation, etc.)
},
{
debounceTime: 300 // Optional: default is 500ms
}
)
// Clean up on component unmount
onUnmounted(() => destroy())
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)
})
}
onUnmounted(() => destroy())
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({})
const { markUpdateAsExternal, destroy } = 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
}
}
onUnmounted(() => destroy())
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. Custom External Update Detection
Define your own logic for identifying external updates:
createFormWatchers(form.value, updateCallback, {
isExternalUpdate: (key, newValue, oldValue) => {
return newValue === oldValue || key.startsWith('_')
}
})
2. Field Exclusions
Skip specific fields from triggering updates:
createFormWatchers(form.value, updateCallback, {
exclude: ['tempField', 'localOnly']
})
3. 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.
Start Using It Today
The library is open source and available on GitHub. If you find it useful, please consider giving it a ⭐️ star on GitHub - it helps other developers discover the package and motivates further development.
Give it a try in your next Vue project and let me know how it works for you!
Happy coding! 🚀
Top comments (0)