I have a problem with setting the default value of my 'radios' button, dynamically. In my code, I have an addresses radios group stated like this:

$form['addresses'] = array(
      '#type' => 'radios',
      '#title' => '',
      '#options' => $addresses,
      isset($user->data['NewAddress']) ? $user->data['NewAddress'] : 0,
    );

This works, however, in my form, I have an ajax callback that lets the user add a new address and this address also gets added to the form once they save the address, via ajax. I want to now set the default value to this new address. The default_value, if I do a dd() of it, shows that it is set to the new address, however, it just doesn't get selected.

I have read somewhere, that the default_value only works the first time that a form is loaded. My situation is, the form loads once, then all the changes are being made via Ajax. I do a $form_state['rebuild'] = true; after each new address is saved, however. So, basically, my question is, is there any way to get around this issue. How can we set the default_value each time a new address is entered via Ajax?

Any help would be greatly appreciated. Thanks.

Comments

<?php
 
if(isset($form_state['values']['NewAddress']))
  {
   
$default_address = $form_state['values']['NewAddress'];
  }
  elseif(isset(
$user->data['NewAddress']))
  {
   
$default_address = $user->data['NewAddress'];
  }
  else
  {
   
$default_address = 0;
  }
 
$form['addresses'] = array(
     
'#type' => 'radios',
     
'#title' => '',
     
'#options' => $addresses,
     
'#default_value' => $default_address, // or maybe array($default_address)
   
);
?>

Jaypan
Our newest Drupal site: PacificAikido.com (Drupal showcase)

