Be sure to first read the BlitzForm basics.
Advanced
Dynamic Props
Dynamic Props — What/When
As you know, BlitzForm needs a schema
with information on each field you want to show. Each field in your schema can have props like label
component
and any prop the component itself might need.
However, your fields can also have dynamic props, for example based on the data of the form! Such dynamic props are called Dynamic Props.
To use this you need to set the prop to a function. This function will be executed any time the data of any field changes.
Your form could have a disabled field by setting disabled: true
to that field. But you can make a field be disabled based on wether or not a checkbox in your form is checked. In this case set the disabled
prop to (val, context) => !!context.formData.myCheckBox
. Now that field is disabled when myCheckBox
is true.
The function you use for Dynamic Props receive 2 params (val, context)
.
val
— this is the current value of the fieldcontext
— this is the Vue component reference of the BlitzField, you can use this to access any other properties/values
The most important props you can access on context
:
formData
— this is the nested data of all the fields inside a BlitzFormformDataFlat
— this is the flattened data of all the fields inside a BlitzFormmode
— the current mode of the BlitzForm. Can be'edit'
|'readonly'
|'raw'
|'disabled'
Try to refrain from accessing props other than the ones listed above, because these are mainly used internal and could have behaviour changes that could break your app.
A Prop Based on the modelValue of the Field
Here we show how to make the props you pass to a field conditional — based on the modelValue
of that field.
dynamicProps: ['subLabel'],
subLabel: val => val === 'purple' ? 'nice!' : 'choose a color'
A Prop Based on the modelValue of "Another" Field
Here we show how to make the props you pass to a field conditional — based on the modelValue
of another field.
dynamicProps: ['disabled'],
disabled: (val, { formData }) => !formData.under18
Show or Hide a Field Based on Another Field
Here we show how to conditionally hide or show a field. showCondition
is a special prop you can for this, defined inside your BlitzForm schema.
dynamicProps: ['showCondition'],
showCondition: (val, { formData }) => formData.car
Try checking the checkbox and see what happens.
Calculated "Options" of a Select-Field
Here we show how to automatically render select options based on data from a database.
We then also conditionally show different select options based on the modelValue
of the other selected fields.
Show Content Based on Another Field
Here we show how to show the modelValue
of one field as the slot
content of another.
{
component: 'div',
dynamicProps: ['slot'],
slot: (val, { formData }) => formData.myInput
}
Computed Field Values
Computed Field Values — What/When
Computed Field Values are when you need to add a field in your form that have a calculated value based on the form data or some other fields.
Do not confuse this concept with Dynamic Props.
- Dynamic Props: a calculated prop of a field
- Computed Field Values: a field with a calculated value
An example of a Computed Field Value could be a full name of a person which exists of ${formData.firstName} ${formData.lastName}
There are three ways we could create such a field:
The parseValue
Prop
{
id: 'fullName',
component: 'input',
parseValue: (val, { formData }) => `${formData.firstName || ''} ${formData.lastName || ''}`
}
So even though the field fullName
has no value
at all, it will always stay in sync with the current formData
.
When implementing a Computed Field Value this way however, fullName
will never have that computed value emitted. This means that it won't be included in the BlitzForm events: @update:modelValue
, @updateField
and @save
. So it's difficult to capture and save this calculated value alongside your other data. See the next section for another method.
Update via updateField
It can be handy to also save the calculated value in your database so you can filter/search/sort on this field.
In this case we can use the method called updateField()
which is accessible on the context and first explained on the events documentation page.
{
id: 'firstName',
events: {
'update:modelValue': (val, {formData, updateField}) => {
const { lastName = '' } = formData
const value = `${val} ${lastName}`.trim()
updateField({ id: 'fullName', value })
}
},
},
{
id: 'lastName',
events: {
'update:modelValue': (val, {formData, updateField}) => {
const { firstName = '' } = formData
const value = `${firstName} ${val}`.trim()
updateField({ id: 'fullName', value })
}
},
}
This method has pro's and con's though:
- PRO: you don't need to include the Computed Field Value (
fullName
) on the form at all - CON: this is quite verbose...
- CON: it cannot be used if you need a Computed Field Value not based on other fields (eg. a timestamp returning
new Date()
) - CON: when your database already has data, you cannot use this without manually updating what's already in your database
- CON: if you want to save the Computed Field Value to your database, you have to include this Computed Field Value in all forms the user can edit this data
Combine parseValue
& updateField
The third way to create a Computed Field Value is this:
{
id: 'fullName',
component: 'input',
parseValue: (val, {formData, updateField}) => {
const newValue = `${formData.firstName || ''} ${formData.lastName || ''}`.trim()
if (val !== newValue) updateField({ id: 'fullName', value: newValue })
return newValue
},
// If you want to hide the Computed Field Value you can set:
// showCondition: false
}
Basically you write your logic inside the parseValue
prop of your Computed Field Value, and also trigger a updateField
action from within here.
However, as the more experienced developers will notice...
This is the same as introducing a side-effect to a computed property! By design this is discouraged, so isn't this bad?
I say "nay". The reason it is discouraged is because side-effects to computed properties that modify data are impossible to track. In a few months if you don't know why a certain value is being modified, you'll have a hard time finding eventually it was the side-effect from a computed property.
If we understand this reason, then in our case, it is perfectly valid to do so, because we are only modifying the data of the field we are describing right there. We are simply doing something equivalent to triggering emit('update:modelValue', val)
on a component manually, nothing wrong with that.
However, keep in mind that also this method has its own pro's and con's:
- PRO: it can be used as stand-alone, without relying on other fields & without the need to render other fields
- PRO: because it just uses
parseValue
it's less verbose (opposed to listening toupdate:modelValue
events of other fields) - PRO: the logic for this field is contained in its own options object
- PRO: even if your database already has data, a Computed Field Value like this can be added at a later date
- CON: if you want to save the Computed Field Value to your database, you have to include this Computed Field Value in all forms the user can edit this data
Hint: add showCondition: false
if you want to hide the field but still have it save its content in the formData.
Using Locally Registered Components
Using a custom component in BlitzForm
requires it to be registered globally. The idea is that a BlitzForm schema is saved in a Database, so we want to avoid using component instances etc.
However, if you still prefer to use locally registered components you can do so by simply passing the instance directly and wrapping it in markRaw
.
import { markRaw } from 'vue'
import MyInput from './MyInput.vue'
const schema = [
{
id: 'name',
label: 'Name',
component: markRaw(MyInput),
},
]
The example below uses this method: