1

I'm sure there's a standard Drupal way of doing this, but I've tried a couple of the statements that I've found on blogs and stuff, and I can't get a form to restore the values submitted by the users.

For example:

  • form default value: "enter a long word"
  • user submits: "foo"
  • validation sets: "word not long enough"
  • form displayed on page with value: "enter a long word"
  • expected value: "foo"

So far, in the hook_nameform_validate function, I've tried setting form_state['rebuild'] and form_state['redirect'] to FALSE (I've seen both listed in blogs as the right answer). Perhaps unsurprisingly to anyone who knows the correct answer, neither works individually, nor do they both work together.

EDIT as requested, here is some actual code to show what I'm doing (wrong). You're correct that the question was probably too general to be of value without any actual code on display. This sample is still "abstracted" - there's closer to a dozen fields, but the effect is the same.

In this case, with these functions (and the others, like theme etc...) when a user submits their email address, if the validation returns an error, the form tells them "bad user" then clears the email field (and all others). Ideally the form should repopulate all fields with any typing they've already done.

function sampleform_nameform($form, &$form_state) {
    $d = sampleform_defaults();
    $form = array(
        '#method'                   => 'post',
        '#prefix'                   => $d['form_prefix'].'<div class="sample">',
        '#suffix'                   => '</div>'.$d['form_suffix'],
        'your_email'                => array(
            '#value'            => $d['your_email'],
            '#type'             => 'textfield',
            '#field_suffix'         => '<span class="required">*</span>',
            '#required'             => TRUE,
            '#attributes'           => array('class' => array('standardInput'),
                                             'default' => $d['your_email'])
        ),
        'sampleform_submit'         => array(
            '#prefix'               => $d['clear'],
            '#type'                 => 'submit',
            '#value'                => $d['submit'],
            '#attributes'           => array('class' => array('buttonInput', 'submitInput')),
            '#executes_submit_callback' => true
        )
    );
    return $form;
}

function sampleform_nameform_validate($form, &$form_state){
    $d = sampleform_defaults();
    if (!valid_email_address($form_state['input']['your_email'])) {
        form_set_error('your_email', $d['e_email_v']); 
    }
}

It's very possible that one of the two answers below has fixed the issue, and I've not had the chance to read them yet, so with a few more minutes, maybe we'l find the answer is already here.

:)

EDIT 2

kiamlaluno has shown us that while I was using #value in my form-builder function, the correct nondestructive setting in creation of a form is #default_value

If I look back to my original reference point, Pro Drupal 7 Development the form API examples in chapter 11 give the instruction to use #value on page 247 (where you build your first form).

They also use MODULENAME_nameform as the hook, while it appears to be more correct to use MODULENAME_form (according to the way drupal works, it's easier to find further documentation if you search for _form rather than nameform).

Anyways, hopefully this saves someone else some time. Someone should probably tell Todd Tomlinson and John K VanDyk that they've got an error in their book.

:)

2
  • May you show the code that builds the form, and the form validation handler code? As side note, a form validation handler is not a hook.
    – avpaderno
    Commented Aug 19, 2011 at 23:11
  • I am not sure if I fully understand your question. Are you asking about the case where the form has both your long word field and one or more other fields like say a city and state text field in addition to the form submit button(s)? Are you asking how to preserve what the user entered in the example city and state fields when an error is encountered validating your long word field?
    – LToomre
    Commented Aug 20, 2011 at 8:21

2 Answers 2

2

There is nothing particular that needs to be done, to avoid to overwrite the value entered by the user, when a validation handler returns an error.

For example, the following form, is build from the code shown below (system_ip_blocking_form()):

screenshot

function system_ip_blocking_form($form, $form_state, $default_ip) {
  $form['ip'] = array(
    '#title' => t('IP address'), 
    '#type' => 'textfield', 
    '#size' => 48, 
    '#maxlength' => 40, 
    '#default_value' => $default_ip, 
    '#description' => t('Enter a valid IP address.'),
  );
  $form['actions'] = array('#type' => 'actions');
  $form['actions']['submit'] = array(
    '#type' => 'submit', 
    '#value' => t('Add'),
  );
  $form['#submit'][] = 'system_ip_blocking_form_submit';
  $form['#validate'][] = 'system_ip_blocking_form_validate';
  return $form;
}

Its validation handler is the following one (system_ip_blocking_form_validate()):

function system_ip_blocking_form_validate($form, &$form_state) {
  $ip = trim($form_state['values']['ip']);
  if (db_query("SELECT * FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField()) {
    form_set_error('ip', t('This IP address is already blocked.'));
  }
  elseif ($ip == ip_address()) {
    form_set_error('ip', t('You may not block your own IP address.'));
  }
  elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) == FALSE) {
    form_set_error('ip', t('Enter a valid IP address.'));
  }
}

When I enter a value for which the validation handler returns an error, the value I enter is not modified, as you can see from the following screenshots.

screenshot

screenshot

This is what happens on Drupal 6 too. The only case where a field value is cleared is when the form validation handler reports an error for a password form field; in that case the password field doesn't contain the previously entered password, which would be difficult to edit as it is shown as "•••••."

There is nothing that needs to be set; by default Drupal will not change the content of a field when a validation handler reports an error for that field. As far as I know, the value of a field could be changed by its "#after_build" callback, that is invoked after the field is built, and that is described in form_builder() with the following sentence:

The "#after_build" flag allows any piece of a form to be altered after normal input parsing has been completed.

3
  • 1
    I see you're using #default_value, while I'm putting #value in there. I wonder if that's having an effect. I'll try that now.
    – Alex C
    Commented Aug 20, 2011 at 14:37
  • OOOOOOOOOOOOOOOHHHHH YEAAAAHHHHH!!!! Thankyou thankyou thankyou thankyou thankyou thankyou thankyou thankyou thankyou thankyou thankyou... I was expecting to spend my whole Saturday fixing this, huge deadline Monday and this worked the first try. Woooo! Thanks. You have literally saved my weekend.
    – Alex C
    Commented Aug 20, 2011 at 14:42
  • 1
    You should use "#default_value"; using "#value" you are not allowing the user to set a value because, as you said, the value of that property is overriding the value set by the user. The code I shown comes from one of Drupal core modules; it's not code I wrote for one of my modules.
    – avpaderno
    Commented Aug 20, 2011 at 20:38
1

Quick example of validating form:

function MODULENAME_form($form, &$form_state) {
  $form['SOMEFIELDNAME'] = array(
    '#type' => 'textfield,
    '#title' => t('SOMETITLE'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}
function MODULENAME_form_validate($form, &$form_state) {
  if (strlen($form_state['values']['SOMEFIELDNAME'])<=3) { // or use mb_strlen()
    form_set_error('SOMEFIELDNAME', t('word not long enough'));
  }
}
function MODULENAME_form_submit($form, &$form_state) {
  // Here will vaildated data.
}

?>

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.