Skip to content

Fields

When you use FancyCRUD you can create forms just by specifying the fields and their attributes, and it will create the HTML structure, handle the form data, send the request, handle the responses, display notifications, display any field error, and more.

Fields are one of the main utilities to create forms using FancyCRUD. As long you're using any of the existing wrapper, you should be able to use the props and slots from the source UI Framework.

To get the correctly fields structure we need to pass the raw fields to useForm composable. This function will return a normalized fields to interact with.

Let's see the next example:

vue
<template>
  <div class="card">
    <!-- Component to render the form -->
    <f-form v-bind="form" />
  </div>
</template>

<script lang="ts" setup>
import { FieldType, useForm } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: {
      type: FieldType.text,
      label: 'First name',
      placeholder: 'John',
    },
    lastName: {
      type: FieldType.text,
      label: 'Last name',
      placeholder: 'Doe',
    },
  },
  settings: {
    url: 'endpoint/'
  },
})
</script>

We're defining a form with the field firstName and lastName. Even when we're just defining three attributes(type, label and placeholder) inside these fields. The composable will normalized them and it going to add all the necessary attributes into each field.

So, we will have a structure as the next:

js
{
  fields: {
    firstName: {
      type: "text",
      label: "First name",
      id: `field-firstName-control`,  
      modelKey: "firstName",
      name: "firstName",
      errors: [],
      wasFocused: false,
      modelValue: null,
      class: '',
      wrapper: {
          class: '',
      },
      ref: null,
    }
  }
}

Also, you can override those default values by passing the key with another custom value. Then you will be able to access to those properties as the follow example:

vue
<script lang="ts" setup>  
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: {
      type: FieldType.text,
      label: 'First name',
      modelValue: 'John Doe'
    }
  }
})

console.log(form.fields.firstName.modelValue) // John Doe
console.log(form.fields.firstName.label) // First name
console.log(form.fields.firstName.id) // field-firstName-control
console.log(form.fields.firstName.errors) // []
</script>

Types

Forms are nothing without fields. So, we can use multiple field types to create those forms. Right now we have the next field types:

  • Text
  • Password
  • Color
  • Datepicker
  • Radio
  • Select
  • Textarea

We're working to bring more and more field types 😃. You can specify the field type by using the FieldType enumerator or using a string when you want to specify custom field types.

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: {
      type: FieldType.text, 
      label: 'First name',
    }
    favoriteColor: {
      type: FieldType.color, 
      label: 'Favorite color',
    },
    password: {
      type: FieldType.password, 
      label: 'Password',
    },
    birthDate: {
      type: FieldType.datepicker, 
      label: 'Birth date',
    },
    role: {
      type: FieldType.radio, 
      label: 'Role',
      options: ["Manager", "Developer", "Sales"]
    },
    programmingLanguage: {
      type: FieldType.select, 
      label: 'Skills',
      options: ["Python", "Vue", "Typescript", "FancyCRUD", "NodeJS"]
    },
    comments: {
      type: FieldType.textarea, 
      label: 'Comments',
    },
  }
})
</script>

Create new record

R
G
B
A

Native attributes

Fields are available to use attributes from native HTML inputs, or specify attributes from the ui wrapper.

For example, let's say we are using Vuetify as our wrapper and we're going to use placeholder attribute into our firstName field. When the FancyCRUD map our field, it will pass all the attributes to the input, and display the text in the placeholder attribute.

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: {
      type: FieldType.text,
      label: 'First name',
      placeholder: 'John Doe', 
    }
  }
})
</script>

Reserved Attributes

ModelValue

NameTypeDefault
modelValueanynull

The modelValue attribute is to handle the input value. So you can always find the most recent value here, or set a initial value.

vue
<template>
  <f-form v-bind="form"></f-form>
  {{ form.fields.firstName.modelValue }}
</template>
  
<script setup lang='ts'>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: {
      type: FieldType.text,
      label: 'First name',
      modelValue: 'Juan Camaney'
    },
  }
})
</script>
modelValue: Juan Camaney

Create new record

ModelKey

NameTypeDefault
modelKeystringSame as the [fieldKey] name
valor

The modelKey attribute is responsible to handle the key name of the field to be send in the request payload.

vue
<template>
  <f-form v-bind="form"></f-form>
</template>
  
<script setup lang='ts'>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: { // <- [fieldKey] name
      type: FieldType.text,
      label: 'First name',

      // Also, you can omit this attribute,
      // and it going to take "firstName" [fieldKey] name
      // as default value
      modelKey: 'firstName'
    },
  }
})
</script>

Create new record


Request payload

{ "firstName": null }

Errors

NameTypeDefault
errorsstring[][]

The errors attribute is to handle the field errors. These errors can be set from rules validation or backend validations. You can set errors programmatically as well.

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    text: {
      type: FieldType.text,
      label: 'Favorite color',
      errors: ['Displaying an error'] 
    }
  }
})
</script>

Create new record


Rules

NameTypeDefault
rules(value: any) => string | true | unknownundefined

