Conditions
#Binding Conditions
Elements accept a conditions
option which can used to define conditions under which the element will be present in the form.
#Array Condition
Let's say we want the birthday
field only to present if the user intends to buy alcohol on the website:
<?php
namespace App\Forms;
class ConditionForm extends \Laraform
{
public function schema() {
return [
'alcohol' => [
'type' => 'select',
'label' => 'Do you intend to buy alcohol?',
'items' => [
'no' => 'No',
'yes' => 'Yes'
]
],
'birthday' => [
'type' => 'date',
'label' =>'Date of birth',
'conditions' => [
['alcohol', 'yes']
]
]
];
}
}
When a condition is defined as an array it's first parameter is the path of the an other element, while the second is it's expected value. The expected value can be a number
, string
, boolean
or even an array
.
Multiple Accepted Values
It's also possible to accept multiple values for the condition by defining an array
of values as the second parameter:
'delivery' => [
'type' => 'select',
'label' => 'How do you want receive your package?',
'items' => [
1 => 'Pick at the store',
2 => 'Delivery with UPS',
3 => 'Delivery with FedEx'
]
],
'phone' => [
'type' => 'text',
'label' => 'Phone number',
'conditions' => [
['delivery', [2,3]]
]
]
Then the phone number will only appear if UPS or FedEx is selected.
Custom Operator
You might want to use different operators to examine the condition value, which can be done by simply defining the operator as the second array element, and the comparison value third:
'deposit' => [
'type' => 'text',
'label' => 'Deposit amount'
],
'id_number' => [
'type' => 'text',
'label' => 'ID Card number',
'conditions' => [
['deposit', '>', 500]
]
]
In this example, ID Card number will only be present in the form if the deposit amount is higher than 500
.
Here's the list of available operators:
!=
=
>
>=
<
<=
#Anonym Function
You can write your own functions to achieve more complex validation logic.
To demonstrate that let's create a form that has a frontend component attached to it:
<?php
namespace App\Forms;
class DepositForm extends \Laraform
{
public $component = 'deposit-form';
public function schema() {
return [
'deposit' => [
'type' => 'text',
'label' => 'Deposit amount'
],
'id_number' => [
'type' => 'text',
'label' => 'ID Card number'
]
];
}
}
Let's create the frontend form at resources/js/components/forms/DepositForm.vue
:
<script>
export default {
mixins: [Laraform],
data() {
return {
schema: {
id_number: {
conditions: [
function(){
// If elements don't exist yet return false
if (!this.el$('deposit')) {
return false
}
// The ID Card number will only be present if
// the deposit amount is over 500
return parseInt(this.el$('deposit').value) > 500
}
]
}
}
}
}
}
</script>
If you render the form, you'll notice that id_number
only appears if you enter larger deposit value than 500.
this
refers to the root Laraform component.#Global Function
Conditions defined as a string
will look for the condition in the main form's conditions
object. This way conditions can be predefined and reused over elements.
Let's take the same example as before, but this time using the global function:
<?php
namespace App\Forms;
class DepositForm extends \Laraform
{
public $component = 'deposit-form';
public function schema() {
return [
'deposit' => [
'type' => 'text',
'label' => 'Deposit amount'
],
'id_number' => [
'type' => 'text',
'label' => 'ID Card number',
'conditions' => [
'depositOver500'
]
]
];
}
}
And create the frontend form at resources/js/components/forms/DepositForm.vue
:
<script>
export default {
mixins: [Laraform],
data() {
return {
conditions: {
depositOver500: () => {
// If element is not rendered yet return false
if (!this.el$('deposit')) {
return false
}
// Otherwise check if the value is over 500
return parseInt(this.el$('deposit').value) > 500
}
}
}
}
}
</script>
Now the depositOver500
can be assigned to multiple elements as condition.
this
refers to the root Laraform component.#Conditions For Nested Elements
In this section we'll look into how we can deal with some specific use cases of conditions in nested elements.
#List Item Conditions
Having conditional list elements is a bit tricky when used with objects. The reason for that is simply because you can't define a fixed path to an element, as element path includes indexes
, like team.0.name
, team.1.name
.
Let's see how we can deal with them:
<?php
namespace App\Forms;
class TeamForm extends \Laraform
{
public function schema() {
return [
'team' => [
'type' => 'list',
'label' => 'Team',
'object' => [
'label' => 'Member',
'schema' => [
'name' => [
'type' => 'text',
'label' => 'Name'
],
'founder' => [
'type' => 'checkbox',
'text' => 'Founder'
],
'background' => [
'type' => 'textarea',
'text' => 'Background',
'conditions' => [
['team.*.founder', true]
]
]
]
]
]
];
}
}
By using team.*.founder
we can set a dynamic condition, that will apply to each list element separately.
#Group Conditions
Even though Group element's data is flat, to reference conditions to its elements you need to use full path:
<?php
namespace App\Forms;
class GroupConditionForm extends \Laraform
{
public function schema() {
return [
'profile' => [
'type' => 'group',
'label' => 'Profile',
'schema' => [
'is_company' => [
'type' => 'checkbox',
'text' => 'Company account',
],
'vat_number' => [
'type' => 'text',
'label' => 'VAT number',
'conditions' => [
['profile.is_company', true]
]
]
]
]
];
}
}
#The v-condition
Directive
While elements can have conditions defined in their schema, they can be also binded to plain DOM elements. You can add conditions to any DOM element using v-condition
directive, which value can be used exactly the same way as if was defined in an element's schema:
<!-- Array -->
<!-- condition_field should equal 1 -->
<div v-condition="[['condition_field', 1]]"></div>
<!-- condition_field should not equal 1 -->
<div v-condition="[['condition_field', '!=', 1]]"></div>
<!-- condition_field should equal 1 or 2 -->
<div v-condition="[['condition_field', [1,2]]]"></div>
<!-- Function -->
<!-- some_condition_function is a component property which returns a function -->
<div v-condition="[some_condition_function]"></div>
<!-- Global / String -->
<!-- a name of condition defined at the form template's 'conditions' object -->
<div v-condition="['global_condition']"></div>
It's also possible to have multiple conditions, even mixed ones:
<!-- Array -->
<!-- condition_field should equal 1 AND meet 'global_condition' -->
<div v-condition="[['condition_field', 1], 'global_condition']"></div>
Here's a complex example where one complete block of the form depends on a checkbox value. In this case the <div class="registration-block"></div>
has the condition and all of its elements will only be available
and visible if the Create account checkbox is checked:
<template>
<form
@submit.prevent="submit"
>
<!--
This Delivery details block is always
visible and requires user's name and address
-->
<div class="delivery-block">
<h5>Delivery details</h5>
<div class="row">
<TextElement
name="name"
:schema="schema.name"
v-ref:elements$
/>
<TextElement
name="address"
:schema="schema.address"
v-ref:elements$
/>
<CheckboxElement
name="create_account"
:schema="schema.create_account"
v-ref:elements$
/>
</div>
</div>
<!--
This Registration block is only visible and
it's elements are only available if the
`create_account` checkbox is checked
-->
<div
class="registration-block"
v-condition="[['create_account', true]]"
>
<h5>Create account</h5>
<div class="row">
<TextElement
name="email"
:schema="schema.email"
v-ref:elements$
/>
<TextElement
name="password"
:schema="schema.password"
v-ref:elements$
/>
</div>
</div>
<FormButtons
:buttons="buttons"
/>
</form>
</template>
<script>
export default {
mixins: [Laraform],
data: () => ({
schema: {
name: {
type: 'text',
label: 'Name',
rules: 'required'
},
address: {
type: 'text',
label: 'Address',
rules: 'required'
},
create_account: {
type: 'checkbox',
text: 'Create account'
},
email: {
type: 'text',
label: 'Email',
rules: 'required|email'
},
password: {
type: 'password',
label: 'Password',
rules: 'required'
}
},
buttons: [{
label: 'Submit',
class: 'btn-primary',
disabled() {
return this.form$.disabled
}
}]
})
}
</script>
In this scenario not only the <div class="registration-block"></div>
DOM will be hidden when conditions are not met but all the element components inside will have available
set to false
, meaning they will not be taken into account when validating and submitting data.