Feedback Laraform is now in maintenance mode. Read more on our GitHub.

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.

When using function condition 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.

When using global condition functions 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.