AutoFormFields not rendering Input File control

Hi I’m a bit stuck on following the instructions to get AutoFormFields to render a file upload control as seen here
[Auto Form Components]

This is my the vue component

<script lang="ts" setup>
import {onMounted, ref} from 'vue'
import {useHead} from "@unhead/vue"
import {ApiResponse} from "@servicestack/client"
import {useClient, useMetadata} from "@servicestack/vue"
import {QuerySignup, UpdateSignupForm} from "@/dtos";

useHead({title: 'Onboard'})

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

let api = ref<ApiResponse>();
let request = ref<UpdateSignupForm>();

onMounted(async () => {

  let api = await client.api(new QuerySignup({id: 1}));
  if (api.succeeded) {
    request.value = new UpdateSignupForm(toFormValues(api.response!.results[0]));
  }

})

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

<template>
  <div class="mt-8 mb-20 mx-auto max-w-screen-md">
    <h1 class="mb-4 text-3xl font-bold tracking-tight text-gray-900 dark:text-gray-50 sm:text-4xl">On Boarding</h1>

    <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">
          <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>
  </div>
</template>

<style scoped>

</style>

and these are my models

[Tag("signup")]
[Description("Find Signup")]
[Route("/signups", "GET")]
[Route("/signup/{Id}", "GET")]
[AutoApply(Behavior.AuditQuery)]
[HirerActionAuthFilter]
public class QuerySignup : QueryDb<HirerSignupForm>
{
    public int? Id { get; set; }
    public int? HirerId { get; set; }
}


[Tag("signup")]
[Description("Edit Hirer Signup Form")]
[Notes("Sign up form that hirer has to first fill out")]
[Route("/hirer/signup/{Id}", "PATCH")]
[ValidateHasRole(Roles.Hirer)]
[AutoApply(Behavior.AuditModify)]
public class UpdateSignupForm : IPatchDb<HirerSignupForm>, IReturn<HirerSignupForm>
{
    [AutoIncrement] [PrimaryKey] public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    // Please Provide DVLA Check PDF
    [Input(Type = "file")]
    [UploadTo("local")]
    public string DvlaCheckPdfUrl { get; set; }

}

and this is the data model

public class HirerSignupForm : AuditBase
{
    [AutoIncrement] [PrimaryKey] public int Id { get; set; }

    [Index] public int HirerId { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }

   [Input(Type = "file")]
   [UploadTo("local")]
   public string DvlaCheckPdfUrl { get; set; }
}

But the it renders the field as despite having the attributes

Is the component intended to be used this way?

The UI Form attributes should only be on the Request DTO (i.e. not the data model).

What’s the configuration of your FilesUploadFeature?

        var appFs = new FileSystemVirtualFiles(ContentRootDirectory.RealPath.CombineWith("App_Data").AssertDir());

        Plugins.Add(new FilesUploadFeature(
            new UploadLocation("local", appFs, readAccessRole: RoleNames.AllowAnon,
                writeAccessRole: RoleNames.AllowAnon)
        ));

I have removed the attributes from the data model and it hasn’t changed anything.

Can you point me to a repo for the code displayed in the Vue documentation? The examples don’t really show what the actual code setup is and its hard to know what I’ve potentially missed out/ misconfigured.

All code for the docs.servicestack.net is available from
https://github.com/ServiceStack/docs.servicestack.net

So you can search the repo for UploadTo to see source code of pages with [UploadTo] examples.

I’ve added your example source code in a new Vue App and was able to render the form:

I’ve had to create a Migration to create the missing table.

Can you try clearing your App Metadata with ?clear=metadata, e.g:

https://localhost:5173/?clear=metadata

This should clear your /metadata/app.json in your localStorage to update it with the latest version.

Please note you’re DTOs should not have Data Model attributes. E.g. remove [AutoIncrement] [PrimaryKey] from UpdateSignupForm

Also [PrimaryKey] is redundant when using [AutoIncrement], it’s also unnecessary when you Primary Key is named Id.

Your Data Model should also not have UI Form attributes so you should remove [Input(Type = "file")] [UploadTo("local")] from HirerSignupForm

Thanks, clearing out the metadata solved it, how does this work in production? does the user have to run the command to clear the metadata if there are updates?

What is the best way to split up the UI when a dto has a large number of fields

Should each section be its own DTO ? Or are there attributes that can control the form and the order which they appear?

The metadata is cached for 1hr

You can control how long it caches, e.g. ?clear=metadata just sets it to 0 which you can always use to have it redownloaded after each every full page reload.

How you layout your forms is up to you, there are some declarative UI Attributes which you can use to customize the CSS of fields or inputs of Auto Form UIs.

For more customization have a look at Custom Auto Forms and Custom Input Components.

When you need greater customization than what’s available decoratively you’ll need to design your own manual forms using a Custom Form with individual Input Components.

Perfect, thanks for your help :slight_smile: