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:
<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:
{
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:
<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.
<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>
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.
<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
Name | Type | Default |
---|---|---|
modelValue | any | null |
The modelValue
attribute is to handle the input value. So you can always find the most recent value here, or set a initial value.
<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
ModelKey
Name | Type | Default |
---|---|---|
modelKey | string | Same 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.
<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>
Request payload
{
"firstName": null
}
Errors
Name | Type | Default |
---|---|---|
errors | string[] | [] |
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.
<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>
Rules
Name | Type | Default |
---|---|---|
rules | (value: any) => string | true | unknown | undefined |
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:
<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
Name | Type | Default |
---|---|---|
options | any[] | 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
<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.
<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>
URL
Name | Type | Default |
---|---|---|
url | string | undefined |
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:
<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>
DebounceTime
Name | Type | Default |
---|---|---|
debounceTime | number | 0 |
The debounceTime
property allows specifying a wait time before update the modelValue
.
CreateOnly
Name | Type | Default |
---|---|---|
createOnly | boolean | false |
The createOnly
is for those cases where you want to display a field only when the form is FORM_MODE.create
.
<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
Name | Type | Default |
---|---|---|
updateOnly | boolean | false |
The updateOnly
is for those cases where you want to display a field only when the form is FORM_MODE.update
.
<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
Name | Type | Default |
---|---|---|
hidden | boolean | false |
The hidden
is to hide a field, not matter the FORM_MODE
.
Exclude
Name | Type | Default |
---|---|---|
exclude | boolean | false |
The exclude
attribute is to avoid the field to be add it in the request payload.
Multiple
Name | Type | Default |
---|---|---|
exclude | boolean | false |
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:
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:
<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:
<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:
<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:
<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>