Conditions

#Binding Conditions

Elements accept a conditions schema property which can used to define conditions under which the element will be present in the form. Let's say we want the birthday field only to present if the user intends to buy alcohol on the website:

          
<script>
  export default {
    mixins: [Laraform],
    data: () => ({
      schema: {
        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']
          ]
        }
      }
    })
  }
</script>
        

Each condition can be either an array, a function or a string.

#Condition Types

#Array

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 as you've seen in the previous example. 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:

schema: {
  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: 'phone',
    label: 'Phone number',
    conditions: [
      ['delivery', [2,3]]
    ]
  }
}

The values of the array can be either numbers or strings.

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:

schema: {
  deposit: {
    type: 'input',
    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. The function should return boolean:

data() {
  return {
    conditions: {
      depositOver500: 
    },
    schema: {
      deposit: {
        type: 'input',
        label: 'Deposit amount'
      },
      withdraw: {
        type: 'input',
        label: 'Withdraw amount'
      },
      id_number: {
        type: 'text',
        label: 'ID Card number',
        conditions: [
          function(){
            // The ID Card number will only be present if either
            // deposit or withdraw amount is over 500
            return parseInt(this.element('deposit').value) > 500 ||
                   parseInt(this.element('withdraw').value) > 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.

The the global conditions form property is an object where the key is the name of the condition and the value is the function which returns a boolean.

data() {
  return {
    conditions: {
      depositOver500: () => {
        return parseInt(this.element('deposit').value) > 500
      }
    },
    schema: {
      deposit: {
        type: 'input',
        label: 'Deposit amount'
      },
      id_number: {
        type: 'text',
        label: 'ID Card number',
        conditions: [
          'depositOver500'
        ]
      },
      address_card: {
        type: 'text',
        label: 'Address Card number',
        conditions: [
          'depositOver500'
        ]
      },
    }
  }
}
When using global condition functions this refers to the root Laraform component.

#List Items

Having conditional list elements is a bit tricky when used with objects. The reason for that is simply because you can't define a concrete.path to an element, as element path includes indexes, like team.0.name, team.1.name:

schema: {
  team: {
    type: 'list',
    label: 'Team',
    object: {

      // the element's path is: team.*.name
      name: {
        type: 'text',
        label: 'Name'
      },

      // the element's path is: team.*.founder
      founder: {
        type: 'checkbox',
        text: 'Founder'
      }
    }
  }
}

It might happen that we want to have additional informations about founders but not other team members, like their Background.

schema: {
  team: {
    type: 'list',
    label: 'Team',
    object: {
      schema: {
        name: {
          type: 'text',
          label: 'Name'
        },
        founder: {
          type: 'checkbox',
          text: 'Founder'
        },
        background: {
          type: 'textarea',
          text: 'Background',
          conditions: [
            // ???
          ]
        }
      }
    }
  }
}

In fact this can be easily managed by using * wildcard for indexes when defining the condition element as Laraform will replace it with the element's index when validating conditions:

background: {
  type: 'textarea',
  text: 'Background',
  conditions: [
    ['team.*.founder', true]
    // this will be transformed to
    // • team.0.founder
    // • team.1.founder
    // • ...
  ]
}

Try it yourself:

          
<script>
  export default {
    mixins: [Laraform],
    data: () => ({
      schema: {
        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]
                ]
              }
            }
          }
        }
      }
    })
  }
</script>
        

#'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 it's elements will only be available and visible if the Create account checkbox is checked:

// `filtered` form data:

        
          
<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.

#'available' Property

Elements have an available property which show if the element should be included in the form or not. If true, it means that the element either has no conditions or has all of them fulfilled. If any of the conditions aren't met the available property will be false. To achieve 'or' condition logic, you should use anonym function.

// VAT number's `available` property:

        
          
<script>
  export default {
    mixins: [Laraform],
    data: () => ({
      schema: {
        name: {
          type: 'text',
          placeholder: 'Name',
          rules: 'required',
        },
        vat_number: {
          type: 'text',
          placeholder: 'VAT number',
          conditions: [
            ['is_company', true]
          ]
        },
        is_company: {
          type: 'checkbox',
          label: 'Register as company'
        }
      }
    })
  }
</script>
        

When the element is not available, it's display property is also set to false. By default if the display is false the element will be hidden using v-if so it's DOM will not be visible.

If an element is unavailable it will neither be taken into account when validating or submitting the form. You can add validation rules to elements with conditions and they will be ignored if any of their conditions aren't met as you will see in the following.

#'data' And 'filtered' Property

Each element and the main form component has two properties representing it's data model. The first is data and the other is filtered. The difference between them is that data contains all data the elements have regardless their available status. Contrary to that filtered only includes data from elements which are available.

Check out how VAT number is only required and present in filtered data if the Register as company is checked, while always contained in data.

// `filtered` and `data`:

        
          
<script>
  export default {
    mixins: [Laraform],
    data: () => ({
      formErrors: false,
      schema: {
        name: {
          type: 'text',
          placeholder: 'Name',
          rules: 'required',
        },
        vat_number: {
          type: 'text',
          placeholder: 'VAT number',
          rules: 'required',
          conditions: [
            ['is_company', true]
          ]
        },
        is_company: {
          type: 'checkbox',
          text: 'Register as company',
        }
      },
      buttons: [{
        label: 'Submit',
        class: 'btn-primary',
        disabled() {
          return this.form$.disabled
        }
      }]
    })
  }
</script>
        

When submitting a form, the filtered data will be sent for processing.