Thanks for the example, but unfortunately, it is still not making any effect. A dd($default_value) and dd($form['addresses']['#default_value'] shows that the default value is the new address value, but it just isn't getting selected. Wonder, why there is a problem with the select button moving from the old address to the newly-entered address. Seems simple enough...

Shabana Navas
Drupal Developer
Blackborder

I don't know what to say. I've used the above many times, both in #ahah in D6, and #ajax in D7, and it works fine. I'm guessing it's something else in your code, but cannot tell from the bit you've given.

Jaypan
Our newest Drupal site: PacificAikido.com (Drupal showcase)

After further debugging of the radios button, I have found out that, once a new address is entered via Ajax (a div with the old address radios is replaced with a div with the new address included), the #default_value is set to the new address, however, the #value remains the same, pointed to the initial default address during form load. This is how the addresses radios array looks for a particular address:

[48720] => Array
  (
    [#default_value] => 48722
    [#value] => 48721
  )

As you notice, the #default_value is set to the new address, but the #value is the same. Do you think this has anything to do with the default value not getting checked? I tried setting the #value to the new address, as well, but that didn't work. Also tried using a #value_callback function to set it to the new address, but still no luck. Any ideas, as to why it would keep the #value the same despite rebuilding the form after every new address has been inserted?

UPDATE!! I wanted to test if the #value was the one that was causing the new address to be not selected, so what I did (as much as I don't like doing this) is, I manually, changed the #value for each option in the addresses radio box to the default value to see if that made any difference. Well, presto, it worked! The new address is being selected as the default address now. This is the code that I did:

<?php
//We have to set the #value of each address in the radio box to the default_value as well, otherwise, the new address won't get checked as the default
foreach($form['addresses']['radios']['#options'] as $key => $value) {
 
$form['addresses']['radios'][$key]['#value'] = isset($user->data['NewAddress']) ? $user->data['NewAddress'] :  $default_value;
}
?>

So now the question is, why would the #value remain the same? Even though, after each rebuild, we are populating the radio button from scratch. Also, note, I tried to unset the radio button after each new address was submitted, but that didn't work either.

Shabana Navas
Drupal Developer
Blackborder

#value cannot be overridden, no matter what the user enters. If the user submits 3, and #value is set to 2, then the submitted value will be 2 regardless. If you set #default_value and #value, #default_value has no meaning since #value is the value.

Jaypan
Our newest Drupal site: PacificAikido.com (Drupal showcase)

I think that the #value is setting every time that a new address is saved. Basically, my Ajax button for saving a new address is of type "submit", I am thinking this submits the form. My button definition is like this:

<?php
//Add the submit button to save the new address in the database and replace the address div with the new address added
   
$form['save'] = array(
     
'#type' => 'submit',
     
'#name' => 'Save',
     
'#value' => 'Save',
     
'#ajax' => array(
       
'callback' => 'NewAddress_Save_ajax_callback',
       
'wrapper' => 'NewAddress_wrapper',
       
'method' => 'replace',
      ),
     
'#submit' => array('NewAddress_submit'),
     
'#validate' => array('NewAddress_validate'),
    );
?>

Is it because it is type "submit" that the #value, which is the initial #default_value, is being set each time I save a new address. I guess, we can change the button to #type "button", but if I understand it correctly, a button, which is of #type "button" will not call the #submit handler, and thus, my "NewAddress_submit" function won't get called. If so, then what would be the way around this?

How can we basically, NOT get the radios button value to submit each time we save an address?

Shabana Navas
Drupal Developer
Blackborder

Can you show your form definition?

Jaypan
Our newest Drupal site: PacificAikido.com (Drupal showcase)

I have copied and pasted all the relevant form definitions for this radios problem:

<?php
 
//Get the addresses that this user has under their uid from the database
 
$result = db_query("SELECT add_id, add_First_Name, add_Last_Name, add_Address, add_City, add_State, add_Zip_Code, add_Country
    FROM {addresses}
    WHERE uid = :uid"
, array(
   
':uid' => $node->uid
 
));
 
//Fieldset for the addresses, this is being themed, as we want each address radio button
  //to be followed by its own edit and delete buttons
 
$form['addresses'] = array(
   
'#type' => 'fieldset',
   
'#theme' => 'theme_Addresses',
   
'#prefix' => '<div id="Addresses_wrapper">',
   
'#suffix' => '</div>',
  );
 
//Check to see if there are any addresses for this user
 
if ($result->rowCount()) {  
   
//Initialize the addresses array to enter all the available addresses for this user
   
$addresses = array();
   
//Just a counter to keep track of the default value for the radio button, basically the first address should be selected
   
$count = 0;
   
//Now store all the addresses available for this user in the addresses array
   
foreach ($result as $address) {
     
$addresses[$address->add_id] = '<b>' . $address->add_first_name . ' ' .
     
address->add_last_name . '</b><br>' .
     
$address->add_address . ',' . '<br>' .
     
$address->add_city . ',' . '<br>' .
     
$address->add_state . ',' . '<br>' .
     
$address->add_zip_code . '<br>' .
     
$address->add_country;
    }
       
//Add the edit button for this address
        //Also adds the ajax callback, basically this would be like entering a new address only
        //that we retrieve the address values from the database and insert it into the textfields as the default_value
       
$form['addresses']['editaddress' . $address->add_id] = array(
         
'#type' => 'button',
         
'#value' => 'Edit',
         
'#name' => 'Edit Address' . '-' . $address->add_id,
         
'#ajax' => array(
           
'callback' => 'EditAddress_ajax_callback',
           
'wrapper' => 'EditAddress_wrapper-' . $address->add_id,
           
'method' => 'replace',
          ),
         
'#prefix' => '<div id="EditAddress_wrapper-' . $address->add_id . '">',
         
'#suffix' => '</div>',
         
'#limit_validation_errors' => array(),
         
'#submit' => array(),
         
'#weight' => 20,
        );
       
//Add the delete button for this address
       
$form['addresses']['deleteaddress' . $address->add_id] = array(
         
'#type' => 'button',
         
'#value' => 'Delete',
         
'#name' => 'Delete Address' . '-' . $address->add_id,
         
'#ajax' => array(
           
'callback' => 'DeleteAddress_ajax_callback',
           
'wrapper' => 'DeleteAddress_wrapper-' . $address->add_id,
           
'method' => 'replace',
          ),
         
'#prefix' => '<div id="DeleteAddress_wrapper-' . $address->add_id . '">',
         
'#suffix' => '</div>',
         
'#limit_validation_errors' => array(),
         
'#submit' => array(),
         
'#weight' => 20,
        );
       
//Save the first address id, to make it as the default value for the radio buttons
       
if ($count == 0) {
         
$default_value = $address->add_id;
        }
       
$count++;
    }
   
//Add all the addresses to the radios button
   
$form['addresses']['radios'] = array(
     
'#type' => 'radios',
     
'#title' => '',
     
'#options' => $addresses,
     
'#default_value' => isset($user->data['NewAddress']) ? $user->data['NewAddress'] : $default_value,
    );
   
//Display the fields when the 'Add_Address' form state is 1
   
if ($form_state['Add_Address'] == 1) {
   
//Fieldset, container for the new address fields
   
$form['newaddress']['fieldset'] = array(
     
'#title' => t("Please enter your details"),
     
'#prefix' => '<div id="NewAddress_wrapper">',
     
'#suffix' => '</div>',
     
'#type' => 'fieldset',
    );
   
//Display the fields to enter the new address information
   
$form['newaddress']['fieldset']['first_name'] = array(
     
'#type' => 'textfield',
     
'#title' => t('First Name:'),
     
'#size' => 30,
     
'#maxlength' => 128,
     
'#required' => TRUE,
     
'#default_value' => isset($edit_address) ? $edit_address->add_first_name : '',
    );
   
$form['newaddress']['fieldset']['last_name'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Last Name:'),
     
'#size' => 30,
     
'#maxlength' => 128,
     
'#required' => TRUE,
     
'#default_value' => isset($edit_address) ? $edit_address->add_last_name : '',
    );
   
$form['newaddress']['fieldset']['streetaddress'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Address:'),
     
'#size' => 30,
     
'#maxlength' => 128,
     
'#required' => TRUE,
     
'#default_value' => isset($edit_address) ? $edit_address->add_address : '',
    );
   
$form['newaddress']['fieldset']['city'] = array(
     
'#type' => 'textfield',
     
'#title' => t('City:'),
     
'#size' => 30,
     
'#maxlength' => 128,
     
'#required' => TRUE,
     
'#default_value' => isset($edit_address) ? $edit_address->add_city : '',
    );
   
$form['newaddress']['fieldset']['country'] = array(
     
'#type' => 'select',
     
'#title' => t('Country:'),
     
'#options' => $countries,
     
'#required' => TRUE,
     
'#default_value' => isset($edit_address) ? $edit_address->add_country : 1,
    );
   
$form['newaddress']['fieldset']['state'] = array(
     
'#type' => 'select',
     
'#title' => t('State:'),
     
'#options' => $states,
     
'#default_value' => isset($edit_address) ? $edit_address->add_state : 0,
      ),
    ); 
   
$form['newaddress']['fieldset']['zipcode'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Zip Code:'),
     
'#size' => 10,
     
'#maxlength' => 128,
     
'#required' => TRUE,
     
'#default_value' => isset($edit_address) ? $edit_address->add_zip_code : '',
    );
   
//Add the submit button to save the new address in the database and update the address list with the new address added
   
$form['newaddress']['fieldset']['save'] = array(
     
'#type' => 'submit',
     
'#name' => 'Add New Address',
     
'#value' => 'Save',
     
'#ajax' => array(
       
'callback' => 'NewAddress_Save_ajax_callback',
       
'wrapper' => 'NewAddress_wrapper',
       
'method' => 'replace',
      ),
     
'#submit' => array('NewAddress_submit'),
     
'#validate' => array('NewAddress_validate'),
    );
   
//Add the cancel button to cancel the "Add New Address" form
   
$form['newaddress']['fieldset']['cancel'] = array(
     
'#type' => 'button',
     
'#name' => 'New Address Cancel',
     
'#value' => 'Cancel',
     
'#ajax' => array(
       
'callback' => 'NewAddress_Cancel_ajax_callback',
       
'wrapper' => 'NewAddress_wrapper',
       
'method' => 'replace',
      ),
     
'#limit_validation_errors' => array(),
     
'#submit' => array(),
    );
  }
 
//Else, add the enter new address button
 
else {
   
//Add a button to enter new addresses
   
$form['newaddress']['addnewaddress'] = array(
     
'#type' => 'button',
     
'#name' => 'Add New Address',
     
'#value' => 'Add New Address',
     
'#ajax' => array(
       
'callback' => 'NewAddress_ajax_callback',
       
'wrapper' => 'AddAddress_wrapper',
       
'method' => 'replace',
      ),
     
'#prefix' => '<div id="AddAddress_wrapper">',
     
'#suffix' => '</div>',
     
'#limit_validation_errors' => array(),
     
'#submit' => array(),
    );
  }
?>

Shabana Navas
Drupal Developer
Blackborder

With this line of code:

<?php
'#default_value' => isset($user->data['NewAddress']) ? $user->data['NewAddress'] : $default_value,
?>

If the $user object has the $user->data['NewAddress'] field set on it, the radios will always be set to that value no matter what. Try looking at the code in my first post again. You want to set priority as follows:

Submitted value -> pre-existing value -> default value.

So if a value has been submitted, that should be used, as the user may have overridden the default. Else if no value has been submitted, then all we have is the pre-existing value, so we should use that. And if no pre-existing value exists, then the default value should be used.

Jaypan
Our newest Drupal site: PacificAikido.com (Drupal showcase)

I actually tried that recommendation after your post and it still didn't check the new address. I currently have the #default_value commented, as it isn't working either way.

Shabana Navas
Drupal Developer
Blackborder

In that case, you haven't set #value or #default_value, so the first option will always be selected no matter what happens.

Jaypan
Our newest Drupal site: PacificAikido.com (Drupal showcase)

As I mentioned before, I have it working now with that nasty little for-loop that I created:

<?php
//We have to set the #value of each address in the radio box to the default_value as well, otherwise, the new address won't get checked as the default
foreach($form['addresses']['radios']['#options'] as $key => $value) {
 
$form['addresses']['radios'][$key]['#value'] = isset($user->data['NewAddress']) ? $user->data['NewAddress'] :  $default_value;
}
?>

So, basically, the #default_value in my radios definition is really not needed. Would appreciate it, if you could let me know, if the reason for the initial default value getting set is the ajax button being a #type "submit". If that is the case, then what can I do to get around it, as I need my #submit handlers to be called when the ajax save button is clicked.

Shabana Navas
Drupal Developer
Blackborder

I had the same problem with my code today.
I had to update a textarea element based on selectbox's value and #default_value didn't work, and #value was continuously breaking the user subbmition until I moved the code that sets #value to my AJAX callback.
Now my textarea element is updating properly and user input is properly delivered to my submit handler.

I found this thread after running into a similar problem when trying to use #default_value in form elements when using AJAX callbacks. Here is some example code for doing this:

<?php
/**
* Example of how to set default values for form fields when using AJAX callbacks.
*
* In this example, the form has a select field called "Size" and a text
* field called "Price".  When the user selects a different value for
* "Size", the value of "Price" is updated automatically via AJAX.
*/
function my_example_form($form, &$form_state) {
 
$form['size'] = array(
   
'#title' => t('Size'),
   
'#type' => 'select',
   
'#options' => array(
       
0 => '--',
       
1 => 'Small',
       
2 => 'Medium',
       
3 => 'Large'
    
),
   
// #default_value only gets used the first time the form page is loaded,
    // NOT for any subsequent AJAX calls
   
'#default_value' => 0,
   
'#ajax' => array(
     
'callback' => 'my_example_ajax_callback',
     
'wrapper' => 'price-wrapper',
     
'method' => 'replace',
     
'effect' => 'fade',
    ),
  );
 
$form['price'] = array(
   
'#title' => t('Price'),
   
'#type' => 'textfield',
   
'#prefix' => '<div id="price-wrapper">',
   
'#suffix' => '</div>',
  );
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Submit'),
  );
  return
$form;
}
function
my_example_ajax_callback($form, &$form_state) {
  if (!empty(
$form_state['values']['size'])) {
   
$size = $form_state['values']['size'];
    if (
$size == 1) {
     
// You could also do something like:
      // $form['price']['#value'] = $form['price']['#default_value']
      // if your form builder function already computed/set a #default_value
     
$form['price']['#value'] = '$1.99';
    }
    if (
$size == 2) {
     
$form['price']['#value'] = '$2.99';
    }
    if (
$size == 3) {
     
$form['price']['#value'] = '$3.99';
    }
  }
  else {
   
$form['price']['#value'] = '';
  }
  return
$form['price'];
}
function
my_example_form_submit($form, &$form_state) {
 
$size = $form_state['values']['size'];
 
$price = $form_state['values']['price'];
 
drupal_set_message(t('You submitted: Size = %size, Price = %price', array('%size' => $size, '%price' => $price)));
}
?>