1

I get a node form with node_form and then I render it with some modifications.

One of the modifications is that I duplicate the fields so I have the same fields twice. One field is disabled and the other same field is enabled, I also have a checkbox to show or hide the disabled/enabled field with #states. So I have only one field visible at time, for example, I have a disabled field visible, if I check the checkbox then disabled field is hidden and enabled field is shown.

The problem comes with the #requried = TRUE fields. When I submit the form it validates the two fields (enabled and disabled) but I only want to validate the visibile field. So, if it's visible the disabled field, I don't want to validate the enabled field.

What is a good way to achieve this?

7
  • Could you please tell me why you not using field-conditional-state module?
    – madhurjya
    Commented Dec 12, 2013 at 10:12
  • 3
    @madhurjya Some people (me incuded) prefer to code their own solution
    – Clive
    Commented Dec 12, 2013 at 10:14
  • yes clive i know but, in this question i look that it can be perform by the simplest way of field-conditional-state module, thats why i am putting this comment...:)
    – madhurjya
    Commented Dec 12, 2013 at 10:16
  • can you remove all #required=>TRUE elements and specify you own validation?
    – xurshid29
    Commented Dec 12, 2013 at 10:17
  • I had similar problem and the answer is - recreate your hiding logic in your validator.
    – Mołot
    Commented Dec 12, 2013 at 10:42

1 Answer 1

3

I've tacked a variation on this before and this was the only solution I found that didn't have problems of some sort.

The key is not to skip all validation as you may add security holes so you have to specifically skip required validation. - Specifically what I'm getting at here is don't use #limit_validation_errors.

You cannot stop drupal core from validating that required fields are not empty, so you have to make the fields not required when they get validated.

Note that this example will make all fields not required, so you'll have to add some logic to only do that for the fields you are interested in. I couldn't add this because I don't have enough info about your setup.

In your form add this:

  // Add an after build callback so we can modify the form before validation.
  $form['#after_build'][] = 'MYMODULE_form_after_build';

Then add that after build function and a helper function:

/**
 * Form after build callback.
 *
 * We are using this to modify the form after it has been submitted,
 * but before it has been validated.
 * This means we can remove required flags for certain fields.
 *
 * @param array $element
 *   An associative array containing the structure of a form element.
 *   In this case the form.
 * @param array $form_state
 *   The form state array.
 *
 * @return array
 *   An associative array containing the structure of a form element.
 */
function MYMODULE_form_after_build($element, &$form_state) {
  // Check that the form has been submitted.
  if ($form_state['process_input']) {
    // Deal with required fields.
    _MYMODULE_remove_required($element);
  }
  return $element;
}

/**
 * Make elements of a form not required.
 *
 * This example function will make all required fields not
 * required.
 * In your case you want to only do certain fields so you will have
 * to add logic in here to only affect some fields.
 * You could do this based on field name or some other flag you have
 * set, or whatever.
 *
 * @param array $elements
 *   An associative array containing the structure of a form.
 */
function _MYMODULE_remove_required(&$elements) {
  // Recurse through all children.
  foreach (element_children($elements) as $key) {
    if (isset($elements[$key]) && $elements[$key]) {
      _MYMODULE_remove_required($elements[$key]);
    }
  }
  if (!empty($elements['#required'])) {
    $elements['#required'] = FALSE;
  }
}
8
  • Ok, so with this approach I set #required = FALSE for enabled fields (hidden for default) and then I have to implement a hook_validate to validate if a enabled field is shown, right?
    – ilazgo
    Commented Dec 12, 2013 at 11:28
  • Instead of just setting required = FALSE for all fields as per my example, I would try to set it to FALSE only for fields that are hidden, then you don't need any validation function. At the time of the after build you should have access to the values of the form, so you can check the status of the fields you were using for your states to determine what's hidden and needs to have required = FALSE. You can always pass $form_state into _MYMODULE_remove_required if you need to.
    – rooby
    Commented Dec 12, 2013 at 12:07
  • But I show/hide fields with #states (with JavaScript). after_build function is called before you click submit, right? So I think I have to set #required = FALSE for every field and then validate what fields I want, right?
    – ilazgo
    Commented Dec 12, 2013 at 12:26
  • After build function is called when the form is built, which happens both before and after submission. There is a check in the after build callback that makes sure you are dealing with the form after the submit button is pressed. #states work based on values of other fields, so in you after build you can check the values of those fields to work out what the state was and which fields would have been hidden. You don't need any custom validation code.
    – rooby
    Commented Dec 12, 2013 at 14:08
  • If course you could also make all fields not required and then do custom validation if you wanted. That would still work.
    – rooby
    Commented Dec 12, 2013 at 14:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.