Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Apress.Pro.Drupal.7.Development.3rd.Edition.Dec.2010.pdf
Скачиваний:
63
Добавлен:
14.03.2016
Размер:
12.64 Mб
Скачать

CHAPTER 11 THE FORM API

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';

285

CHAPTER 11 THE FORM API

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 by Drupal 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 defined submit 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 Submit button, specific validation and submit functions can be assigned directly to a button.

286

CHAPTER 11 THE FORM API

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.

Caution If you are outputting text inside a collapsible fieldset, wrap it in <div> or other block HTML element tags, like <p>, so that when the fieldset is collapsed, your text will collapse within it.

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 removed because the law prohibits us from asking your shoe size.'),

);

287

CHAPTER 11 THE FORM API

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 a previous 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 page reload 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 capbilities include:

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’].

288

CHAPTER 11 THE FORM API

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']) ?

289

Download from Wow! eBook <www.wowebook.com>

CHAPTER 11 THE FORM API

$form_state['values']['model_dropdown'] : '', );

$form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'),

);

return $form;

}

/**

*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'))),

);

290

CHAPTER 11 THE FORM API

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.

CAUTIONS AND TIPS

You can only make changes to the form in the form builder function (automobile_dependent_dropdown() in the example here), or validation will fail. The callback function must not alter the form or any other state.

You can replace any HTML on the page, not just a form element. This is just a matter of providing a wrapper ID.

You can replace the entire form if like. Just add a #prefix and #suffix to the entire form array, then set that as the #ajax['wrapper']. (This will allow you to change multiple form elements via a single ajax call.) Just be aware that the more information transferred, the slower the process.

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, the markup of an element is straightforward:

<?php

$elements['some_element']['#markup'] = 'New markup.'; return $elements;

?>

291

CHAPTER 11 THE FORM API

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 or non-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 AJAXenabled element 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. This provides 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 entry in hook_menu() to point to your replacement path.

292

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]