Auto Form Components

AutoForm

The AutoForm component is a generic form component that can be used to create and wire a traditional Form for any Request DTO definition where successful responses can be handled the @success event, e.g:

<AutoForm type="QueryBookings" @success="onSuccess" />
<div v-if="results">
    <h3 class="py-4 text-2xl">Results</h3>
    <HtmlFormat :value="results" />
</div>

<script setup>
const results = ref([])
const onSuccess = response => results.value = response.results
</script>

Results

These Auto Form components are customizable with the declarative C# UI Attributes where you can override the form's heading with [Description] and include a subHeading with [Notes] which supports rich HTML markup.

AutoForm Properties

Alternatively they can be specified in the components properties:

defineProps<{
    type: string|InstanceType<any>|Function
    modelValue?: ApiRequest|any
    heading?: string
    subHeading?: string
    showLoading?: boolean
    jsconfig?: string         //= eccn,edv
    configureField?: (field:InputProp) => void

    /* Default Styles */
    formClass?: string        //= shadow sm:rounded-md
    innerFormClass?: string
    bodyClass?: string
    headerClass?: string      //= p-6
    buttonsClass?: string     //= mt-4 px-4 py-3 bg-gray-50 dark:bg-gray-900 sm:px-6 flex justify-between
    headingClass?: string     //= text-lg font-medium leading-6 text-gray-900 dark:text-gray-100
    subHeadingClass?: string
    submitLabel?: string      //= Submit
}>()

Both @success and @error events are fired after each API call, although built-in validation binding means it's typically unnecessary to manually handle error responses.

defineEmits<{
    (e:'success', response:any): void
    (e:'error', error:ResponseStatus): void
    (e:'update:modelValue', model:any): void
}>()

Model Binding

Forms can be bound to a Request DTO model where it can be used to pre-populate the Forms default values and Request DTO whereby specifying a type is no longer necessary:

<AutoForm v-model="request" />

<script setup>
const request = ref(new QueryBookings({ skip:1, take:2, orderBy:'Name' }))
</script>

Create Form

AutoCreateForm can be used to create an automated form based on a AutoQuery CRUD Create Request DTO definition which can be rendered in a traditional inline Form with card formStyle option, e.g:

<AutoCreateForm type="CreateBooking" formStyle="card" />

By default Auto Forms are rendered in a SlideOver dialog:

<AutoCreateForm type="CreateBooking" />

These Auto Forms are powered by the rich App Metadata surrounding your APIs, which contain all the necessary metadata to invoke the API and bind any contextual validation errors adjacent to the invalid field inputs.

Edit Form

AutoEditForm can be used to render an automated form based on Update and Delete AutoQuery CRUD APIs which also makes use of heading and sub-heading customization options:

<AutoEditForm v-model="booking" type="UpdateBooking" deleteType="DeleteBooking" 
    heading="Change an existing Room Booking" sub-heading="Manage reservations for MyApp hotels." />

The same form rendered in a traditional inline form with a card formStyle with some more advanced customization examples using rich markup in custom <template #heading> and <template #sub-heading> slots:

<AutoEditForm v-model="booking" formStyle="card" type="UpdateBooking" deleteType="DeleteBooking">
  <template #heading>
    <h3 class="text-xl font-semibold text-green-600">Change an existing Room Booking</h3>
  </template>
  <template #sub-heading>
    <p>
      Here are some 
      <TextLink href="https://youtu.be/rSFiikDjGos">good tips on making room reservations 
        <Icon class='inline-block' icon="lucide:external-link" />
      </TextLink>
    </p>
  </template>
</AutoEditForm>

The forms behavior and appearance is further customizable with the API annotation, declarative validation and the custom Field and Input attributes, e.g:

[Description("Update an existing Booking")]
[Notes("Find out how to create a <a href='https://youtu.be/rSFiikDjGos'>C# Bookings App from Scratch</a>")]
[Route("/booking/{Id}", "PATCH")]
[ValidateHasRole("Employee")]
[AutoApply(Behavior.AuditModify)]
public class UpdateBooking : IPatchDb<Booking>, IReturn<IdResponse>
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public RoomType? RoomType { get; set; }
    [ValidateGreaterThan(0)]
    public int? RoomNumber { get; set; }
    [ValidateGreaterThan(0)]
    public decimal? Cost { get; set; }
    public DateTime? BookingStartDate { get; set; }
    public DateTime? BookingEndDate { get; set; }
    [Input(Type = "textarea")]
    public string? Notes { get; set; }
    public string? CouponId { get; set; }
    public bool? Cancelled { get; set; }
}

Where they can be used to customize Auto Form's appearance from annotations on C# Server DTOs:

<AutoEditForm v-model="booking" formStyle="card" type="UpdateBooking" deleteType="DeleteBooking" />

Form Fields

For more advanced customization of a Forms appearance and behavior, AutoFormFields can be used to just render the Form's fields (with validation binding) inside a custom Form which can submit the data-bound populated Request DTO to invoke the API, e.g:

<template>
<form v-if="request" @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">
                    Change an existing Room Booking
                </h3>
                <p class="notes mt-1 text-sm text-gray-500 dark:text-gray-400">
                    Find out how to quickly create a 
                    <a class='svg-external' target='_blank' href='https://youtu.be/rSFiikDjGos'>
                        C# Bookings App from Scratch
                    </a>
                </p>
            </div>

            <AutoFormFields v-model="request" :api="api" />

        </div>
        <div class="bg-gray-50 dark:bg-gray-800 px-4 py-3 text-right sm:px-12">
            <PrimaryButton>Save</PrimaryButton>
        </div>
    </div>
</form>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { ApiResponse } from '@servicestack/client'
import { useClient, useMetadata } from '@servicestack/vue'
import { QueryBookings, UpdateBooking } from '../dtos'

const { toFormValues } = useMetadata()
const client = useClient()

let api = ref<ApiResponse>()
let request = ref<UpdateBooking>()

async function submit(e:Event) {
    api.value = await client.api(request.value!)
}

onMounted(async () => {
    let api = await client.api(new QueryBookings({ id: 1 }))
    if (api.succeeded) {
        request.value = new UpdateBooking(toFormValues(api.response!.results[0]))
    }
})
</script>

toFormValues is used when updating the data bound request DTO to convert API response values into the required format that HTML Inputs expect.