It's been a long time that I want to write about Ctools. I have two good reasons: They are extremely useful -God bless Earl Miles, and it is very short on documentation.
Ctools have many tools to offer and I am going to explain some of them, one at a time. This time, I want to show you how to use Dependent tool: It make form items appear and disappear based upon the selections in another item.
Concept
When using Dependent tool, you have two kind of fields:
- One field that it's selected value is observed by other fields.
- One or more fields that are depended on the first field and appear or disappear upon the selected value of it.
Field that others are depended on its value can be one of these types: Radios, Checkbox and Select. Dependent fields can be anything, even markups.
How to use the Dependent tool
First you need to install the Ctools module. Following snippet is a simple example:
function _mytests_ctools_dependent_form() {
ctools_include('dependent');
$form['payment_type'] =
array(
'#type' => 'select',
'#title' => 'Payment type',
'cash' => 'Cash',
'credit' => 'Credit',
),
);
$form['cach_amount'] =
array(
'#type' => 'textfield',
'#title' => 'Amount',
'#process' =
> array('ctools_dependent_process'),
'#dependency' =
> array('edit-payment-type' =
> array('cash')),
);
$form['credit_type'] =
array(
'#type' => 'select',
'#title' => 'Credit card type',
'visa' => 'Visa',
'mc' => 'Master Card',
),
'#process' =
> array('ctools_dependent_process'),
'#dependency' =
> array('edit-payment-type' =
> array('credit')),
);
$form['credit_exp_date'] =
array(
'#type' => 'textfield',
'#title' => 'Expiration date',
'#process' =
> array('ctools_dependent_process'),
'#dependency' =
> array('edit-payment-type' =
> array('credit')),
);
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
Here is the explanation:
- Line 2: Load the dependent tool of Ctools. This is necessary to load the required javascript files and process the extra form element attributes.
- Line 4: A Select form element is defined. Some other fields in the form will observe its value and change their appearance upon its current selected value. This field has no extra attributes.
- Line 13: This text field is a dependent form element. Its appearance changes upon the
payment_type Select field. It has two extra attribute that are meaningful to Ctools: #process and #dependency.
- Line 16:
#process attribute tells the Drupal to process this field with function ctools_dependent_process. Note if a field has another process function, all of them should be added to this array as well.
- Line 17:
#dependency determines the dependency of this element. Setting this attribute is a bit trickey. value of this attribute is an array containing one key => value pair.
Key is HTML id of the form element which this element is depended on. This id is usually the element name, having all underscores replaced with dash and prefixed with edit-. If you are not sure about the element id, use an HTML inspector tool like Firebug to find it out.
Value is an array containing the element values that when are selected, this element will be visible.
Tips and Tricks
Well, it was easy and handy. With few lines of code, you added nice effects to your form that without Ctools, you had to write many lines of javascript to achieve them.
But this tool has some tricks that are hard to find in documents, or some are not there, yet.
Depending on Radio Buttons
Since radio buttons does not have ids of their own, you should select them differently. Please note that by term radio buttons I mean a group of radio buttons, not any individual radio button. Each individual radio button has an id, of course. This is how radio buttons should be handled:
$form['payment_type'] =
array(
'#type' => 'radios',
'#title' => 'Payment type',
'cash' => 'Cash',
'credit' => 'Credit',
),
'#default_value' => 'cash',
);
$form['cach_amount'] =
array(
'#type' => 'textfield',
'#title' => 'Amount',
'#process' =
> array('ctools_dependent_process'),
'#dependency' =
> array('radio:payment_type' =
> array('cash')),
);
You should use this style for radio buttons:
radio:ElementName which ElementName is the name of form element. If element is a child of another elements, use this style:
radio:Parent[Child].
Making Radios and Checkboxes dependent
For making an element dependent, it needs to have an HTML id -which is being used to find it- and be wrapped in another DIV element, which is being used to hide the element -and its label or description, if there are any. Wrapper DIV element id should be same as element id, suffixed with -wrapper. If an element does not have wrapper DIV, or does not have id at all, you should set them manually. For example, Radios -not confused with a single radio element- and Checkboxes, neither have an id, nor a wrapper. So you should add them manually:
$form['radio_element'] =
array(
'#type' => 'radios',
'#title' => 'Radios',
'one' => 'One',
'two' => 'Two',
),
);
$form['checkboxes_element'] =
array(
'#type' => 'checkboxes',
'#title' => 'Checkboxes',
'three' => 'Three',
'four' => 'Four',
),
'#prefix' => '<div id="edit-checkboxes-element-wrapper"><div id="edit-checkboxes-element">',
'#suffix' => '</div></div>',
'#process' =
> array('ctools_dependent_process',
'expand_checkboxes'),
'#dependency' =
> array('radio:radio_element' =
> array('one')),
);
- Line 17 and 18: This checkboxes element is wrapped in two DIVs. Note that ids are created based on element name.
- Line 19: checkbox and radio button processors should put back manually. function names are
expand_checkboxes and expand_radios respectively.
You can follow this approach for other elements that does not have wrappers or ids, like Buttons.
Form elements that are not Inputs
Ctoold dependent processes only form elements that are inputs, like textfields. Form elements like Fieldsets or Markups cannot be dependent directly. They need to pretend they are inputs for being processed:
$form['fieldset_element'] =
array(
'#type' => 'fieldset',
'#title' => 'Fieldset',
'#prefix' => '<div id="edit-fieldset-element-wrapper"><div id="edit-fieldset-element">',
'#suffix' => '</div></div>',
'#process' =
> array('ctools_dependent_process'),
'#dependency' =
> array('radio:radio_element' =
> array('one')),
'#input' => true,
);
$form['fieldset_element']['textfield'] =
array(
'#type' => 'textfield',
'#title' => 'Textfield',
);
$form['markup_element'] =
array(
'#value' => '<strong>Note this is not an input element<strong>',
'#prefix' => '<div id="edit-markup-element-wrapper"><div id="edit-markup-element">',
'#suffix' => '</div></div>',
'#process' =
> array('ctools_dependent_process'),
'#dependency' =
> array('radio:radio_element' =
> array('one')),
'#input' => true,
);
Line 8 and 22: By adding '#input' => true to fieldset and markup elements, we make them dependent as well. Note that child elements of a fieldset does not need dependency form attributes.
Now go play hide and seek.
Comments
Post new comment