Form Inputs Components

Bookings Form

The TextInput, SelectInput, CheckboxInput and TextAreaInput contains the most popular Input controls used by C# POCOs which can be bound directly to Request DTOs and includes support for declarative and Fluent Validation binding.

<form @submit.prevent="submit">
    <div class="shadow sm:overflow-hidden sm:rounded-md">
        <div class="space-y-6 py-6 px-4 sm:p-6 bg-white dark:bg-black">
            <div>
                <h3 class="text-lg font-medium leading-6 text-gray-900 dark:text-gray-100">
                    Update an existing Booking
                </h3>
            </div>
            <fieldset>
                <ErrorSummary :except="visibleFields" class="mb-4" />
                <div class="grid grid-cols-6 gap-6">
                    <div class="col-span-6 sm:col-span-3">
                        <TextInput id="name" v-model="request.name" required placeholder="Name for this booking" />
                    </div>
                    <div class="col-span-6 sm:col-span-3">
                        <SelectInput id="roomType" v-model="request.roomType" :options="enumOptions('RoomType')" />
                    </div>
                    <div class="col-span-6 sm:col-span-3">
                        <TextInput type="number" id="roomNumber" v-model="request.roomNumber" min="0" required />
                    </div>
                    <div class="col-span-6 sm:col-span-3">
                        <TextInput type="number" id="cost" v-model="request.cost" min="0" required />
                    </div>
                    <div class="col-span-6 sm:col-span-3">
                        <TextInput type="date" id="bookingStartDate" v-model="request.bookingStartDate" required />
                    </div>
                    <div class="col-span-6 sm:col-span-3">
                        <TextInput type="date" id="bookingEndDate" v-model="request.bookingEndDate" />
                    </div>
                    <div class="col-span-6">
                        <TextareaInput id="notes" v-model="request.notes" placeholder="Notes about this booking" class="h-24" />
                    </div>
                </div>
            </fieldset>
        </div>
        <div class="mt-4 bg-gray-50 dark:bg-gray-800 px-4 py-3 text-right sm:px-12">
            <div class="flex justify-between space-x-3">
                <div>
                    <ConfirmDelete v-if="canDelete" @delete="onDelete">Delete</ConfirmDelete>
                </div>
                <div>
                    <PrimaryButton @click="submit">Update Booking</PrimaryButton>
                </div>
            </div>
        </div>
    </div>
</form>

Which can be wired up to handle querying, updating and deleting including limiting functionality to authorized users with:

<script setup lang="ts">
import { computed, ref, watchEffect } from 'vue'
import { useMetadata, useAuth, useClient } from '@servicestack/vue'
import { DeleteBooking, QueryBookings, UpdateBooking } from '../dtos'

const props = defineProps<{
    id: number
}>()
const emit = defineEmits<{
    (e: 'done'): void
}>()

const { enumOptions, toFormValues } = useMetadata()

const visibleFields = "name,roomType,roomNumber,bookingStartDate,bookingEndDate,cost,notes"

const { hasRole, user, isAuthenticated } = useAuth()
const canDelete = computed(() => hasRole('Manager'))
const client = useClient()
const request = ref(new UpdateBooking())

watchEffect(async () => {
    const api = await client.api(new QueryBookings({ id: props.id }))
    if (api.succeeded) {
        request.value = new UpdateBooking(toFormValues(api.response?.results[0]))
    }
})

async function submit(e:Event) {
    const api = await client.api(request.value)
    if (api.succeeded) close()
}
async function onDelete() {
    const api = await client.apiVoid(new DeleteBooking({ id: props.id }))
    if (api.succeeded) close()
}

const close = () => emit('done')
</script>

This also shows how we can utilize enumOptions from our App Metadata to populate select drop downs from C# enums.