1

I have a form that includes a set of radio inputs, and other fields that will or will not be relevant, depending on which radio option is selected. I'm using #states for client-side UX sugar.

However there are certain conditions, picked up in the validate function that need to change the value the user entered for the radio, and re-present the form with a different option selected. I'm having problems with this, as the form comes back but the option is not changed. e.g. Submitting this should with 'a' selected should change it to 'b' and re-present.

What happens is that the value is set to b, the form rebuilds, but the browser still shows 'a' selected.

<?php
function x_a_form($form, &$form_state) {
  return [
    'switcher' => [
       '#type' => 'radios',
       '#options' => [
           'a' => 'Aye',
           'b' => 'Bee', ],
       '#default_value' => empty($form_state['values']['switcher']) 
                           ? 'a' 
                           : $form_state['values']['switcher'],
    ],
    'submit' => ['#type' => 'submit', '#value' => 'Go' ],
  ];
}

function x_a_form_validate($form, &$form_state) {
  // silly example of a condition...
  if ($form_state['values']['switcher'] == 'a') {
     // Change the value.
     // Nb. form_set_value() is a very long winded way to do just this:
     $form_state['values']['switcher'] = 'b';
     // We will not be saying anything is invalid, but we don't want
     // the form to submit.
     $form_state['rebuild'] = TRUE;
     return;
  }
  // other validation...
}
1

1 Answer 1

1

Did a little more digging. It seems when Drupal (re)builds a form, it sets the element values based on the actual form input ($form_state['input']) and not the form values ($form_state['values']). See _form_builder_handle_input_element. So form_set_value does changes the form value, but it does not update the form input and, therefore, does not get processed how you want it to in this case. While I don't know if this is the "proper" way to do this, but in your form function, you can try throwing in something like:

if (!empty($form_state['values']['myelement']) {
  $form_state['input']['myelement'] = $form_state['values']['myelement'];
}

I tried this with a textfield element, and the value I set using form_set_value was displayed in the textfield when the form was rendered.

6
  • Pls see comment in my code and/or the source for that function on the page you linked to. Mar 16, 2015 at 17:37
  • Sorry, missed that part. Long winded or not, form_set_value does what you want it to do. You could alternatively set a separate variable in $form_state. Something like $form_state['my_module']['switcher']. Mar 16, 2015 at 19:53
  • My point is that it doesn't do anything. You can replace that line of code with form_set_value(['#parents'=>['switcher']], 'b', $form_state) and the behaviour is identical. Mar 16, 2015 at 19:57
  • Edited my answer. Please see. Mar 16, 2015 at 21:32
  • 1
    Came to same conclusion. Thanks, accepted your answer. Basically what happens is: form build → copy input to values → validate changes values and sets rebuild → rebuild triggers form build → original input copied again over values. So values set in validate that are in input are lost when rebuild is triggered. Mar 17, 2015 at 10:00

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.