CakePHP 3 Tutorial 14: Optional Requirements

Submitted by naidim on Tue, 10/04/2016 - 12:21

There may come a time when you have a form that has optional requirements. By that I mean that depending on a previous selection, future selections may become required, or not.

A simple method I've found to do this is with jQuery on the front end and no validation requirements on the back end. An example follows:

A victim of either type "business" or "individual" needs to be entered. One or the other must be entered, but we don't want to require the business information for an individual or vice versa. So we can enable/disable the requirements and display/hide the sections based on the selection.

First, in the layout (src/Template/Layout/default.ctp) we load jQuery by adding the following line in the head section:

echo $this->Html->script('http://code.jquery.com/jquery.min.js');

Then for our form (/src/Template/Victims/add.ctp) we add a choice field and use jQuery to show/hide and enable/disable required.

<?php echo $this->Form->input('victim', ['type' => 'radio', 'label' => 'Victim is:', 'options' => ['Business', 'Individual'], 'required' => true]); ?>
<div class="business" style="display:none">
    <?php
        echo $this->Form->input('business_name', ['required' => true]);
        echo $this->Form->input('business_telephone');
        echo $this->Form->input('business_address', ['required' => true]);
        echo $this->Form->input('business_city', ['required' => true]);
        echo $this->Form->input('business_state', ['required' => true, 'options' => $states]);
        echo $this->Form->input('business_zip', ['required' => true]);
    ?>
</div>
<div class="individual" style="display:none">
    <?php
        echo $this->Form->input('name', ['required' => true]);
        echo $this->Form->input('telephone');
        echo $this->Form->input('address', ['required' => true]);
        echo $this->Form->input('city', ['required' => true]);
        echo $this->Form->input('state', ['required' => true, 'options' => $states]);
        echo $this->Form->input('zip', ['required' => true]);
    ?>
</div>
<script>
    if (jQuery('#victim-0').is(':checked')) {
        showAndRequire('.business', true);
        showAndRequire('.individual', false);
    } else if (jQuery('#victim-1').is(':checked')) {
        showAndRequire('.individual', true);
        showAndRequire('.business', false);
    }
    jQuery('#victim-0').click(function() {
        showAndRequire('.business', true);
        showAndRequire('.individual', false);
    });
    jQuery('#victim-1').click(function() {
        showAndRequire('.individual', true);
        showAndRequire('.business', false);
    });
    function showAndRequire(section, onOff) {
        jQuery(section).toggle(onOff);
        if (onOff) {
            jQuery(section + ' .required input').attr('required', onOff);
            jQuery(section + ' .required select').attr('required', onOff);
        } else {
            jQuery(section + ' .required input').removeAttr('required');
            jQuery(section + ' .required select').removeAttr('required');
        }
    }
</script>

Now when a user selects business or individual, only that section will be displayed and only that section will have the required attributes set.

Next: Neighbors

Add new comment