When building a form definition in your form building function, array keys are used to specify information about the
form. The most common keys are listed in the following sections. Some keys are added automatically by the form
builder.
Properties for the Root of the Form
The properties in the following sections are specific to the form root. In other words, you can set $form ['#programmed'] = TRUE, but setting $form['myfieldset']['mytextfield'][#programmed'] = TRUE
will not make sense to the form builder.
#action
The path to which the form will be submitted.
#built
Used to ascertain whether a form element has been built yet.
#method
The HTTP method with which the form will be submitted.
Properties Added to All Elements
When the form builder goes through the form definition, it ensures that each element has some default values set. The default
values are set in _element_info() in includes/form.inc but can be overridden by an element’s definition in hook_elements().
#description
This string property is added to all elements and defaults to NULL. It’s rendered by the element’s theme function. For example, a
text field’s description is rendered underneath the text field, as shown in Figure 11-2.
#attributes
Additional HTML attributes, such as “class” can be set using this mechanism. The following example sets the CSS class of the
form to “search-form”.
<?php
$form[‘#attributes’] = array(‘class’ => ‘search-form’);
?>
#required
This Boolean property is added to all elements and defaults to FALSE. Setting this to TRUE will cause Drupal’s built-in form
validation to throw an error if the form is submitted but the field has not been completed. Also, if set to TRUE, a CSS class is
setfor this element (see theme_form_element() in includes/form.inc).
#tree
This Boolean property is added to all elements and defaults to FALSE. If set to TRUE, the $form_state['values'] array resulting
from a form submission will not be flattened. This affects how you access submitted values (see the “Fieldsets” section of this
chapter).
Properties Allowed in All Elements
The properties explained in the sections that follow are allowed in all elements.
#type
This string declares the type of an element. For example, #type = 'textfield'. The root of the form must contain the declaration
#type = 'form'.
#access
This Boolean property determines whether the element is shown to the user. If the element has children, the children will not be shown if the parent’s #access property is FALSE. For example, if the element is a fieldset, none of the fields included in the field set
will be shown if #access is FALSE.
The #access property can be set to TRUE or FALSE directly, or the value can be set to a function that returns TRUE or FALSE when executed. Execution will happen when the form definition is retrieved. Here’s an example from Drupal’s default nodeform:
$form['revision_information'
['revision'] = array( '#access' => user_access('administer nodes'),
#type' => 'checkbox','#title' =>
t('Create new revision'), '#default_value' => $node->revision,);
#after_build
An array of function names that will be called after the form or element is built.
#array_parents
The array of names of the element's parents (including itself) in the form. This will always match the structure of $form. It is
different from #parents in that #parents lists only the structure used in $form_state['values'], which is flat unless #tree is set
to TRUE.
#attached
A keyed array of type => value pairs, where the type (most often “css”, “js”, and “library”) determines the loading
technique, and the value provides the options presented to the loader function.
#default_value
The type for this property is mixed. For input elements, this is the value to use in the field if the form has not yet been
submitted. Do not confuse this with the #value element, which defines an internal form value that is never given to the user but isdefined in the form and appears in $form_state['values'].
#disabled
Disables (grays out) a form input element. Note that disabling a form field doesn't necessarily prevent someone from
submitting a value through DOM manipulation. It just tells the browser not to accept input.
#element_validate
A list of custom validation functions that need to be passed.
#parents
This array property is added to all elements and defaults to an empty array. It is used internally by the form builder to identify parent elements of the form tree. For more information, see http://drupal.org/node/48643.
#post_render
Function(s) to call after rendering in drupal_render() has occurred. The named function is called with two arguments, the
rendered element and its children. It returns the (potentially) altered element content.
#prefix
The string defined in this property will be added to the output when the element is rendered, just before the rendered element
#pre_render
Function(s) to call before rendering in drupal_render() has occurred. The function(s) provided in #pre_render receive the
element as an argument and must return the altered element.
#process
This property is an associative array. Each array entry consists of a function name as a key and any arguments that need to be passed as the values. These functions are called when an element is being built and allow additional manipulation of the
element atform building time. For example, in modules/system/system.module where the checkboxes type is defined, the
function form_process_checkboxes() in includes/form.inc is set to be called during form building:
$type['checkboxes'] = array( '#input' => TRUE, '#process' => array('form_process_checkboxes'),);
#states
Adds JavaScript to the element to allow it to have different active states.
#suffix
The string defined in this property will be added to the output when the element is rendered, just after the rendered element.
#theme
This optional property defines a string that will be used when Drupal looks for a theme function for this element. For
example, setting #theme = 'foo' will cause Drupal to check the theme registry for an entry that corresponds with foo.
See the “Finding a ThemeFunction for the Form” section earlier in this chapter.
#theme_wrappers
Theme function to call for the element, after the element and children are rendered, but before the
#post_render functions are called.
#title
This string is the title of the element.
#tree
Used to allow collections of form elements. Normally applied to the "parent" element, as the #tree
property cascades to sub-elements.
#weight
This property can be an integer or a decimal number. When form elements are rendered, they are sorted by their weight. Those with smaller weights “float up” and appear higher; those with larger weights “sink down” and appear lower on the rendered page.
Form Elements
In this section, we’ll present examples of the built-in Drupal form elements.
Text Field
An example of a text field element follows:
$form['pet_name'] = array( '#title' => t('Name'), '#type' => 'textfield', '#description' => t('Enter the name of your pet.'), '#default_value' => $user->pet_name,'#maxlength' => 32, '#required' => TRUE, '#size' => 15,'#weight' => 5,
'#autocomplete_path' => 'pet/common_pet_names',);
$form['pet_weight'] = array( '#title' => t('Weight'), '#type' => 'textfield',
'#description' => t('Enter the weight of your pet in kilograms.'), '#field_suffix' => t('kilograms'),
'#default_value' => $user->pet_weight,'#size' => 4, '#weight' => 10,);
This results in the form element shown in Figure 11-11.
Figure 11-11. The text field element
The #field_prefix and #field_suffix properties are specific to text fields and place a string immediately before or after the text
field input. The #autocomplete property defines a path where Drupal’s automatically included JavaScript will send HTTP requests using jQuery. In the preceding example, it will query http://example.com/?q=pet/common_pet_names.
See the user_autocomplete() function in modules/user/user.pages.inc for a working example.
Properties commonly used with the text field element follow: #attributes, #autocomplete_path (the default is FALSE), #default_
value, #description, #field_prefix, #field_suffix, #maxlength (the default is 128), #prefix, #required, #size (the default is60),
#suffix, #title, #process (the default is array('ajax_process_form')), and #weight.
Password
This element creates an HTML password field, where input entered by the user is not shown (usually bullet characters are echoed
to the screen instead). An example from user_login_block() follows:
$form['pass'] = array('#type' => 'password', '#title' => t('Password'),'#maxlength' => 60, '#size' => 15, '#required' =>
TRUE,);
Properties commonly used with the password element are #attributes, #description, #maxlength, #prefix, #required, #size
(the default is 60), #suffix, #title, #process (the default is array('ajax_ process_form')), and #weight. The #default_
value property is not used with the password element for security reasons.
Password with Confirmation
This element creates two HTML password fields and attaches a validator that checks if the two passwords match. For
example, this element is used by the user module when a user changes his or her password.
$form['account']['pass'] = array( '#type' => 'password_confirm', '#description' =>
t('To change the current user password, enter the new password in both fields.'), '#size' => 25,);
Textarea
An example of the textarea element follows:
$form['pet_habits'] = array( '#title' => t('Habits'), '#type' => 'textarea',
'#description' => t('Describe the habits of your pet.'), '#default_value' => $user->pet_habits,
'#cols' => 40, '#rows' => 3, '#resizable' => FALSE, '#weight' => 15,);
Properties commonly used with the textarea element are #attributes, #cols (the default is 60),
#default_value, #description, #prefix, #required, #resizable, #suffix, #title, #rows (the default is 5),
#process (the default is array('ajax_process_form')), and #weight.
The #cols setting may not be effective if the dynamic textarea resizer is enabled by setting #resizable to TRUE.
Select
A select element example from modules/statistics/statistics.admin.inc follows:
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
/* Period now looks like this: Array ([3600] => 1 hour [10800] => 3 hours [21600] => 6 hours [32400] => 9 hours[43200] => 12 hours [86400] => 1 day [172800] => 2 days [259200] => 3 days [604800] => 1 week [1209600] => 2 weeks [2419200] => 4 weeks [4838400] => 8 weeks [9676800] => 16 weeks )
*/
$form['access']['statistics_flush_accesslog_timer'] = array( '#type' => 'select',
'#title' => t('Discard access logs older than'),
'#default_value' => variable_get('statistics_flush_accesslog_timer', 259200), '#options' => $period,
'#description' => t('Older access log entries (including referrer statistics) will be automatically discarded. (Requires a correctly configured
<a href="@cron">cron maintenance task</a>.)', array('@cron' => url('admin/reports/status'))),);
Drupal supports grouping in the selection options by defining the #options property to be an associative array of submenuchoices, as shown in Figure 11-12.
$options = array( array(t('Healthy') => array(1 => t('wagging'),2 => t('upright'),3 => t('no tail')),), array(
t('Unhealthy') => array(4 => t('bleeding'),5 => t('oozing'),),),);
$form['pet_tail'] = array( '#title' => t('Tail demeanor'),
'#type' => 'select','#description' => t('Pick the closest match that describes the tail of your pet.'),
'#options' => $options, '#multiple' => FALSE, '#weight' => 20,);
Figure 11-12. A select element using choice grouping
Selection of multiple choices is enabled by setting the #multiple property to TRUE. This also changes the value in $form_state['values'] from a string (e.g., 'pet_tail' = '2', assuming upright is selected in the preceding example) to an array of values (e.g.,pet_tail = array( 1 => '1', 2 => '2') assuming wagging and upright are both chosen in the preceding
example). Properties commonly used with the select element are #attributes, #default_value, #description, #multiple, #options, #prefix, #required, #suffix, #title, #process (the default is array('form_ process_select',
'ajax_process_form')), and #weight.
Radio Buttons
A radio button example from modules/block/block.admin.inc follows:
$form['user_vis_settings']['custom'] = array( '#type' => 'radios',
'#title' => t('Custom visibility settings'), '#options' => array(
t('Users cannot control whether or not they see this block.'), t('Show this block by default, but let individual users hide it.'),t('Hide this block by default but let individual users show it.')),
'#description' => t('Allow individual users to customize the visibility of this block in their account settings.'),'#default_value' => $edit['custom'],);
Properties commonly used with this element are #attributes, #default_value, #description,#options, #prefix, #required,#suffix, #title, and #weight. Note that the #process property is set to array('form_process_radios') (see includes/form.inc) by default.
Check Boxes
An example of the check boxes element follows. The rendered version of this element is shown in Figure 11-13.
$options = array('poison' => t('Sprays deadly poison'), 'metal' => t('Can bite/claw through metal'), 'deadly' => t('Killed previous owner') );$form['danger'] = array('#title' => t('Special conditions'), '#type' =>
'checkboxes','#description' => (t('Please note if any of these conditions apply to your pet.')),
'#options' => $options, '#weight' => 25,);
Figure 11-13. An example using the check boxes element
The array_filter() function is often used in validation and submission functions to get the keys of the checked boxes. Forexample, if the first two check boxes are checked in Figure 11-13,
$form_state['values']['danger'] would contain the following:
array('poison' => 'poison', 'metal' => 'metal', deadly' => 0,)
Running array_filter($form_state['values']['danger']) results in an array containing only the keys of the checked boxes: array('poison', 'metal').
Properties commonly used with the check boxes element are #attributes, #default_value,
#description, #options, #prefix, #required, #suffix, #title, #tree (the default is TRUE), and #weight.
Note that the #process property is set to form_process_checkboxes() (see includes/form.inc) by default.
Value
The value element is used to pass values internally from $form to $form_state['values'] without ever being sent to the browser, for example:
$form['pid'] = array( '#type' => 'value', '#value' => 123,);
When the form is submitted, $form_state['values']['pid'] will be 123.
Do not confuse #type => 'value' and #value => 123. The first declares what kind of element is being described, and the
second declares the value of the element. Only #type and #value properties may be used with the value element.
Hidden
This element is used to pass a hidden value into a form using an HTML input field of type hidden, as in the following example.
$form['my_hidden_field'] = array( '#type' => 'hidden','#value' => t('I am a hidden field value'),);
If you want to send a hidden value along through the form, it’s usually a better idea to use the value element for this, and use
the hidden element only when the value element does not suffice. That’s because the user can view the hidden element in the
HTML source of a web form, but the value element is internal to Drupal and not included in the HTML. Only the #prefix,
#suffix, #process (the default is array('ajax_process_form')), and #value properties are used with the hidden element.
Date
The date element, as shown in Figure 11-14, is a combination element with three select boxes:
$form['deadline'] = array( '#title' => t('Deadline'), '#type' => 'date','#description' => t('Set the deadline.'), '#default_
value' => array('month' => format_date(time(), 'custom', 'n'), 'day' => format_date(time(), 'custom', 'j'), 'year' => format_date(time(), 'custom', 'Y'),),);
Figure 11-14. A date element
Properties commonly used by the date element are #attributes, #default_value, #description, #prefix, #required, #suffix, #title,
and #weight. The #process property defaults to call array('form_process_date'), in which the year selector is hard-coded to the
years 1900 through 2050. The #element_validate property defaults to date_validate() (bothfunctions can be found in includes/
form.inc). You can define these properties when defining the date element in your form to use your own code instead.
Weight
The weight element (not to be confused with the #weight property) is a drop-down used to specify weights:
$form['weight'] = array( '#type' => 'weight', '#title' => t('Weight'), '#default_value' => 0, '#delta' => 10,
'#description' => t('In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top.'),);
The preceding code will be rendered as shown in Figure 11-15.
Figure 11-15. The weight element
The #delta property determines the range of weights to choose from and defaults to 10. For example, if you set #delta to 50, the
range of weights would be from -50 to 50. Properties commonly used with the weight element are #attributes, #delta (the default is 10), #default_value, #description, #prefix, #required, #suffix, #title, and #weight. The #process property defaults to array('form_ process_weight', 'ajax_process_form').
File Upload
The file element creates a file upload interface. Here’s an example from modules/user/user.module:
$form['picture']['picture_upload'] = array( '#type' => 'file', '#title' => t('Upload picture'), '#size' => 48,
'#description' => t('Your virtual face or picture.'));
The way this element is rendered is shown in Figure 11-16.
Figure 11-16. A file upload element
Note that if you use the file element, you’ll need to set the enctype property at the root of your form:
$form['#attributes']['enctype'] = 'multipart/form-data';
Properties commonly used with the file element are #attributes, #default_value, #description, #prefix, #required, #size (the
default is 60), #suffix, #title, and #weight.
Fieldset
A fieldset element is used to group elements together. It can be declared collapsible, which means JavaScript automatically provided byDrupal is used to open and close the fieldset dynamically with a click while a user is viewing the form. Note the use of the
#access property in this example to allow or deny access to all fields within the fieldset:
// Node author information for administrators.
$form['author'] = array( '#type' => 'fieldset','#access' => user_access('administer nodes'), '#title' =>
t('Authoring information'), '#collapsible' => TRUE,'#collapsed' => TRUE,'#weight' => 20,);
Properties commonly used with the fieldset element are #attributes, #collapsed (the default is FALSE), #collapsible (the default is
FALSE), #description, #prefix, #suffix, #title, #process (the default is array('form_process_fieldset','ajax_process_form')), and #weight.
Submit
The submit element is used to submit the form. The word displayed inside the button defaults to “Submit” but can be changed using the #value property:
$form['submit'] = array( '#type' => 'submit', '#value' => t('Continue'),);
Properties commonly used with the submit element are #attributes, #button_type (the default is “submit”), #executes_submit_callback (the default is TRUE), #name (the default is “op”), #prefix, #suffix, #value, #process (the default is array('ajax_process_
form')), and #weight. Additionally, the #validate and #submit properties may be assigned directly to the submit element. For
example, if #submit is set to array('my_special_form_submit'), the function my_special_form_submit() will be used instead of
the form’s definedsubmit handler(s).
Button
The button element is the same as the submit element except that the #executes_submit_callback property defaults to FALSE. This property tells Drupal whether to process the form (when TRUE) or simply re-render the form (if FALSE). Like the Submitbutton,
specific validation and submit functions can be assigned directly to a button.
Image Button
The image button element is the same as the submit element with two exceptions. First, it has a #src property that has the URL of
an image as its value. Secondly, it sets the internal form property #has_garbage_value to TRUE, which prevents #default_value
from being used due to a bug in Microsoft Internet Explorer. Do not use #default_value with image buttons. Here is an image
button that uses the built-in Powered by Drupal image as the button:
$form['my_image_button'] = array( '#type' => 'image_button', '#src' => 'misc/powered-blue-80x15.png','#value' => 'foo',);
The value of the button can be safely retrieved by looking in $form_state['clicked_button']['#value'].
Markup
The markup element is the default element type if no #type property has been used. It is used to introduce text or HTML into the middle of a form.
$form['disclaimer'] = array( '#prefix' => '<div>', '#markup' => t('The information below is entirely optional.'),
'#suffix' => '</div>',);
Properties commonly used with the markup element are #attributes, #prefix (the default is the empty string ''), #suffix (the default is the empty string ''), #value, and #weight.
Item
The item element is formatted in the same way as other input element types like text element or select element, but it lacks the
input field.
$form['removed'] = array( '#title' => t('Shoe size'), '#type' => 'item', '#description' => t('This question has been removedbecause the law prohibits us from asking your shoe size.'),);
The preceding element is rendered as shown in Figure 11-17.
Figure 11-17. An item element
Properties commonly used with the item element are #attributes, #description, #prefix (the default is an empty string, ''),
#required, #suffix (the default is an empty string, ''), #title, #value, and #weight.
#ajax Property
AJAX-enabled forms in Drupal provide the ability to dynamically modify forms as a user interacts with the elements on the form.
A common example is to update the list of items in a select list based on some value that the user selected or entered in aprevious
field – for example, select an automobile manufacturer from a select list changes the list of available models based on the value
selected by the user. While you can perform that action without AJAX, its nice to not force the user to sit through a pagereload
the form populates the values in the second drop down list. AJAX provides the means for performing that update without having to reload the whole page, only the part that needs to be changed. The benefits of using the Form API’s AJAX capbilitiesinclude:
• AJAX forms provide dynamic form behavior without forcing the user to sit through one or more page reloads while the form updates an element.
• You as the developer don't have to code Javascript to create an AJAX-enabled form. The Form API does
all of the heavy lifting for you.
• AJAX forms are often simpler than multistep forms.
The process for creating an AJAX-enabled form is relatively simple:
Create or update an existing form element and mark it as AJAX-enabled by using the #ajax property.
Form elements marked as AJAX-enabled trigger a background AJAX call when the user change it or clicks on it.
The #ajax['wrapper'] property includes the HTML ID of a page section that will be modified when the Ajax call is executed. The
#ajax['callback'] indicates which callback should be executed after the AJAX call happens and the form is rebuilt.
Second, create a callback function using the name of the callback listed in #ajax['callback']. This function’s primary typically
updates the content of the HTML ID identified in the #ajax[‘wrapper’].
The following example demonstrates the use of Ajax by creating a form with two select lists, one for automobile manufacturer and the second for the models offered by that manufacturer. When a user selects a manufacturer from the list, the second select list is
automatically updated with the list of models that are offered by the manufacturer that was selected by the user. The second select
list is updated through Ajax without having to reload the page. Only that section of the page that contains the model select list is
updated.
/**
* A form with a dropdown whose options are dependent on a
* choice made in a previous dropdown.
*
* On changing the first dropdown, the options in the second
* are updated.
*/
function automobile_dependent_dropdown($form, &$form_state) {
// get the list of manufacturers to populate the manuacturer dropdown
$options_first = _automobile_get_manufacturer_dropdown_options();
// if we have a value for the manufacturer dropdown from
// $form_state['values'] we use this both as the default value for
// the first dropdown and also as a parameter to pass to the
// function that retrieves the options for the second dropdown.
$selected = isset($form_state['values']['manufacturer_dropdown']) ?
$form_state['values']['manufacturer_dropdown'] : key($options_first);
$form['manufacturer_dropdown'] = array( '#type' => 'select',
'#title' => 'Manufacturer', '#options' => $options_first, '#default_value' => $selected,
// bind an ajax callback to the change event (which is the default for the
// select form type) of the manufacturer dropdown. It will replace the
// model dropdown when rebuilt '#ajax' => array(
'callback' => 'automobile_dependent_dropdown_callback', 'wrapper' => 'dropdown_model_replace',
),
);
$form['model_dropdown'] = array( '#type' => 'select',
'#title' => 'Model',
// The entire enclosing div created here gets replaced when manufacturer_dropdown
// is changed.
'#prefix' => '<div id="dropdown_model_replace">', '#suffix' => '</div>',
// when the form is rebuilt during ajax processing, the $selected variable
// will now have the new value and so the models will change '#options' => _automobile_get_model_dropdown_options($selected), '#default_value' => isset($form_state['values']['model_dropdown']) ?$form_state['values']['model_dropdown'] : '',
);
$form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'),
);
return $form;
}
if (isset($options[$key])) { return $options[$key];
}
else {
return array();
}
}
The general processing performed by the code above:
1. Presents the form to the user, as any form would be.
2. In the form, a div with an HTML ID of ' dropdown_model_replace ' wraps
$form['model_dropdown'] . This is done with $form['model_dropdown'] ['#prefix'] and $form['model_dropdown'] ['#suffix'].
3. When the user changes $form['manufacturer_dropdown'] a background request is made to the server, causing the form to be rebuilt.
4. The form is rebuilt and the values for model are reset based on the value selected in the $form[‘model_dropdown’]
5. The function automobile_dependent_dropdown_callback() is called. It selects the piece of the form which is to be replaced on the page (almost always the same as what's in #ajax['wrapper']).
6. The portion returned is rendered, sent back to the page, and the div with id ‘dropdown_model_replace’ is replaced on the page.
/**
* Selects just the model dropdown to be returned for re-rendering
*
* The version here has been re-loaded with a different set of options and
* is sent back to the page to be updated.
*
* @return renderable array (the second dropdown)
*/
function automobile_dependent_dropdown_callback($form, $form_state) { return $form['model_dropdown'];
}
/**
* Helper function to populate the manufacturer dropdown. This would normally be
* pulling data from the database.
*
* @return array of options
*/
function _automobile_get_manufacturer_dropdown_options() {
// drupal_map_assoc() just makes an array('Strings' => 'Strings'...).
return drupal_map_assoc(array(t('Honda'), t('Toyota'), t('Ford'), t('Volkswagen')));
}
/**
* Helper function to populate the model dropdown. This would normally be
* pulling data from the database.
*
* @param key. This will determine which set of options is returned.
*
* @return array of options
*/
function _automobile_get_model_dropdown_options($key = '') {
$options = array(
t('Honda') => drupal_map_assoc(array(t('Accord'), t('Civic'), t('CRX'), t('Pilot'))), t('Toyota') => drupal_map_assoc(array(t('Camry'), t('Yaris'), t('Tundra'),
t('Tacoma'))),
t('Ford') => drupal_map_assoc(array(t('F-150'), t('Explorer'), t('Escape'), t('Edge'))), t('Volkswagen') => drupal_map_assoc(array(t('GTI'), t('Passat'), t('Jeta'), t('Polo'))),
);
Remember that the $form you're dealing with in your callback function has already been sent through all the form processing functions (but hasn't yet been sent to drupal_render()). So while adjusting, say, themarkup of an element is straightforward:
<?php
$elements['some_element']['#markup'] = 'New markup.'; return $elements;
?>
Changing a value that has already been converted into the #attributes property means digging deeper into the $form array, as well as also changing that element's corresponding property.
<?php
// You need to do both
$elements['some_element']['#disabled'] = TRUE;
$elements['some_element']['#attributes']['disabled'] = 'disabled'; return $elements;

If Javascript is not supported
Best practices call for providing a graceful for degrading behavior when the users browser does not support Javascript. AJAX forms provide the ability to address this, but it may take considerable effort to make a form behave correctly in either a Javascript ornon-javascript environment. In most cases you must provide alternative means for navigating, such as a "next" button for the AJAX-enabled element. When it is pressed, the page (and form) are rebuilt emulating the same functionality when the AJAX- enabledelement is changed, but with a page reload. The Examples module provides several examples of AJAX with graceful degradation in ajax_example_graceful_degradation.inc:
• An add-more button
• A dependent dropdown example
• Dynamic sections
• Wizard (classic multistep form)
Additional AJAX features
The AJAX Framework provides many additional features and options in beyond basic forms behavior.
• AJAX Framework Commands may be used on the server side to generate dynamic behaviors on the page. The #ajax['callback'] function may return an array of commands instead of returning a renderable array or an HTML string. Thisprovides the ablity to create dynamic functions that extend beyond simple Form API operations.
• The #ajax['callback'] does not have to return a portion of the form. It can return any renderable array, or it can return an HTML string.
• The replace method is the default and most common, but it is also possible to do other things with the content returned by the #ajax['callback'], including prepending, appending, etc.
• If you want to replace ajax_form_callback() with your own functions, use ajax_form_callback() would be the model for your replacement. In that case, you would change #ajax['path'] from the default 'system/ajax' and set up a menu entryin hook_menu() to point to your replacement path.
Additional resources
• The Examples module (http://drupal.org/project/examples) provides more examples, including an AJAX-enabled dependent dropdown, and several other examples, including an example of graceful degradation when Javascript is notenabled.
• See the AJAX Framework (http://api.drupal.org/api/group/ajax/7) documentation and the Form API Reference
Summary
After reading this chapter, you should understand the following concepts:
• How the form API works.
• Creating simple forms.
• Changing the rendered form using theme functions.
• Writing a validation function for a form or for individual elements.
• Writing a submit function and doing redirection after form processing.
• Altering existing forms.
• Creating dynamic forms.
• Using the #ajax property to create dynamic forms that react to users input without page reloads
• The form definition properties you can use and what they mean.
• The form elements (text fields, select fields, radios, and so on) thatre available in Drupal.
• How AJ-based text replacement works with forms.
For more information about forms, including tips and tricks, see the Drupal Handbook at