We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
  • About time that Any Screen Size posted a new MODX tutorial!

    Order form in MODX with custom hook VAT check

    How to create an order form in MODX with custom hook VAT check using formvalidation.io, FormIt and AjaxFrom.

    The goal
    A simple order form with a country select dropdown, if a EU country is selected make the VAT field mandatory using a custom FormIt post hook.

    Add to this, check the VAT using the great plugin formvalidation.io.

    Finally hide the VAT field is a non-EU country is selected.


    Install the following MODX plugins:

    • FormIt
    • AjaxForm

    You will also need the following Javascript:

    • jQuery
    • formvalidation.io

    Many thanks to: joeke, oetzienl, Joshua, markh and optimuscrime from the MODX Slack who helped me figure this out!


    <div id="order_form_outer">
    	<div id="order_form_thankyou" style="display: none;">
    		<h3>Your order has been send</h3>
    	<div id="order_form">
    			&validationErrorMessage=`Sorry something went wrong.`
    			&successMessage=`Your order has been send.`
    			&emailSubject=`New order from [[+name]]`


    <form id="order_form_inner" action="[[~[[*id]]]]#order_form_outer" method="post" data-fv-framework="foundation">
            Name: [[!+fi.error.name:notempty=`<span class="label alert">[[!+fi.error.name]]</span>`]]
            <input type="text" name="name" id="name" value="[[!+fi.name:htmlent]]" tabindex="1" placeholder="Fill in your full name" />
            E-mail: [[!+fi.error.email:notempty=`<span class="label alert">[[!+fi.error.email]]</span>`]]
            <input type="email" name="email" id="email" value="[[!+fi.email:htmlent]]" tabindex="2" placeholder="Fill in your e-mail" />
            Country: [[!+fi.error.country:notempty=`<span class="label alert">[[!+fi.error.country]]</span>`]]
            <select name="country" id="country" tabindex="3">
        <label id="vat_outer">
            VAT number: [[!+fi.error.vat:notempty=`<span class="label alert">[[!+fi.error.vat]]</span>`]]
            <input type="text" name="vat" id="vat" value="[[!+fi.vat:htmlent]]" tabindex="11" placeholder="Fill in your VAT number" data-fv-vat="true" data-fv-vat-country="country" data-fv-vat-message="The VAT number is not valid" />
        <input type="submit" value="Send order" class="button" tabindex="4" />


    <h3>New order</h3>
    <p>Name: [[+name]] <br>
    E-mail: <a href="mailto:[[+email]]">[[+email]]</a> <br>
    Country: [[+country]] <br>
    VAT: [[+vat]]</p>

    The btwNrCheck snippet
    // Get country dropdown and set as variable
    $country = $hook->getValue('country');
    // If EU country is selected...
    if (in_array($country, ['NL', 'AT', 'BE', 'BR', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IS', 'IE', 'IT', 'LV', 'LT', 'LU', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'RS', 'SK', 'SI', 'ZA', 'ES', 'SE', 'CH', 'GB', 'VE'])) {
    	// Put VAT input field in variable
    	$vat = $hook->getValue('vat');
    	// If the VAT is empty, give error
    	if (empty($vat)) {
    		$hook->addError('vat', 'VAT can not be empty');    
    		return false;        
    // If country not EU or VAT not empty set validation as true
    return true;

    The order_form_js Javascript

    // Order form JS
    // Wait till AjaxForm is finished
    $(document).on('af_complete', function(event, response) {
    	var form = response.form;
    	// If has error
    		// Log an error message
    	// If no error
    	else {
    		// Hide the order form
    		// Show the thank you message
    // Wait for page to load
    $(document).ready(function() {
    	// Revalidate vat number when changing the country
    	.on('change', '[name="country"]', function(e) {
    		$('#order_form_inner').formValidation('revalidateField', 'vat');
    	// Hide VAT field if not EU country
    	$(function() {
        	$("select[name=country]").change(function() {
    				$(this).val() ===  "AT" || 
    				$(this).val() ===  "BE" || 
    				$(this).val() ===  "BR" || 
    				$(this).val() ===  "BG" || 
    				$(this).val() ===  "HR" || 
    				$(this).val() ===  "CY" || 
    				$(this).val() ===  "CZ" || 
    				$(this).val() ===  "DK" || 
    				$(this).val() ===  "EE" || 
    				$(this).val() ===  "FI" || 
    				$(this).val() ===  "FR" || 
    				$(this).val() ===  "DE" || 
    				$(this).val() ===  "GR" || 
    				$(this).val() ===  "HU" || 
    				$(this).val() ===  "IS" || 
    				$(this).val() ===  "IE" || 
    				$(this).val() ===  "IT" || 
    				$(this).val() ===  "LV" || 
    				$(this).val() ===  "LT" || 
    				$(this).val() ===  "LU" || 
    				$(this).val() ===  "NL" || 
    				$(this).val() ===  "NO" || 
    				$(this).val() ===  "PL" || 
    				$(this).val() ===  "PT" || 
    				$(this).val() ===  "RO" || 
    				$(this).val() ===  "RU" || 
    				$(this).val() ===  "RS" || 
    				$(this).val() ===  "SK" || 
    				$(this).val() ===  "SI" || 
    				$(this).val() ===  "ZA" || 
    				$(this).val() ===  "ES" || 
    				$(this).val() ===  "SE" || 
    				$(this).val() ===  "CH" || 
    				$(this).val() ===  "GB" || 
    				$(this).val() ===  "VE"
    			} else {

      MODX Ambassador (NL) | Responsive web design specialist, developer & speaker
      DESIGNfromWITHIN, MPThemes and Any Screen Size
      Follow me on Twitter | Read my blog | My code on GitHub
      • 17301
      • 932 Posts
      Very nice, thank you for posting!
        ■ email: [email protected] | ■ website: https://alienbuild.uk

        The greatest compliment you can give back to us, is to spend a few seconds leaving a rating at our trustpilot: https://uk.trustpilot.com/review/alienbuild.uk about the service we provided. We always drop mention of services offered by businesses we've worked with in the past to those of interest.