4

I have a form with managed file field. Form has single field. I have declared this field as required and indeed after submit without file I have an error: Field is required.

I wanted to add HTML5 validation to this field, but in my custom theme_file implementation $variables array has #required => FALSE for this field...

I have even red asterisk above this input field so I truly don't know what is wrong..

My custom theme_file:

function custom_file($variables) {
    if (! _custom_isMyTheme()) {
        return theme_file($variables);
    }

    $tpl = <<<HTML
    <div class="inputFile" style="width:390px; height:36px;">
        <div class="inputFileContainer">
            <div class="inputFileField"></div>
            <div class="inputFileButton">%s</div>
        </div>
        %s
    </div>
HTML;
    dpm($variables);//devel shows #required property as FALSE
    return sprintf($tpl, t('Select'), theme_file($variables));
}
  • I see it too – adding a required managed file field has #required => TRUE in theme_field_widget(), and then drupal_render_children() in the render chain, and then in drupal_render() it suddenly becomes FALSE and remains thusly in your theme_file() implementation. My initial guess is that the input type="file" isn't required but the hidden input is. I'll look a bit deeper into form.inc locally and see if I have more ideas... – Charlie Schliesser Sep 2 '13 at 1:04
  • 1
    Agh my eyes! What are you doing with that HEREDOC? Please, consider using a theme hook! see drupal.stackexchange.com/a/83855/487 – Capi Etheriel Sep 2 '13 at 12:51
  • @barraponto if he's overriding theme_file, why would he need to declare a new theme function? – Charlie Schliesser Sep 2 '13 at 15:24
  • Yeah, he can use template file with hook_theme_alter. But I don't recall seeing any HEREDOC template in a theme funcion... – Capi Etheriel Sep 4 '13 at 0:49
  • 1
    I am calling stadard theme_file function too, so using heredoc has totally no meaning in this case – Codium Sep 9 '13 at 6:00
2
+250

In short, the hidden input field that stores the file ID (fid) is what is required, but the displayed file upload element isn't. The actual "displayed" element is added to that form element in file_managed_file_process() in file.module. Specifically, check out line 440 of that file:

  // The file upload field itself.
  $element['upload'] = array(
    '#name' => 'files[' . implode('_', $element['#parents']) . ']',
    '#type' => 'file',
    '#title' => t('Choose a file'),
    '#title_display' => 'invisible',
    '#size' => $element['#size'],
    '#theme_wrappers' => array(),
    '#weight' => -10,
  );

This has no #required property, and so therefore defaults to FALSE. If you dpm() your element earlier in the process (before it's expanded to include more hidden elements and attach the necessary javascript and CSS to be a full-fledged "managed file" element) you'll see your #required => TRUE.

I would add an additional function to the #process property of your form element, which will run after file_managed_file_process(). In it, you can check if the original element had #required => TRUE and then also set that on the $element['upload'] item. I haven't tried it, but I think that would get you what you want.

Edit: It would be wiser to do this in #after_build and not just append to #process. Here's an example:

<?php

function my_form_builder($form, &$form_state) {
  $form['file'] = array(
    '#type' => 'managed_file',
    '#title' => 'Upload a File',
    '#required' => TRUE,
    '#after_build' => array('my_file_element_after_build')
  );

  return $form;
}

function my_file_element_after_build($element, &$form_state) {
  // Set the 'file' element to have the same #required property as its original form element.
  $element['upload']['#required'] = $element['#required'];
  return $element;
}

?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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