Form
This component provides a structured and validated form for creating or editing subscription plans. It utilizes Vue's Composition API along with Joi for form validation and emits an event upon submission or cancellation.
Features Input fields for Plan Name, Subscription Fee, and Plan Status
Field-level validation with real-time error display
Custom form input components (FormText, FormSelect)
Submission loading state handling
Emits close event on cancel or successful validation
Template Structure
<template>
<form @submit.prevent="onSubmit">
<!-- Plan Name Field -->
<FormText
label="Plan Name"
v-model="planName"
placeholder="Standard"
@input="validateField('planName')"
/>
<span v-if="errors.planName">{{ errors.planName }}</span>
<!-- Subscription Fee Field -->
<FormText
label="Subscription Fee"
v-model="subscription"
placeholder="Enter amount"
@input="validateField('subscription')"
/>
<span v-if="errors.subscription">{{ errors.subscription }}</span>
<!-- Plan Status Dropdown -->
<FormSelect
label="Plan Status"
v-model="status"
:options="statusOption"
placeholder="Select option"
/>
<span v-if="errors.status">{{ errors.status }}</span>
<!-- Form Actions -->
<div class="flex gap-4 pt-3">
<CommonButton title="Cancel" type="button" @click="emit('close')" />
<CommonButton title="Save" type="submit" :loading="isLoading" />
</div>
</form>
</template>
Script Setup
<script setup>
import { ref, computed } from 'vue'
import Joi from 'joi'
import FormSelect from '../components/common/input/FormSelect.vue'
import FormText from '~/components/common/input/FormText.vue'
const emit = defineEmits(['close'])
const statusOption = [
{ name: 'Active', value: 'Active' },
{ name: 'Inactive', value: 'Inactive' }
]
const planName = ref('')
const subscription = ref('')
const status = ref('')
const errors = ref({})
const isLoading = ref(false)
const isFormValid = computed(() => {
return (
planName.value && subscription.value && status.value && Object.keys(errors.value).length === 0
)
})
// Validation is handled using Joi schema:
const validationSchema = Joi.object({
planName: Joi.string().trim().required().messages({
'any.required': 'Plan name is required',
'string.empty': 'Plan name is required'
}),
subscription: Joi.number().min(0).required().messages({
'any.required': 'Subscription fee is required',
'number.base': 'Subscription fee must be a number',
'number.min': 'Subscription fee must be at least 0',
'string.empty': 'Subscription fee is required'
}),
status: Joi.string().required().messages({
'any.required': 'Plan status is required',
'string.empty': 'Plan status is required'
})
})
// The validateForm function checks all fields and assigns error messages to the errors object:
const validateForm = () => {
const formData = {
planName: planName.value,
subscription: subscription.value,
status: status.value
}
const { error } = validationSchema.validate(formData, { abortEarly: false })
errors.value = {}
if (error) {
error.details.forEach((err) => {
errors.value[err.path[0]] = err.message
})
}
}
// The onSubmit function validates the form and emits the close event if valid:
const onSubmit = async () => {
validateForm()
if (isFormValid.value) {
// Call Api
}
}
</script>