This section is to understand how to specify a rule for a field. You can follow the Rules section to have a full understanding. The next example is using Zod, but you can use your own rules or third-party libraries like Valibot or Joi:

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    email: {
      type: FieldType.text,
      rules: value => ({ value, rule: z.string().email() }), 
    }
  }
})
</script>

Options

NameTypeDefault
optionsany[]undefined

You can use the options attribute to render a list of items. Then the user will be able to pick a value, and it will be assigned to modelValue

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    favoriteColor: {
      type: FieldType.select,
      label: 'Favorite color',
      options: ['red', 'blue', 'purple'] 
    }
  }
})
</script>

Also, you can work with objects and specify the label to be displayed, and the value to be picked. To those cases you need to use optionLabel and optionValue. Let's see an example:

WARNING

If you don't specify the optionLabel when you're working with objects, it will display something like [Object object].

INFO

If you don't specify the optionValue when you're working with objects, it will gives you the object as value.

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const employees = [
  { id: 1, name: 'Marco', age: 34 },
  { id: 2, name: 'Linda', age: 28 },
  { id: 3, name: 'Alex', age: 42 },
  { id: 4, name: 'Emily', age: 31 },
  { id: 5, name: 'Jordan', age: 35 }
];

const form = useForm({
  fields: {
    favoriteColor: {
      type: FieldType.select,
      label: 'Favorite color',
      options: employees,     
      optionLabel: 'name',    
      optionValue: 'id'
    }
  }
})
</script>

Create new record


URL

NameTypeDefault
urlstringundefined

Sometimes when you're working with the select field type. You will need to populate the field with some data from the backend. So, you can use the url attribute. If the url is specified the form will trigger a HTTP request to GET the values from an API, and automatically set those values into the field options. Then you can set optionLabel and optionValue, to display and picked the data from each object. Let's see an example:

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    favoriteColor: {
      type: FieldType.select,
      label: 'Favorite color',
      url: 'employees/',    
      optionLabel: 'name',  
      optionValue: 'id'
    }
  }
})
</script>

Create new record


DebounceTime

NameTypeDefault
debounceTimenumber0

The debounceTime property allows specifying a wait time before update the modelValue.

CreateOnly

NameTypeDefault
createOnlybooleanfalse

The createOnly is for those cases where you want to display a field only when the form is FORM_MODE.create.

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    favoriteColor: {
      type: FieldType.select,
      label: 'Favorite color',
      createOnly: true
    }
  }
})
</script>

UpdateOnly

NameTypeDefault
updateOnlybooleanfalse

The updateOnly is for those cases where you want to display a field only when the form is FORM_MODE.update.

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    favoriteColor: {
      type: FieldType.select,
      label: 'Favorite color',
      updateOnly: true
    }
  }
})
</script>

Hidden

NameTypeDefault
hiddenbooleanfalse

The hidden is to hide a field, not matter the FORM_MODE.

Exclude

NameTypeDefault
excludebooleanfalse

The exclude attribute is to avoid the field to be add it in the request payload.

Multiple

NameTypeDefault
excludebooleanfalse

The multiple attribute allows you to start the modelValue as an array. Usually this attribute works perfectly along with the FieldType.select

Wrapper

The wrapper attribute allows you to pass attributes to the field wrapper, but it depends on the UI Wrapper that you're using.

Methods

RecordValue

The recordValue?: (value: any) => unknown function is use it to get the field value coming from the source object. This is useful when you want to handle a nested object value or you want to compute a value before assign it to the modelValue. For example, let's say that you have the next object:

ts
employee: {
  id: 1,
  name: 'Samira Gonzales'
}

And you want to send an employee_id value in the request payload. So, you need to set the modelValue with the employee.id. To accomplish that, you can do something like the code below:

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

interface Employee {
  id: int
  name: str
}

const form = useForm({
  fields: {
    employee_id: {
      type: FieldType.text,
      label: 'Employee ID',
      recordValue: (obj: { employee: Employee }) => obj.employee.id
    }
  }
})
</script>

InterceptOptions

The interceptOptions?: (options: any[]) => unknown[] is use it to intercept the values that will be assigned into the de options attribute.

ParseModelValue

The parseModelValue is a function to parse the modelValue before send it into the request payload. For example, let's say we have a modelValue with number as string, and you want to send that value as number. So, you can do something like:

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

interface Employee {
  id: int
  name: str
}

const form = useForm({
  fields: {
    employee_id: {
      type: FieldType.text,
      label: 'First name',
      modelValue: '1',
      parseModelValue: Number
    }
  }
})
</script>

The example above is a shortcut for:

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

interface Employee {
  id: int
  name: str
}

const form = useForm({
  fields: {
    employee_id: {
      type: FieldType.text,
      label: 'First name',
      modelValue: '1',
      parseModelValue: value => Number(value)
    }
  }
})
</script>

Events

Fields also allows you to handle events from the native HTML input or custom events from the ui wrapper like click, blur, focus, etc. See the next example:

vue
<script lang="ts" setup>
import { useForm, FieldType } from '@fancy-crud/vue'

const form = useForm({
  fields: {
    firstName: {
      type: FieldType.text,
      label: 'First name',
      onFocus: () => {
        // Do something
      },

      onBlur: () => {
        // Do something
      }
    }
  }
})
</script>