7

I have an AJAX form. I want to update the text of a textfield when a button is triggered. But this does not work. My form is below:

<?php
function my_form($form, &$form_state) {
  $form['ask_first_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Ask me my first name'),
    '#default_value' => 'I LOVE chickens',
    '#prefix' => '<div id="textfields">',
    '#suffix' => '</div>',
  );
  $form['update'] = array(
    '#type' => 'button',
    '#value' => t('Update'),
    '#ajax' => array(
      'callback' => 'ajax_example_autotextfields_callback',
      'wrapper' => 'textfields',
      'effect' => 'fade',
    ),
  );

  // shouldn't this update the default value when the button is pressed??
  if (isset($form_state['values'])) {
    $form['ask_first_name']['#default_value'] = 'I HATE chickens';
  }

  return $form;
}
?>

When I press the 'update' button I'm expecting the field text to change, but it doesn't. If I use #value instead of #default_value it works, but I know I shouldn't use that because I still want the user to be able to change it again.

<?php
// using #value works - but should I use that?
$form['ask_first_name']['#value'] = 'I HATE chickens';
?>

What is the recommended Drupal way to change the field value after AJAX is triggered?

NOTE: This answer solved the problem in my case, but as mentioned in the comments there is not access to the values in $form_state['values'] after submit. However, I'm storing the data in $form_state['storage'] so I can still access the data, though I'll probably implement ctools object cache in the end.

5 Answers 5

5

This is taken from the description of #default_value in the form api documentation:

The value of the form element that will be displayed or selected initially if the form has not been submitted yet

Because your form has been submitted, it wont be using #default_value. Just use #value, the user will still be able to change it.

2021 edit.....
As people have pointed out, the above is wrong as although it will allow you to set the value, it wont allow the user to submit an altered value.

Now using Drupal 9, in a form alter, I needed to set some default field values when an ajax button (which I inserted) was clicked.
I needed to set default values on the node "body" field and "field_url" link field.
I removed the user input for these fields before setting a default value.

$userInput = $form_state->getUserInput();
unset($userInput['body']);
unset($userInput['field_url']);
$form_state->setUserInput($userInput);

$form['body']['widget'][0]['#default_value'] = 'my default value set after ajax callback';
$form['field_url']['widget'][0]['uri']['#default_value'] = 'my default value';

To be honest, I am not 100% sure it is the correct way, but it does work.

6
  • 2
    User-entered value will not be includes in $form_state['values'] if #value is set.
    – AKS
    Feb 5, 2013 at 2:51
  • 1
    @Ayesh K. If it works with #value and it's okay to do so, I'll do that. I can always get the value from $form_state['input']? Feb 5, 2013 at 9:06
  • Ayesh K may be correct, I haven't tried it. @ Web Assistant, try it an tell us if it works.
    – 2pha
    Feb 5, 2013 at 12:33
  • 1
    I've got this working, but the thing stopping me giving it a correct answer is that the data does not appear in $form_state['values'] or $form_state['input'] after submit, as Ayesh said. I've worked around this by storing the data in $form_state['storage']. If I don't find a better answer I'll mark this as the accepted answer. Feb 5, 2013 at 14:30
  • 8 years later I start reading this answer only to realize it's by me... lol. The answer is wrong BTW, Doing it like this ignored further user input.
    – 2pha
    Mar 27, 2021 at 5:10
2

I made it the quick and dirty way. In my ajax callback, I set the

$form['inputfield']['#value'] = $form['inputfield']['#default_value'];

The I changed the value in the input field manually to test if the value can be changed by user and is then submitted. After checking the $form_state['values']['inputfield'] I realized, that the value was correctly submitted, although the field got a '#value' attribute in the ajax callback.

But I think you have to be careful: Only set the '#value' attribute in the ajax callback, not in the form declaration!

Hope that helps, although a little bit late.

1
  • The extra important part of this is: "you have to be careful: Only set the '#value' attribute in the ajax callback, not in the form declaration!"
    – DrCord
    Sep 17, 2014 at 20:14
2

As 2pha pointed out #default_value cannot be changed once the form has been submitted. However the array in $form_state['input'] can be manipulated at any time.

To update the example you gave:

if (isset($form_state['values'])) {
  $form_state['input']['ask_first_name'] = 'I HATE chickens';
}

When the actual html for your form is built the value we set in $form_state['input'] will be used as the default value.

1
  • This seems like the best solution to me
    – argiepiano
    Dec 12, 2016 at 16:43
1

2pha's answer did not work for me - if I set values with um, value, ie $form['myfield']['#value'] then sure the value changed - but it then ignored further user input!

So this is how I achieved setting values dynamically in my form builder function during ajax call backs and still let the user amend the values (within the if at end).

Note in my case, I'm updating 3 fields whenever the user changes a couple of other fields.

 $form['ld']['letterdrop_allocations'] += array(                                              
     '#type' => 'textfield',                                                                  
     '#title' => t('Letterdrop allocations for %contact in drop %letterdrop',     
       $tokens),                                                                              
     '#description' => 'blah.'                                  
     );                                                                                       

 $form['ld']['letterdrop_notes'] = array(                                                     
     '#type' => 'textfield',                                                                  
     '#title' => 'Notes',                                                                     
     '#description' => t('notes for all allocations %contact in drop %letterdrop',            
       $tokens));                                                                                 

 $form['ld']['letterdrop_kitstate'] = array(                                                  
     '#type' => 'select',                                                                     
     '#title' => 'Kit state',                                                                 
     '#options' => AgcLetterDrop::kitstates(),                                                
     '#description' => 'some words for here');                                                                                                     

 if ($letterdrop_allocations_changed) { // overwrite field values                                         
   unset($form_state['input']['letterdrop_allocations']);                                     
   unset($form_state['input']['letterdrop_notes']);                                           
   unset($form_state['input']['letterdrop_kitstate']);                                        

   $form['ld']['letterdrop_notes']['#default_value'] =                                        
     $ldallocations['notes'];                                                                 
   $form['ld']['letterdrop_allocations']['#default_value'] =                                  
     $ldallocations['lda_id'];                                                                
   $form['ld']['letterdrop_kitstate']['#default_value'] =                                     
     $ldallocations['kit_state'];                                                             

 }                                                                                            

hope that helps - i've lost about ten hours on this!

1
  • 3
    This will work - the values will change, however it would be simpler to just update $form_state['input'] directly instead of unsetting it and then setting the #default_value
    – Felix Eve
    Jun 11, 2015 at 6:47
0

I believe the proper way to change the user input or a submitted form value is by calling form_set_value.

This comment explains how to use this.

// form_set_value requires that #parents be set on the field
$form['field_your_field']['#parents'] = array('field_your_field'); 
// set the value by calling form_set_value($element, $value, $form_state)
form_set_value($form['field_your_field'], array('und' => array(0 => array('value' => 'WORKS'))), $form_state);

$form_state is passed by reference so the actual user input is changed and this will be reflected when the form is rebuilt and passed back by ajax callback. Therefore I think it's best to call this function during a form_validate function.

Your Answer

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

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